From f72c6ac3cced17cd249c399e977af98aa8ba0ba7 Mon Sep 17 00:00:00 2001 From: Rafael Bittencourt Date: Thu, 4 Jun 2026 17:45:26 -0300 Subject: [PATCH 01/16] chore(skills): sync managed agent skills from Skills-Manager catalog Project-subscribed skill copies under .agents/skills, kept current with the central Skills-Manager catalog (SOTA/freshness-verified, internal-name leaks removed). Auto-managed via sync-projects; do not hand-edit. Co-Authored-By: Claude Opus 4.8 (1M context) --- .agents/skills/langgraph-deep-agents/SKILL.md | 133 +++++++++++ .../references/IMPLEMENTATION_SNIPPETS.md | 222 ++++++++++++++++++ .../LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md | 29 +++ .../references/LANGGRAPH_CORE_PATTERNS.md | 198 ++++++++++++++++ .../references/LANGGRAPH_HITL_MEMORY.md | 196 ++++++++++++++++ .../references/LANGGRAPH_MULTI_AGENT.md | 188 +++++++++++++++ .../references/VERSIONING_FRESHNESS.md | 51 ++++ 7 files changed, 1017 insertions(+) create mode 100644 .agents/skills/langgraph-deep-agents/SKILL.md create mode 100644 .agents/skills/langgraph-deep-agents/references/IMPLEMENTATION_SNIPPETS.md create mode 100644 .agents/skills/langgraph-deep-agents/references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md create mode 100644 .agents/skills/langgraph-deep-agents/references/LANGGRAPH_CORE_PATTERNS.md create mode 100644 .agents/skills/langgraph-deep-agents/references/LANGGRAPH_HITL_MEMORY.md create mode 100644 .agents/skills/langgraph-deep-agents/references/LANGGRAPH_MULTI_AGENT.md create mode 100644 .agents/skills/langgraph-deep-agents/references/VERSIONING_FRESHNESS.md diff --git a/.agents/skills/langgraph-deep-agents/SKILL.md b/.agents/skills/langgraph-deep-agents/SKILL.md new file mode 100644 index 0000000..9d77989 --- /dev/null +++ b/.agents/skills/langgraph-deep-agents/SKILL.md @@ -0,0 +1,133 @@ +--- +name: langgraph-deep-agents +description: |- + Build stateful, graph-based, multi-agent AI systems with LangGraph orchestration and the Deep Agents harness. Covers StateGraph with typed reducers, persistence (MemorySaver, SQLite, Postgres, DynamoDB, MongoDB, Redis), human-in-the-loop (interrupt_before/after, dynamic interrupt(), Command(resume=)), subgraph composition, streaming v2 (7 typed StreamPart modes), short-term thread memory and long-term cross-thread Store, multi-agent patterns (supervisor, swarm, hierarchical teams), and create_deep_agent planning with subagent delegation. Use when building durable graph agents with checkpointing/resume, approval workflows, or LangSmith Deployment; mentions "langgraph", "deep agents", "stategraph", "checkpointer", "multi-agent orchestration"; or needs LangGraph implementation code. Do not use for vendor-neutral topology/handoff decisions (use agent-orchestration-patterns) or the OpenAI Agents SDK stack (use openai-agents-sdk-python). +license: Apache-2.0 +metadata: + author: coding-agent + version: 1.0.5 + category: ai-agents + subcategory: orchestration + vendor: universal + lifecycle: active + coding_agent: true + tags: + - ai-agents + - langgraph + - langgraph-1-2 + - deep-agents + - dcode + - acp + - stategraph + - orchestration + - persistence + - human-in-the-loop + - streaming + - multi-agent + - coding + - project_level + audience: developer + output_format: markdown + modality: text +--- + +# LangGraph Deep Agents + +Implementation playbook for building stateful, graph-based AI agent systems using LangGraph. Covers StateGraph construction with typed reducers, persistence with multiple backends, human-in-the-loop workflows (3 interrupt mechanisms), subgraph composition, v2 type-safe streaming (7 modes), short-term and long-term memory, multi-agent patterns (supervisor, swarm, hierarchical teams), and the Deep Agents standalone library for hierarchical planning with subagent delegation. + +## When to Use + +- Building agents that require explicit control flow (conditional branching, loops, cycles) +- Implementing durable execution with checkpointing and resume-after-failure +- Designing human-in-the-loop approval or review workflows (interrupt_before, interrupt_after, dynamic interrupt()) +- Composing complex multi-agent systems (supervisor via langgraph-supervisor-py, swarm via langgraph-swarm-py, hierarchical teams) +- Implementing the Deep Agents pattern (create_deep_agent with write_todos planning, subagent delegation, filesystem backends) +- Needing both short-term (thread checkpoints) and long-term (cross-thread Store) memory +- Streaming agent execution at token, node, custom event, checkpoint, tasks, or debug granularity (7 modes) +- Deploying graph-based agents to LangSmith Deployment (self-hosted or managed) or embedding in applications + +## Inputs to Collect + +1. **Agent purpose** -- what problem does the graph solve? +2. **State schema** -- what data flows through the graph (TypedDict, Pydantic model, or dataclass)? +3. **Node design** -- what processing steps are needed (LLM calls, tool execution, data transformation)? +4. **Edge logic** -- what conditions determine the flow between nodes? +5. **Persistence needs** -- MemorySaver (dev), SQLite, PostgreSQL, DynamoDB, MongoDB, Redis? +6. **Human-in-the-loop** -- which steps require human approval, review, or input? +7. **Multi-agent pattern** -- single agent, supervisor, swarm, hierarchical teams, or Deep Agents? +8. **Memory requirements** -- thread-scoped (checkpoints), cross-thread (Store), or both? +9. **Streaming needs** -- values, updates, messages, custom, checkpoint, tasks, debug, or multiple simultaneous? +10. **Deployment target** -- LangSmith Deployment (managed/self-hosted), self-hosted standalone, or embedded? +11. **Deep Agents needs** -- planning via write_todos, subagent spawning, filesystem backend, sandbox? + +## Execution Playbook + +Five steps, each with copy-paste code in `references/IMPLEMENTATION_SNIPPETS.md`. Work through them in order; skip steps that do not apply (e.g. single-agent graphs skip Step 4). + +1. **State Schema and Graph Structure** — define the state that flows through the graph (TypedDict / Pydantic / dataclass) with the right reducers (no annotation = overwrite; `add_messages` = append + dedup by ID; custom `(old, new) -> merged`), then wire nodes as pure functions returning partial updates and edges (static or conditional via `add_conditional_edges`). +2. **Persistence, Checkpointing, and Streaming** — compile with a `checkpointer` (snapshot per super-step → resume, time-travel, HITL), inspect via `get_state` / `get_state_history`, and stream in one of 7 modes (`values`, `updates`, `messages`, `custom`, `checkpoint`, `tasks`, `debug`). Opt into `version="v2"` for typed `StreamPart` dicts, `GraphOutput` (`.value` / `.interrupts`), and Pydantic/dataclass coercion. +3. **Human-in-the-Loop and Memory** — add approval gates via 3 interrupt mechanisms (`interrupt_before`, `interrupt_after`, dynamic `interrupt()` inside nodes), resume with `Command(resume=...)` or `update_state`; use thread checkpoints for short-term memory and a cross-thread `Store` (namespaced by user_id) for long-term memory. +4. **Multi-Agent Patterns** — pick supervisor (`langgraph-supervisor-py`, central routing), swarm (`langgraph-swarm-py`, peer handoff via `Command(goto=...)`, ~40% lower latency vs supervisor), hierarchical teams (nested subgraphs), or Deep Agents (`create_deep_agent`). Define clear agent boundaries. +5. **Tool Integration, Deep Agents, and Deployment** — wire tools via `ToolNode` + `tools_condition` or `create_react_agent`; configure Deep Agents middleware (write_todos, filesystem, subagent task tool) and a filesystem backend (`StateBackend`, `FilesystemBackend`, `StoreBackend`, `ContextHubBackend`, `LocalShellBackend`, `CompositeBackend`, sandboxes); deploy to LangSmith Deployment (managed/lite/enterprise/BYOC), standalone server, or embedded, with LangSmith tracing. + +**Read `references/IMPLEMENTATION_SNIPPETS.md`** for the full code for every step. **Read `references/LANGGRAPH_CORE_PATTERNS.md`** (Steps 1-2), **`references/LANGGRAPH_HITL_MEMORY.md`** (Step 3), and **`references/LANGGRAPH_MULTI_AGENT.md`** (Step 4) for conceptual depth. + +## Deliverables / Definition of Done + +- [ ] State schema defined with appropriate reducers (add_messages, custom) +- [ ] Graph nodes and edges implemented and tested individually +- [ ] Conditional routing logic validated with test cases +- [ ] Checkpointing configured and tested (resume after failure, time-travel) +- [ ] Human-in-the-loop interrupts working (interrupt_before/after, dynamic interrupt()) +- [ ] Memory configured (short-term thread checkpoints and/or long-term Store) +- [ ] Multi-agent pattern implemented with clear agent boundaries (if applicable) +- [ ] v2 streaming verified at the required granularity +- [ ] Tools integrated and tested via ToolNode or create_react_agent +- [ ] Deep Agents configured with appropriate middleware and filesystem backend (if applicable) +- [ ] Deployed to target environment with health checks and observability +- [ ] Graph visualization generated and documented + +## Common Pitfalls + +1. **Mutable state in nodes** -- Nodes should return new state dicts, not mutate the input state directly. +2. **Missing reducers** -- Without proper reducers (e.g., `add_messages`), state updates overwrite instead of accumulate. +3. **Forgetting checkpointer for HITL** -- Human-in-the-loop requires checkpointing; without it, interrupts lose state. Humans may take hours/days to respond -- persistence is essential. +4. **Infinite loops** -- Conditional edges can create cycles; always include termination conditions. +5. **Over-complex graphs** -- Start simple; add nodes and edges incrementally. Visualize the graph to verify structure. +6. **Ignoring stream modes** -- Different consumers need different stream modes; choose the right one for your UI/API. Use v2 for type safety. +7. **Tight coupling between subgraphs** -- Subgraphs should communicate via well-defined state interfaces, not shared mutable data. +8. **Using v1 dict access on v2 GraphOutput** -- Old-style `result["key"]` is deprecated since v1.1 (emits `LangGraphDeprecatedSinceV11`), removed in v3.0. Use `result.value` and `result.interrupts`. +9. **In-memory storage in production** -- MemorySaver is ephemeral and local; use PostgresSaver/DynamoDB for production (fault tolerance, multi-worker). +10. **Cross-user memory leakage** -- Always namespace Store memories by user_id to prevent cross-user data leaks. +11. **Middleware + custom state_schema** -- Currently mutually exclusive in `create_agent()`; workaround by attaching state to message metadata. + +## Example Prompts + +- "Build a research agent graph with a planner node, parallel research nodes, and a synthesis node." +- "Add human-in-the-loop approval before the agent executes any database write operations using dynamic interrupt()." +- "Implement a supervisor pattern using langgraph-supervisor-py where a router delegates to code, research, and writing specialists." +- "Create a swarm multi-agent system using langgraph-swarm-py with handoff tools between triage, sales, and support agents." +- "Create a Deep Agent with create_deep_agent() that plans a document, spawns subagents for each section, then assembles the final output." +- "Add long-term memory via Store so my agent remembers user preferences across conversations." +- "Set up v2 streaming with multiple simultaneous modes (updates + messages) for a chat UI." + +## Invocation + +``` +Use the langgraph-deep-agents skill to [describe your graph-based agent need]. +``` + +## Versioning and Freshness + +As-of 2026-06-04. Current lines: **`langgraph 1.2.4`** (1.0 GA: durable state, built-in persistence, first-class HITL; `langgraph.prebuilt` deprecated → `langchain.agents`) and **`deepagents 0.6.8`** (released 2026-06-03; standalone library on the LangGraph runtime — write_todos planning, task-tool subagents, filesystem backends, async subagents, multi-modal `read_file`, `dcode` CLI, ACP). LangGraph Platform renamed to **LangSmith Deployment** (Oct 2025). Checkpointers: MemorySaver (dev), SqliteSaver, PostgresSaver (prod), DynamoDBSaver, MongoDB, Redis. Known limit: `middleware` + custom `state_schema` mutually exclusive in `create_agent()`. LangGraph APIs evolve frequently — verify import paths, class names, and signatures against the latest docs; do not hardcode minor versions in user code. Comparison: LangGraph = production-grade stateful (best observability via LangSmith); CrewAI = fastest time-to-production; AutoGen = maintenance mode; Deep Agents = complex multi-step tasks with context isolation. + +**Read `references/VERSIONING_FRESHNESS.md`** for the full source list (official docs, GitHub, PyPI, supervisor/swarm libs), all version deltas, OpenTelemetry/OWASP relevance, runtime defaults, and the model-family reference. + +## Reference files + +- **`references/IMPLEMENTATION_SNIPPETS.md`** — full copy-paste code for all 5 Execution Playbook steps. Read when implementing any step (state schema, checkpointing/streaming, HITL/memory, multi-agent, tools/Deep Agents/deployment). +- **`references/LANGGRAPH_CORE_PATTERNS.md`** — StateGraph fundamentals, reducers, conditional edges, persistence, v2 streaming/invoke. Read for Steps 1-2 depth. +- **`references/LANGGRAPH_HITL_MEMORY.md`** — interrupt mechanisms, `Command(resume=)`, short-term checkpoints, long-term Store. Read for Step 3 depth. +- **`references/LANGGRAPH_MULTI_AGENT.md`** — supervisor, swarm, hierarchical teams, Deep Agents patterns with code. Read for Step 4 depth. +- **`references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md`** — SOTA deltas for LangGraph 1.2.x + Deep Agents 0.6.x (extras, subagent typing, backends). Read when targeting the current release line. +- **`references/VERSIONING_FRESHNESS.md`** — complete source links, version pins, freshness notes, OWASP/OTel relevance, runtime/model references. Read to verify currency before shipping. diff --git a/.agents/skills/langgraph-deep-agents/references/IMPLEMENTATION_SNIPPETS.md b/.agents/skills/langgraph-deep-agents/references/IMPLEMENTATION_SNIPPETS.md new file mode 100644 index 0000000..a21b36a --- /dev/null +++ b/.agents/skills/langgraph-deep-agents/references/IMPLEMENTATION_SNIPPETS.md @@ -0,0 +1,222 @@ +# LangGraph Deep Agents — Implementation Snippets + +Copy-paste implementation code for each Execution Playbook step. Verify import +paths, class names, and method signatures against the latest docs (LangGraph +APIs evolve frequently). For conceptual depth, also read the companion +references: `LANGGRAPH_CORE_PATTERNS.md`, `LANGGRAPH_HITL_MEMORY.md`, +`LANGGRAPH_MULTI_AGENT.md`, `LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md`. + +## Step 1: State Schema and Graph Structure + +Define the state that flows through the graph and the graph's node/edge topology. + +```python +from langgraph.graph import StateGraph, START, END +from typing import TypedDict, Annotated +from langgraph.graph.message import add_messages + +class AgentState(TypedDict): + messages: Annotated[list, add_messages] # Reducer: append + dedup by ID + next_step: str # No annotation: overwrite + results: Annotated[list, lambda a, b: a + b] # Custom reducer: concat +``` + +**Reducers**: no annotation = overwrite; `add_messages` = append + dedup by ID; custom `(old, new) -> merged`. + +Design nodes as pure functions (or async functions) that accept state and return partial state updates. Define edges (static or conditional) to control flow. + +```python +graph = StateGraph(AgentState) +graph.add_node("research", research_node) +graph.add_node("analyze", analyze_node) +graph.add_node("respond", respond_node) + +graph.add_edge(START, "research") +graph.add_conditional_edges("research", route_after_research, {"analyze": "analyze", "done": END}) +graph.add_edge("analyze", "respond") +graph.add_edge("respond", END) +``` + +## Step 2: Persistence, Checkpointing, and Streaming + +Add durable execution and real-time output. + +- **Checkpointing**: Saves state as snapshots at every super-step (all nodes scheduled for a step execute, producing a checkpoint). Enables resume after failures, time-travel debugging, and human-in-the-loop interrupts. + +```python +from langgraph.checkpoint.memory import MemorySaver +# Production backends: +# from langgraph.checkpoint.sqlite import SqliteSaver +# from langgraph.checkpoint.postgres import PostgresSaver +# Also: DynamoDBSaver (AWS), MongoDB, Redis checkpointers + +checkpointer = MemorySaver() +app = graph.compile(checkpointer=checkpointer) + +config = {"configurable": {"thread_id": "user-123-conv-1"}} +result = app.invoke({"messages": [("user", "Hello")]}, config) +``` + +- **State inspection and time-travel**: +```python +state = app.get_state(config) # state.values, state.next +for snapshot in app.get_state_history(config): + print(snapshot.values) +``` + +- **Streaming** (7 modes): + - `stream_mode="values"`: Full state after each node + - `stream_mode="updates"`: State delta from each node + - `stream_mode="messages"`: Token-level streaming from LLM nodes + - `stream_mode="custom"`: Custom events emitted from nodes via `adispatch_custom_event` + - `stream_mode="checkpoint"`: Checkpoint snapshots + - `stream_mode="tasks"`: Task-level events + - `stream_mode="debug"`: Debug-level events for development + +```python +# v1 (default): yields bare data +async for event in app.astream(input, config, stream_mode="updates"): + print(event) + +# v2 (opt-in): yields typed StreamPart dicts +async for part in app.astream(input, config, stream_mode="updates", version="v2"): + print(part["type"], part["data"]) # Typed: UpdatesStreamPart + +# v2 invoke: returns GraphOutput with .value and .interrupts +result = app.invoke(input, config, version="v2") +print(result.value, result.interrupts) + +# Multiple modes simultaneously +async for event in app.astream(input, config, stream_mode=["updates", "messages"]): + ... +``` + +**v2 StreamPart types** (importable from `langgraph.types`): `ValuesStreamPart`, `UpdatesStreamPart`, `MessagesStreamPart`, `CustomStreamPart`, `CheckpointStreamPart`, `TasksStreamPart`, `DebugStreamPart`. Union type `StreamPart` is a discriminated union on `part["type"]`. + +**Pydantic / dataclass coercion under v2**: with `version="v2"`, `invoke()` and values-mode stream output are automatically coerced to your declared Pydantic model or dataclass type — prefer a typed state schema so downstream consumers never hand-parse dicts. + +**Time-travel fixes (v2)**: replays no longer reuse stale RESUME values, and subgraphs correctly restore the checkpoint for the parent's historical state. Re-run audited HITL traces under v2 if you previously observed drift. + +## Step 3: Human-in-the-Loop and Memory + +Implement approval workflows and persistent memory. + +- **3 interrupt mechanisms**: + 1. `interrupt_before=["node_name"]`: Pause **before** a node runs. Human reviews state and approves/rejects/modifies. + 2. `interrupt_after=["node_name"]`: Pause **after** a node runs. Useful for reviewing results. + 3. `interrupt()` function: Dynamic, conditional pausing inside nodes based on runtime conditions. + +```python +app = graph.compile( + checkpointer=checkpointer, + interrupt_before=["sensitive_action"], +) + +# Resume after human approval: +from langgraph.types import Command +app.invoke(Command(resume={"approved": True}), config) + +# Or modify state before continuing: +app.update_state(config, {"planned_action": modified_action}) +app.invoke(None, config) +``` + +Dynamic interrupt inside a node: +```python +from langgraph.types import interrupt + +def sensitive_node(state): + if state["risk_level"] == "high": + human_response = interrupt( + {"question": "This action is high-risk. Proceed?", "details": state["action"]} + ) + if not human_response.get("approved"): + return {"messages": [AIMessage(content="Action cancelled.")]} + return execute_action(state) +``` + +- **Short-term memory**: Thread-scoped state via checkpoints. All state within a thread persists across invocations. Different threads have independent state. +- **Long-term memory**: Cross-thread `Store` interface for user preferences, learned facts, shared knowledge. + +```python +from langgraph.store.memory import InMemoryStore +# Production: database-backed stores + +store = InMemoryStore() +app = graph.compile(checkpointer=checkpointer, store=store) + +# In nodes: +def my_node(state, config, *, store): + user_id = config["configurable"]["user_id"] + memories = store.search(("users", user_id, "preferences")) + store.put(("users", user_id, "preferences"), key="theme", value={"preference": "dark_mode"}) + return {"messages": [...]} +``` + +## Step 4: Multi-Agent Patterns + +Choose and implement the right multi-agent architecture. + +- **Supervisor** (via `langgraph-supervisor-py`): Central supervisor routes tasks to specialized workers via tool-based handoff mechanism. Supports multi-level hierarchies (supervisor managing supervisors), message forwarding (`create_forward_message_tool`), flexible message history management. + +- **Swarm** (via `langgraph-swarm-py`): Agents hand off control to each other dynamically using `Command(goto="agent_name")`. System remembers last active agent. Decentralized, no central controller. ~40% reduction in end-to-end response time vs supervisor (eliminates supervisor intermediary hop). + +- **Hierarchical Teams**: Nested supervisors via subgraph composition. Top supervisor delegates to team leads (subgraphs), who delegate to workers. + +- **Deep Agents** (standalone library `deepagents`): Hierarchical planning pattern with `create_deep_agent()`. Middleware architecture: write_todos (planning), filesystem tools (context offloading), task tool (subagent spawning). Pluggable filesystem backends. Built on LangGraph runtime. + +For all patterns, define clear agent boundaries and use the graph structure to enforce the coordination protocol. + +## Step 5: Tool Integration, Deep Agents, and Deployment + +Wire tools, configure Deep Agents, and deploy. + +- **ToolNode**: Built-in node that executes tool calls from LLM responses. +- **tools_condition**: Routes to "tools" node or END based on tool_calls presence. +- **create_react_agent**: Prebuilt ReAct agent with tool loop. +- **MCP tools**: Via `langchain-mcp-adapters` for external tool server access. + +```python +from langgraph.prebuilt import ToolNode, tools_condition, create_react_agent + +tools = [search_tool, calculator_tool] +tool_node = ToolNode(tools) +graph.add_node("tools", tool_node) +graph.add_conditional_edges("agent", tools_condition) + +# Prebuilt ReAct agent +app = create_react_agent(model, tools=tools, checkpointer=checkpointer) +``` + +- **Deep Agents** (`pip install deepagents`, MIT license, current line `deepagents == 0.6.8` released 2026-06-03; Python `>=3.11,<4.0` — 3.11 through 3.14; verify at https://pypi.org/project/deepagents/): + +```python +from deepagents import create_deep_agent +from langchain.chat_models import init_chat_model + +# Basic usage -- returns compiled LangGraph graph +agent = create_deep_agent() +result = agent.invoke({"messages": [{"role": "user", "content": "Research and summarize LangGraph"}]}) + +# Custom configuration +agent = create_deep_agent( + model=init_chat_model("openai:gpt-5.4-mini"), + tools=[my_custom_tool], + system_prompt="You are a research assistant.", +) +``` + +Deep Agents middleware (auto-attached): +1. **write_todos middleware**: Adds `write_todos` tool + instructions for explicit planning and todo tracking. +2. **Filesystem middleware**: Adds `ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep` for context offloading. +3. **Subagent middleware**: Adds `task` tool for spawning subagents with isolated context windows. + +Filesystem backends (named classes): `StateBackend` (default; ephemeral per thread, stored in LangGraph state), `FilesystemBackend` (local disk), `StoreBackend` (LangGraph Store, cross-thread persistence), `ContextHubBackend` (LangChain Context Hub), `LocalShellBackend` (shell-backed filesystem), `CompositeBackend` (route paths across multiple backends). Sandboxes (Modal, Daytona, Runloop) and S3/PostgreSQL are available via `deepagents-backends` or custom implementations. + +Additional Deep Agents features: auto-summarization (triggers when conversations grow long), shell access (`execute` with sandboxing), MCP support via `langchain-mcp-adapters`, CLI with web search/persistent memory/HITL, **async subagents** (April 2026 — subagents run as non-blocking background tasks so users keep interacting with the main agent; requires LangSmith Deployment), **multi-modal `read_file`** (PDFs, audio, and video in addition to images), updated backend protocol / file format in State and Store backends to support binary files (backwards-compatible), the `dcode` CLI (`pip install deepagents-code`) for terminal-driven coding workflows, and an Agent Communication Protocol (ACP) integration via `pip install deepagents-acp` for IDE wiring. + +- **Deployment options**: + - **LangSmith Deployment** (formerly LangGraph Platform): Managed deployment with built-in persistence, streaming, monitoring. Self-hosted lite (free, 100k nodes/month), self-hosted enterprise (fully in VPC), hybrid BYOC (SaaS control plane + self-hosted data plane). + - **Standalone Server**: Lightweight option with Agent Servers + PostgreSQL + Redis. Kubernetes (production) or Docker (dev). + - **Embedded**: Compile the graph and invoke directly within your application. + - **Observability**: LangSmith for tracing (`LANGSMITH_TRACING=true`), step-by-step traces with token counts per node, replay failed runs with modified inputs. diff --git a/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md new file mode 100644 index 0000000..d231549 --- /dev/null +++ b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md @@ -0,0 +1,29 @@ +# LangGraph 1.2.x + Deep Agents 0.6.x — SOTA notes + +> Scope: deltas vs the previous LangGraph 1.1.x / Deep Agents 0.5.x lines. +> Verified 2026-06-04 against the local SOTA guides +> (`guia_completo_agentes/guia_langgraph_orquestracao.html` and +> `guia_completo_agentes/guia_deepagents.html`, at the repo root) +> and live docs. + +## Canonical web sources +- LangGraph overview — https://docs.langchain.com/oss/python/langgraph/overview +- LangGraph multi-agent (supervisor/swarm) — https://docs.langchain.com/oss/python/langgraph/multi-agent +- LangGraph releases — https://github.com/langchain-ai/langgraph/releases +- Deep Agents overview — https://docs.langchain.com/oss/python/deepagents/overview +- Deep Agents reference — https://reference.langchain.com/python/deepagents/ +- Deep Agents releases — https://github.com/langchain-ai/deepagents/releases +- PyPI — https://pypi.org/project/langgraph/ ; https://pypi.org/project/deepagents/ + +## SOTA delta + +- **Versions:** `langgraph == 1.2.4` and `deepagents == 0.6.8` (released 2026-06-03). Python `>=3.11,<4.0` for Deep Agents. +- **LangGraph 1.x stable surface:** durable state, built-in persistence, first-class HITL (interrupt before/after, dynamic `interrupt()`, `Command(resume=)`). v2 typed streaming with Pydantic/dataclass coercion and time-travel fixes for RESUME values and subgraph parent checkpoints. `langgraph.prebuilt` deprecated — use `langchain.agents` (`create_agent`, middleware framework). +- **Deep Agents 0.6 pillars unchanged:** `BASE_AGENT_PROMPT` + feature prompts (TASK / FILESYSTEM / SKILLS / MEMORY / SUMMARIZATION); `write_todos` planning tool; `task(...)` subagent spawning; virtual filesystem (`ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep`). +- **New tooling extras to know:** + - `pip install -U "deepagents[quickjs]"` adds the QuickJS-backed Code Interpreter. + - `pip install deepagents-acp` ships the Agent Communication Protocol integration (IDE / external host wiring). + - `pip install deepagents-code` installs the `dcode` CLI for terminal-driven coding workflows. + - Optional sandbox extras: `langchain-modal`, `langchain-daytona`, `langchain-runloop`, `langsmith[sandbox]`. +- **Subagent typing:** `SubAgent`, `CompiledSubAgent`, `AsyncSubAgent` cover sync, pre-compiled, and async patterns; async subagents stream as non-blocking background tasks under LangSmith Deployment. +- **Filesystem backends:** `StateBackend` (default; ephemeral per thread), `FilesystemBackend` (local disk), `StoreBackend` (LangGraph Store; cross-thread), `ContextHubBackend` (LangChain Context Hub), `LocalShellBackend` (shell-backed filesystem), `CompositeBackend` (path-routed), plus sandbox backends. Backend protocol now carries binary file metadata (backwards-compatible) so multi-modal `read_file` covers PDFs, audio, and video. diff --git a/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_CORE_PATTERNS.md b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_CORE_PATTERNS.md new file mode 100644 index 0000000..8d5cab6 --- /dev/null +++ b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_CORE_PATTERNS.md @@ -0,0 +1,198 @@ + + +# LangGraph Core Patterns + +> Official docs: https://langchain-ai.github.io/langgraph/ +> GitHub: https://github.com/langchain-ai/langgraph +> LangGraph 1.1+: v2 streaming and invoke + +## StateGraph Fundamentals + +### Defining State + +```python +from typing import TypedDict, Annotated +from langgraph.graph.message import add_messages + +class AgentState(TypedDict): + messages: Annotated[list, add_messages] # Reducer: appends + dedup by ID + current_step: str # No annotation: overwrite + results: Annotated[list, lambda a, b: a + b] # Custom reducer: concat +``` + +**Reducers**: no annotation = overwrite; `add_messages` = append + dedup by ID; custom `(old, new) -> merged`. State schema can be TypedDict, Pydantic model, or dataclass. When using Pydantic/dataclass with v2, outputs are automatically coerced to the correct type. + +### Building the Graph + +```python +from langgraph.graph import StateGraph, START, END + +graph = StateGraph(AgentState) +graph.add_node("agent", agent_node) +graph.add_node("tools", tool_node) +graph.add_edge(START, "agent") +graph.add_edge("tools", "agent") +graph.add_conditional_edges("agent", route_function, {"use_tools": "tools", "done": END}) +``` + +### Nodes and Routing + +```python +def agent_node(state: AgentState) -> dict: + response = model.invoke(state["messages"]) + return {"messages": [response]} # Return partial state update + +def route_function(state: AgentState) -> str: + last = state["messages"][-1] + return "use_tools" if hasattr(last, "tool_calls") and last.tool_calls else "done" +``` + +Nodes are pure functions: accept state, return partial state dict. Never mutate input state directly. + +## Persistence and Checkpointing + +Saves state at every super-step boundary (all nodes scheduled for that step execute, then checkpoint). A super-step is a single "tick" of the graph. + +### Checkpointer Backends + +| Backend | Use Case | Package | +|---------|----------|---------| +| `MemorySaver` | Dev/testing (ephemeral, local) | `langgraph.checkpoint.memory` | +| `SqliteSaver` | Light production | `langgraph-checkpoint-sqlite` | +| `PostgresSaver` | Production (recommended) | `langgraph-checkpoint-postgres` | +| `DynamoDBSaver` | AWS production (S3 for large payloads) | `langgraph-checkpoint-dynamodb` | +| MongoDB | MongoDB-backed | `langgraph-checkpoint-mongodb` | +| Redis | Redis-backed | `langgraph-checkpoint-redis` | + +```python +from langgraph.checkpoint.memory import MemorySaver +checkpointer = MemorySaver() +app = graph.compile(checkpointer=checkpointer) + +config = {"configurable": {"thread_id": "user-123-conv-1"}} +result = app.invoke({"messages": [("user", "Hello")]}, config) +result = app.invoke({"messages": [("user", "Follow up")]}, config) # State restored + +# Inspect state +state = app.get_state(config) # state.values, state.next +for snapshot in app.get_state_history(config): + print(snapshot.values) +``` + +DynamoDBSaver: small checkpoints (<350 KB) in DynamoDB; large payloads to S3 with reference pointer. Agent Server/API: checkpointers and stores handled automatically. + +## Streaming (7 Modes) + +### v1 (Default) + +```python +# Full state after each node +async for event in app.astream(input, config, stream_mode="values"): + ... + +# State deltas from each node +async for event in app.astream(input, config, stream_mode="updates"): + node_name, delta = next(iter(event.items())) + +# Token-level LLM streaming +async for event in app.astream(input, config, stream_mode="messages"): + print(event[0].content, end="", flush=True) + +# Multiple modes simultaneously +async for event in app.astream(input, config, stream_mode=["updates", "messages"]): + ... +``` + +### v2 (Type-Safe, Opt-In) + +Add `version="v2"` to `invoke()`/`stream()` for typed outputs. Stream yields `StreamPart` dicts (`type`, `ns`, `data`); invoke returns `GraphOutput` with `.value` and `.interrupts`. + +StreamPart types (from `langgraph.types`): `ValuesStreamPart`, `UpdatesStreamPart`, `MessagesStreamPart`, `CustomStreamPart`, `CheckpointStreamPart`, `TasksStreamPart`, `DebugStreamPart`. Discriminated union on `part["type"]` for full type narrowing. Default remains v1; old-style dict access on v2 emits deprecation warning. + +### Custom Events + +```python +from langchain_core.callbacks import adispatch_custom_event + +async def my_node(state: AgentState) -> dict: + await adispatch_custom_event("progress", {"step": 1, "total": 3}) + return {"current_step": "done"} +``` + +## Subgraph Composition + +```python +sub_graph = StateGraph(SubState) +sub_graph.add_node("step1", step1_fn) +sub_graph.add_edge(START, "step1") +sub_graph.add_edge("step1", END) +compiled_sub = sub_graph.compile() + +parent_graph = StateGraph(ParentState) +parent_graph.add_node("sub_process", compiled_sub) # Subgraph as a node +parent_graph.add_edge(START, "sub_process") +parent_graph.add_edge("sub_process", END) +``` + +State mapping between parent and subgraph is automatic when keys match, or customizable via state transformers. + +## Tool Integration + +### ToolNode (Prebuilt) + +```python +from langgraph.prebuilt import ToolNode, tools_condition +from langchain_core.tools import tool + +@tool +def search(query: str) -> str: + """Search the web for information.""" + return do_search(query) + +tool_node = ToolNode([search]) +graph.add_node("tools", tool_node) +graph.add_conditional_edges("agent", tools_condition) # Routes to "tools" or END +``` + +### Prebuilt ReAct Agent + +```python +from langgraph.prebuilt import create_react_agent + +app = create_react_agent(model, tools=[search, calculator], checkpointer=checkpointer) +``` + +`create_react_agent` parameters: model, tools, checkpointer, store, interrupt_before, interrupt_after, system_message (since recent updates). + +### MCP Tools + +```python +# Via langchain-mcp-adapters +from langchain_mcp_adapters import MCPToolkit + +toolkit = MCPToolkit(server_params=...) +tools = toolkit.get_tools() +``` + +## Middleware (LangGraph 1.1+) + +### Model Retry Middleware +Automatically retries failed model calls with configurable exponential backoff. + +### Content Moderation Middleware (OpenAI) +Detects and handles unsafe content in agent interactions. Supports checking user input, model output, and tool results. + +### Summarization Middleware +Auto-summarizes conversation history when it grows too long, keeping context manageable. + +### Human-in-the-Loop Middleware +Configures which tools require human approval before execution. + +## Key Architecture Principles + +1. **Graph-first**: Explicit control flow via nodes and edges; no implicit routing. +2. **State-driven**: All data flows through a typed state schema with reducers. +3. **Checkpoint-enabled**: Every super-step produces a checkpoint for durability. +4. **Composable**: Subgraphs as nodes; mix prebuilt and custom components. +5. **Stream-native**: 7 streaming modes for different consumers and granularities. +6. **Type-safe (v2)**: Typed StreamPart and GraphOutput for editor/type-checker support. diff --git a/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_HITL_MEMORY.md b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_HITL_MEMORY.md new file mode 100644 index 0000000..fb83de9 --- /dev/null +++ b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_HITL_MEMORY.md @@ -0,0 +1,196 @@ + + +# LangGraph Human-in-the-Loop and Memory + +> HITL docs: https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/ +> Memory docs: https://langchain-ai.github.io/langgraph/concepts/memory/ +> Persistence docs: https://langchain-ai.github.io/langgraph/concepts/persistence/ + +## Human-in-the-Loop (HITL) + +LangGraph's HITL architecture rests on three pillars: **checkpointing** (state persistence), **interrupts** (execution pausing), and **commands** (human responses). Humans may respond immediately or take hours/days -- persistence ensures the workflow survives the wait. + +### Mechanism 1: Interrupt Before + +Pause execution **before** a node runs. Human reviews state and approves, rejects, or modifies. + +```python +app = graph.compile( + checkpointer=checkpointer, + interrupt_before=["execute_action"], # Pause before this node +) + +# Run until interrupt +result = app.invoke(input, config) +# result.next == ("execute_action",) -- paused here + +# Inspect what the agent wants to do +state = app.get_state(config) +pending_action = state.values["planned_action"] + +# Option 1: Approve and continue +from langgraph.types import Command +app.invoke(Command(resume={"approved": True}), config) + +# Option 2: Reject and provide feedback +app.invoke(Command(resume={"approved": False, "feedback": "Too risky"}), config) + +# Option 3: Modify state before continuing +app.update_state(config, {"planned_action": modified_action}) +app.invoke(None, config) # Continue with modified state +``` + +### Mechanism 2: Interrupt After + +Pause execution **after** a node runs. Useful for reviewing results before proceeding. + +```python +app = graph.compile( + checkpointer=checkpointer, + interrupt_after=["generate_draft"], # Pause after this node +) +``` + +### Mechanism 3: Dynamic Interrupts + +Use the `interrupt()` function inside a node for conditional pausing based on runtime conditions: + +```python +from langgraph.types import interrupt + +def sensitive_node(state): + if state["risk_level"] == "high": + # Pause and ask the human + human_response = interrupt( + {"question": "This action is high-risk. Proceed?", "details": state["action"]} + ) + if not human_response.get("approved"): + return {"messages": [AIMessage(content="Action cancelled by human.")]} + # Proceed with action + return execute_action(state) +``` + +### HITL Patterns + +1. **Approval gate**: Interrupt before destructive actions; require explicit approval. +2. **Review and edit**: Interrupt after generation; human edits output before it continues. +3. **Input collection**: Interrupt to request additional information from the human. +4. **Escalation**: Interrupt when the agent detects uncertainty or risk beyond its threshold. +5. **Learning from feedback**: Combine interrupts with Store to save human corrections as long-term memories. + +### HITL with v2 + +```python +# v2 invoke returns GraphOutput with .interrupts +result = app.invoke(input, config, version="v2") +if result.interrupts: + # Handle interrupts + for interrupt_data in result.interrupts: + print(interrupt_data) + # Resume + app.invoke(Command(resume={"approved": True}), config, version="v2") +``` + +## Memory + +### Short-Term Memory (Thread State) + +Thread state is automatically persisted via checkpointing. All state within a thread persists across invocations. Different threads have independent state. + +```python +config = {"configurable": {"thread_id": "user-123"}} + +# First turn +app.invoke({"messages": [("user", "My name is Alice")]}, config) + +# Second turn (agent remembers the name from thread state) +app.invoke({"messages": [("user", "What is my name?")]}, config) +``` + +### Long-Term Memory (Cross-Thread Store) + +For memory that persists across threads (user preferences, learned facts, organizational knowledge), use the `Store` interface. Memory is stored as JSON documents organized using namespaces (like folders) and keys (like filenames). + +```python +from langgraph.store.memory import InMemoryStore +# For production: database-backed stores (verify current API in docs) + +store = InMemoryStore() + +app = graph.compile( + checkpointer=checkpointer, + store=store, +) +``` + +### Accessing the Store in Nodes + +```python +from langchain_core.runnables import RunnableConfig +from langgraph.store.base import BaseStore + +def my_node(state: AgentState, config: RunnableConfig, *, store: BaseStore): + user_id = config["configurable"]["user_id"] + + # Read memories (namespace-based search) + memories = store.search(("users", user_id, "preferences")) + + # Write a memory + store.put( + ("users", user_id, "preferences"), + key="theme", + value={"preference": "dark_mode", "confidence": 0.9}, + ) + + return {"messages": [...]} +``` + +### Memory Patterns + +1. **User profile**: Store user preferences, past interactions, and learned facts. +2. **Semantic memory**: Store embeddings of past interactions for similarity-based retrieval. +3. **Episodic memory**: Store summaries of past conversations as retrievable episodes. +4. **Shared knowledge**: Store organizational or domain knowledge accessible across all threads. + +### Memory Best Practices + +Namespace by user ID (prevent cross-user leakage). Version memories for freshness. Prune with TTL or relevance. Inject only relevant memories, not all. Read at turn start, write at turn end. Agent Server/API manages stores automatically. + +## Combining HITL and Memory + +A common pattern: the agent learns from human feedback and stores corrections as long-term memories. + +```python +def review_node(state, *, store): + # Agent generates a response + response = generate_response(state) + + # Interrupt for human review + feedback = interrupt({"draft": response, "question": "Is this correct?"}) + + if feedback.get("correction"): + # Store the correction as a long-term memory + store.put( + ("corrections", state["topic"]), + key=str(uuid4()), + value={"original": response, "correction": feedback["correction"]}, + ) + return {"messages": [AIMessage(content=feedback["correction"])]} + + return {"messages": [AIMessage(content=response)]} +``` + +## Persistence Comparison + +| Feature | Checkpoints (Short-Term) | Store (Long-Term) | +|---------|------------------------|-------------------| +| Scope | Single thread | Cross-thread | +| Lifetime | Thread lifetime | Indefinite | +| Structure | Full state snapshots | Key-value documents | +| Access | Automatic via thread_id | Explicit via namespace/key | +| Use case | Conversation history, HITL | User preferences, facts | +| Auto-managed | Yes (Agent Server) | Yes (LangGraph API) | + +## Checkpointer Backends + +MemorySaver (dev only, ephemeral). SqliteSaver (light prod). **PostgresSaver** (recommended, durable, multi-worker). DynamoDBSaver (AWS, infinite scale). MongoDB, Redis also supported. In-memory not acceptable for production. diff --git a/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_MULTI_AGENT.md b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_MULTI_AGENT.md new file mode 100644 index 0000000..13343f1 --- /dev/null +++ b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_MULTI_AGENT.md @@ -0,0 +1,188 @@ + + +# LangGraph Multi-Agent Patterns + +> Multi-agent docs: https://langchain-ai.github.io/langgraph/concepts/multi_agent/ +> Supervisor library: https://github.com/langchain-ai/langgraph-supervisor-py +> Swarm library: https://github.com/langchain-ai/langgraph-swarm-py +> Deep Agents: https://github.com/langchain-ai/deepagents +> Deep Agents docs: https://docs.langchain.com/oss/python/deepagents/overview + +## Pattern 1: Supervisor (via langgraph-supervisor-py) + +A central supervisor agent routes tasks to specialized workers via tool-based handoff mechanism. + +```bash +pip install langgraph-supervisor +``` + +```python +from langgraph_supervisor import create_supervisor +from langgraph.prebuilt import create_react_agent + +# Create specialized worker agents +researcher = create_react_agent(model, tools=[search_tool], name="researcher") +coder = create_react_agent(model, tools=[code_tool], name="coder") +writer = create_react_agent(model, tools=[write_tool], name="writer") + +# Create supervisor that orchestrates workers +supervisor = create_supervisor( + model, + agents=[researcher, coder, writer], + prompt="Route tasks to the appropriate specialist.", +) +app = supervisor.compile(checkpointer=checkpointer) +``` + +Key features: tool-based handoff, flexible message history, inherits streaming/memory/HITL, `create_forward_message_tool` for direct output forwarding. + +### Multi-Level Hierarchies + +Nest supervisors: each team is a `create_supervisor(model, agents=[...])`, then pass `team.compile()` as agents to a top-level supervisor. + +**When to use**: Clear task decomposition, centralized control, heterogeneous workers, structured workflows. + +## Pattern 2: Swarm (via langgraph-swarm-py) + +Agents hand off to each other dynamically. No central controller. System remembers last active agent. + +```bash +pip install langgraph-swarm +``` + +```python +from langgraph.prebuilt import create_react_agent +from langgraph.types import Command + +def transfer_to_sales(): + """Hand off the conversation to the sales agent.""" + return Command(goto="sales_agent") + +def transfer_to_support(): + """Hand off the conversation to the support agent.""" + return Command(goto="support_agent") + +# Each agent has handoff tools +triage_agent = create_react_agent( + model, tools=[transfer_to_sales, transfer_to_support], name="triage" +) +sales_agent = create_react_agent( + model, tools=[transfer_to_support, *sales_tools], name="sales_agent" +) +support_agent = create_react_agent( + model, tools=[transfer_to_sales, *support_tools], name="support_agent" +) +``` + +Decentralized (each agent decides next), persistent routing (remembers last active agent), ~40% faster than supervisor (no intermediary hop), fewer LLM calls. + +**When to use**: Peer-to-peer collaboration, dynamic routing, conversational handoffs, customer service flows. + +## Pattern 3: Hierarchical Teams + +Nested supervisors for complex organizational structures. + +``` +[Top Supervisor] + |---> [Research Team Lead] + | |---> [Web Researcher] + | |---> [Paper Researcher] + |---> [Engineering Team Lead] + |---> [Frontend Dev] + |---> [Backend Dev] +``` + +Each team is a subgraph with its own supervisor. The top supervisor delegates to team leads, who delegate to workers. + +```python +# Research team subgraph +research_team = StateGraph(TeamState) +research_team.add_node("lead", research_lead_node) +research_team.add_node("web", web_researcher_node) +research_team.add_node("papers", paper_researcher_node) +# ... edges ... +compiled_research = research_team.compile() + +# Top-level graph +top_graph = StateGraph(TopState) +top_graph.add_node("supervisor", top_supervisor_node) +top_graph.add_node("research_team", compiled_research) +top_graph.add_node("engineering_team", compiled_engineering) +# ... edges ... +``` + +**When to use**: Large-scale systems, domain specialization, team-based decomposition, complex organizations. + +## Pattern 4: Deep Agents (Standalone Library) + +A planner agent creates a structured todo list, then spawns subagents to execute each item with isolated context. + +### Installation + +```bash +pip install deepagents +# or +uv add deepagents +``` + +### Core API: create_deep_agent + +```python +from deepagents import create_deep_agent +from langchain.chat_models import init_chat_model + +# Basic usage -- returns compiled LangGraph graph +agent = create_deep_agent() +result = agent.invoke({"messages": [{"role": "user", "content": "Research and write a summary"}]}) + +# Custom configuration +agent = create_deep_agent( + model=init_chat_model("openai:gpt-5.5"), + tools=[my_custom_tool], + system_prompt="You are a research assistant.", +) + +# Use with LangGraph features +agent = create_deep_agent() +# Stream, checkpoint, HITL, Studio -- all LangGraph features work +async for part in agent.astream(input, config, stream_mode="updates"): + print(part) +``` + +### Middleware Architecture + +Three middleware auto-attached by default: + +1. **write_todos middleware**: Adds `write_todos` tool + instructions. Enables explicit planning with task decomposition, progress tracking, and dynamic plan revision. + +2. **Filesystem middleware**: Adds file tools (`ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep`). Offloads large context to storage, preventing context window overflow. Auto-summarization triggers when conversations grow long. + +3. **Subagent middleware**: Adds `task` tool for spawning specialized subagents with isolated context windows. Keeps main agent's context clean while going deep on specific subtasks. + +Filesystem backends: in-memory (default), local disk, LangGraph store (cross-thread), Modal/Daytona/Deno sandboxes (isolated execution), composite routing, or custom. + +Also includes: shell access (`execute` tool), MCP support, auto-summarization, large output handling, long-term memory (Store), and CLI with web search/sandboxes/HITL. Security: "trust the LLM" model -- enforce boundaries at tool/sandbox level. For simpler tasks, use `create_react_agent` instead. + +**When to use**: Complex decomposition, document generation, codebase-wide changes, multi-step research, context isolation. + +## Choosing the Right Pattern + +| Pattern | Control | Complexity | Best For | Performance | +|---------|---------|------------|----------|-------------| +| Supervisor | Centralized | Medium | Task routing, clear specializations | Extra hop per delegation | +| Swarm | Decentralized | Low-Medium | Conversational handoffs, peer agents | ~40% faster than supervisor | +| Hierarchical | Layered | High | Large teams, domain hierarchy | Depends on depth | +| Deep Agents | Plan-driven | High | Complex decomposition, isolated execution | Context-efficient | + +### Mental Model Test +- **Looks like a flowchart with loops** -> LangGraph (StateGraph) +- **Looks like a conversation thread** -> Swarm (handoffs) +- **Looks like a job description board** -> Supervisor (routing) +- **Looks like a project plan with subtasks** -> Deep Agents (planning) + +### Key Insight +The framework matters less than the infrastructure around it -- state persistence, retry handling, deployment, and monitoring determine reliability more than the agent pattern choice. + +## Comparison (March 2026) + +**LangGraph**: production-grade stateful + LangSmith observability + time-travel + HITL (steeper learning curve). **CrewAI**: fastest time-to-production, role-based (less mature monitoring). **AutoGen**: conversational patterns (maintenance mode). **Google ADK**: Google ecosystem, A2A, multi-language (tighter coupling). diff --git a/.agents/skills/langgraph-deep-agents/references/VERSIONING_FRESHNESS.md b/.agents/skills/langgraph-deep-agents/references/VERSIONING_FRESHNESS.md new file mode 100644 index 0000000..0b46e0f --- /dev/null +++ b/.agents/skills/langgraph-deep-agents/references/VERSIONING_FRESHNESS.md @@ -0,0 +1,51 @@ +# LangGraph Deep Agents — Versioning and Freshness + +Full source list, version pins, and SOTA deltas. LangGraph APIs evolve +frequently — always verify import paths, class names, and method signatures +against the latest docs before shipping user code. Do not hardcode minor +versions in user code. + +## Official docs and sources + +- **Official docs**: https://langchain-ai.github.io/langgraph/ +- **GitHub (LangGraph)**: https://github.com/langchain-ai/langgraph +- **GitHub (Deep Agents)**: https://github.com/langchain-ai/deepagents (MIT license -- verify star count and version at source) +- **Deep Agents PyPI**: https://pypi.org/project/deepagents/ +- **Deep Agents CLI**: https://pypi.org/project/deepagents-cli/ +- **LangSmith Deployment**: https://www.langchain.com/langsmith/deployment +- **Supervisor library**: https://github.com/langchain-ai/langgraph-supervisor-py +- **Swarm library**: https://github.com/langchain-ai/langgraph-swarm-py + +## Deep Agents standalone library + +Deep Agents is a standalone library (not merged into LangGraph core) built on +LangGraph runtime. Provides planning (write_todos), subagent spawning (task +tool), filesystem backends (in-memory/disk/LangGraph store/sandboxes), +long-term memory, HITL, and auto-summarization. CLI available separately. + +## Key recent additions + +- **LangGraph 1.0 GA**: durable state + built-in persistence + first-class HITL as stable primitives; only notable breaking change is the deprecation of `langgraph.prebuilt` — enhanced functionality moved to `langchain.agents`. +- **LangGraph v1.2.4** (current as of 2026-06-04): builds on v1.1.x Deep Agent templates and distributed runtime support in the CLI; v2 type-safe streaming/invoke with Pydantic/dataclass coercion and time-travel fixes for RESUME values and subgraph parent checkpoints; model retry middleware, content moderation middleware (OpenAI), `SystemMessage` support in `create_agent`, summarization middleware, HITL middleware; pluggable sandbox integrations (Modal, Daytona, Runloop). +- **Deep Agents `0.6.8`** (2026-06-03): async subagents, multi-modal `read_file`, backend protocol update for binary files, `dcode` CLI, and ACP integration. +- **Functional API** (`@entrypoint`, `@task`) available alongside the graph API for imperative-style durable workflows — verify the current surface against the LangGraph changelog. +- LangGraph `version="v2"` streaming returns typed `StreamPart` dicts; invoke returns `GraphOutput` with `.value` and `.interrupts`. Default remains v1 for backwards compatibility. Incremental adoption supported. +- LangGraph Platform renamed to LangSmith Deployment (October 2025). Self-hosted options: lite (free), enterprise (in-VPC), hybrid BYOC. +- Checkpointer backends: MemorySaver (dev), SqliteSaver, PostgresSaver (prod recommended), DynamoDBSaver (AWS), MongoDB, Redis. +- Known limitation: `middleware` and custom `state_schema` mutually exclusive in `create_agent()`. +- Comparison: LangGraph = production-grade stateful (best observability via LangSmith). CrewAI = fastest time-to-production. AutoGen = maintenance mode. Deep Agents = complex multi-step tasks with context isolation. + +## Freshness (as-of 2026-06-04) + +Verified against the local SOTA guides `guia_completo_agentes/guia_langgraph_orquestracao.html` and `guia_completo_agentes/guia_deepagents.html`. + +- **LangGraph docs (Python)**: https://docs.langchain.com/oss/python/langgraph/overview — **LangGraph 1.0 is GA** (durable state, built-in persistence, first-class HITL; `langgraph.prebuilt` deprecated in favor of `langchain.agents`). Current line: **`langgraph 1.2.4`**. Checkpointers: MemorySaver, SqliteSaver, PostgresSaver, DynamoDBSaver, MongoDB, Redis. +- **LangGraph GitHub + releases**: https://github.com/langchain-ai/langgraph/releases and https://changelog.langchain.com/announcements/langgraph-1-0-is-now-generally-available (verify latest minor version at release time; do not hardcode in user code). +- **Deep Agents**: https://docs.langchain.com/oss/python/deepagents/overview and https://reference.langchain.com/python/deepagents/ ; releases: https://github.com/langchain-ai/deepagents/releases ; PyPI: https://pypi.org/project/deepagents/ (standalone library built on LangGraph runtime; **current line `deepagents == 0.6.8` released 2026-06-03**, Python `>=3.11,<4.0`). Extras: `deepagents[quickjs]` (Code Interpreter), `deepagents-acp` (IDE/ACP integration), `deepagents-code` (`dcode` CLI). April–May 2026 updates: async subagents (needs LangSmith Deployment), multi-modal `read_file` (PDF/audio/video), backend protocol update for binary files. +- **Supervisor**: https://github.com/langchain-ai/langgraph-supervisor-py ; **Swarm**: https://github.com/langchain-ai/langgraph-swarm-py +- **LangSmith Deployment** (was LangGraph Platform, rename Oct 2025): https://www.langchain.com/langsmith/deployment +- **MCP tools adapter** for LangChain/LangGraph: https://github.com/langchain-ai/langchain-mcp-adapters +- **OpenTelemetry GenAI semconv** (Development/Experimental) for tracing nodes/tools: https://opentelemetry.io/docs/specs/semconv/gen-ai/ +- **OWASP LLM Top 10 2025 relevance** (LLM06 Excessive Agency, LLM10 Unbounded Consumption): enforce interrupt_before on destructive nodes, cap iteration counts, scope cross-thread Store namespaces. https://genai.owasp.org/llm-top-10/ +- **Runtime defaults** (repo policy): Python 3.13 via `uv` / `.python-version` (Python 3.14 only if project explicitly opts in). Deep Agents CLI tested under this runtime. +- **Model reference** in example (`init_chat_model("openai:gpt-5.4-mini")`) aligns with repo CLAUDE.md model family (gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano; also Opus 4.8, Sonnet 4.6, Haiku 4.5; gemini-3.1-pro-preview, gemini-3.5-flash). From c3c31dbacaa45b31356f7886a56ed457fa151377 Mon Sep 17 00:00:00 2001 From: Rafael Bittencourt Date: Thu, 25 Jun 2026 22:01:49 -0300 Subject: [PATCH 02/16] docs(guias-agentes): atualiza guias de agentes (Gemini Interactions API GA, 2026-06-25) Sincroniza o conjunto de guias a partir do master: - Gemini Interactions API: Beta -> GA (caminho SOTA recomendado) - Bumps de versao: openai-agents 0.17.7, google-genai 2.10.0, anthropic 0.112.0, deepagents 0.6.12, google-adk 2.3.0/1.36.0, pydantic-ai 2.0.0 - Sonnet 4.6 max output 128K; Claude Fable 5 GA (indisponivel no momento) - Datas de verificacao atualizadas para 2026-06-25 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../guia_agentic_vision_code_tools.html | 1705 +++ .../guia_arquitetura_orquestracao.html | 1043 ++ .../guia_claude_api.html | 6486 ++++++++++++ ...guia_contexto_compactacao_estrategias.html | 1630 +++ .../guia_deepagents.html | 2581 +++++ .../guia_estado_contexto_memoria.html | 1640 +++ .../guia_ferramentas_mcp_rag.html | 1001 ++ .../guia_file_inputs_no_storage.html | 1314 +++ .../guia_gemini_interactions_api.html | 4534 ++++++++ .../guia_langgraph.html | 3987 +++++++ .../guia_langgraph_orquestracao.html | 911 ++ .../guia_multimodal.html | 9182 +++++++++++++++++ .../guia_openai_modelos.html | 5963 +++++++++++ .../guia_operacao_seguranca_evals.html | 1163 +++ ...lelismo_tools_openai_gemini_anthropic.html | 3314 ++++++ .../guia_providers_adapters.html | 911 ++ .../agents_tools_best_guides/guia_skills.html | 1946 ++++ .../guia_token_counting.html | 7305 +++++++++++++ .../agents_tools_best_guides/index.html | 903 ++ 19 files changed, 57519 insertions(+) create mode 100644 references/agents_tools_best_guides/guia_agentic_vision_code_tools.html create mode 100644 references/agents_tools_best_guides/guia_arquitetura_orquestracao.html create mode 100644 references/agents_tools_best_guides/guia_claude_api.html create mode 100644 references/agents_tools_best_guides/guia_contexto_compactacao_estrategias.html create mode 100644 references/agents_tools_best_guides/guia_deepagents.html create mode 100644 references/agents_tools_best_guides/guia_estado_contexto_memoria.html create mode 100644 references/agents_tools_best_guides/guia_ferramentas_mcp_rag.html create mode 100644 references/agents_tools_best_guides/guia_file_inputs_no_storage.html create mode 100644 references/agents_tools_best_guides/guia_gemini_interactions_api.html create mode 100644 references/agents_tools_best_guides/guia_langgraph.html create mode 100644 references/agents_tools_best_guides/guia_langgraph_orquestracao.html create mode 100644 references/agents_tools_best_guides/guia_multimodal.html create mode 100644 references/agents_tools_best_guides/guia_openai_modelos.html create mode 100644 references/agents_tools_best_guides/guia_operacao_seguranca_evals.html create mode 100644 references/agents_tools_best_guides/guia_paralelismo_tools_openai_gemini_anthropic.html create mode 100644 references/agents_tools_best_guides/guia_providers_adapters.html create mode 100644 references/agents_tools_best_guides/guia_skills.html create mode 100644 references/agents_tools_best_guides/guia_token_counting.html create mode 100644 references/agents_tools_best_guides/index.html diff --git a/references/agents_tools_best_guides/guia_agentic_vision_code_tools.html b/references/agents_tools_best_guides/guia_agentic_vision_code_tools.html new file mode 100644 index 0000000..a19a676 --- /dev/null +++ b/references/agents_tools_best_guides/guia_agentic_vision_code_tools.html @@ -0,0 +1,1705 @@ + + + + + +Agentic vision & code tools — Code Interpreter, Code Execution, Shell e Tool Search + + + + + + + + + +
+
+
Agentic vision & code tools Code Interpreter · Code Execution · Shell · Tool Search
+
+ Verificado em 2026-06-19 + Transversal + OpenAI + Gemini + Anthropic + +
+
+
+ +
+ + +
+ +
+

Agentic vision & code tools

+

+ Como dar a um agente olhos com lupa e mãos com código — sem perder o controle. + Este guia cobre as code tools hospedadas dos três providers (OpenAI Code Interpreter e Shell, + Gemini Code Execution, Anthropic Code Execution), o mecanismo de Tool Search com + defer_loading onde ele existe, a seleção dinâmica de tools no runtime onde ele não + existe, o fallback local de visão em worker isolado e os contratos de schema que valem para + qualquer provider. O princípio transversal: quem decide quais code tools entram no payload + é o gating do runtime, não o provider. +

+
+ Transversal · OpenAI · Gemini · Anthropic + Code tools + Tool Search + SOTA · verificado 2026-06-10 +
+
+ +
+

Sobre este guia

+

+ Este é um guia para IA e humanos: prosa em PT-BR, identificadores, parâmetros e + código em inglês. Ele consolida os fatos verificados sobre as ferramentas de execução de código + e de descoberta dinâmica de tools, e os padrões de engenharia para usá-las em uma arquitetura + em que o runtime é dono do histórico, dos artefatos e das decisões de segurança. +

+
+ Princípio central: code tools são as capabilities mais poderosas — e mais caras + e arriscadas — do catálogo. O modelo solicita execução; o runtime decide antes da + request se a ferramenta sequer aparece no payload (gating), valida argumentos e + persiste cada artefato. Esse é o mesmo invariante do + capability registry do + capítulo de arquitetura, aplicado aqui a Code Interpreter, Code Execution, Shell e Tool Search. +
+
+ Fronteira de escopo (cross-link, sem duplicar): os princípios completos de + estado runtime-owned (store:false, ledger canônico, proibição de + previous_response_id/previous_interaction_id) vivem em + Estado, contexto & memória e + File inputs sem storage. A leitura nativa de + PDF/imagem/planilha por provider vive em Multimodal. + Governança, ACL e contratos de tool em geral vivem em + Ferramentas, MCP & RAG. Aqui tratamos apenas do + que é específico de code tools, shell e tool search. +
+
+ +
+

Mapa de fronteiras — onde cada assunto mora

+
+ + + + + + + + + + + + +
Você procura…Vá para
Ledger canônico, compaction, store:false, asset registryNúcleo · Estado, contexto & memória
Enviar PDFs/imagens sem storage do provider (bytes, file IDs, limites)File inputs sem storage
Visão nativa, OCR, planilhas, vídeo, áudio por providerMultimodal
Capability registry, active plan, skeleton de loop de orquestraçãoNúcleo · Arquitetura & orquestração
Contratos de tool, MCP, RAG, envelopes, segurança e HITLFerramentas, MCP & RAG
Contagem e custo detalhado de tokens por providerToken counting
Frameworks de orquestração (Agents SDK, LangGraph, DeepAgents, ADK)Agents SDK · LangGraph · Deep Agents · Google ADK
Interactions API do Gemini em profundidade (steps, signatures, background)Gemini Interactions API
Code tools deste guia: Code Interpreter, Code Execution, Shell, Tool SearchVocê está no lugar certo.
+
+ + +
+

Parte 1 — Decisão

+

Antes de qualquer parâmetro: quem liga e desliga as code tools, e com qual mecanismo.

+
+ +
+

1. Decisão executiva: gating no runtime

+
+ Decisão SOTA: o runtime deve fazer gating antes de chamar o provider. + Se a tarefa não precisa de visão agentic, não inclua Code Interpreter, Shell ou Code Execution + no payload. Se precisa de crop/zoom/renderização/rotação/contraste/validação visual fina, + inclua a ferramenta apropriada com tool_choice: "auto" (ou equivalente) e deixe o + modelo decidir o momento de uso. +
+

+ Tool Search não é o botão para ligar/desligar Code Interpreter. Tool Search é + um mecanismo de descoberta: carrega definições de tools deferidas no contexto quando o + modelo precisa delas. Ele é excelente para grandes catálogos de custom functions, namespaces e + MCP servers — mas não controla provisionamento, custo ou risco das code tools hospedadas. Para + reduzir custo/risco de Code Interpreter, Shell ou Code Execution, o mecanismo correto é + roteamento/gating no runtime: a ferramenta simplesmente não entra no array tools + quando o turno não a justifica. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProviderCode tool hospedadaVisão agenticTool Search nativo
OpenAI (Responses API)code_interpreter (python tool) e shell (hosted/local)Visão nativa via input_file/input_image + python tool para crop/zoom/rotateSim {"type":"tool_search"} + defer_loading (gpt-5.4+)
Gemini (Interactions API)code_execution (Python-only, 30s) — Interactions API documentada/verificada só na Developer API; em Vertex use generateContent + code_execution (ver §3)Visão nativa + Code Execution with images (documentado em Gemini 3 Flash; herdado pela linha 3.5)Não — seleção dinâmica no runtime (10–20 tools ativas)
Anthropic (Messages API)code_execution_20250825 / code_execution_20260120 (Python + Bash + file ops)Visão/PDF nativa + Code Execution para manipular/processarSim tool_search_tool_regex_20251119 / tool_search_tool_bm25_20251119
Fallback multi-providerWorker isolado próprio (Docker / Cloud Run / GKE)Custom function restrita vision_preprocess_document com allowlistToolRegistry + busca híbrida BM25/embeddings + loop de duas fases (§7)
+
+ Runtime-owned em uma frase: o provider é stateless do ponto de vista da + aplicação — cada chamada usa store:false (ou equivalente) e recebe o envelope + completo montado pelo runtime; histórico, tool calls, tool results e artefatos vivem no seu DB. + A mecânica completa (campos estruturais como id/signature, + anti-padrões de sessão provider-side) está em + Estado, contexto & memória e + File inputs sem storage. Fica aqui o checklist + resumido do que o runtime deve persistir — os dois últimos itens são específicos das code tools + deste guia: +
    +
  • histórico normalizado: mensagens, multimodal parts, tool calls, tool results, outputs, recusas, erros e approvals;
  • +
  • envelope provider-specific enviado e resposta bruta recebida, com versionamento de adapter;
  • +
  • reasoning/assinaturas criptográficas quando o provider exige round-trip para continuidade técnica — sem tratá-las como estado semântico de negócio;
  • +
  • artefatos: arquivos originais, crops, páginas renderizadas, imagens derivadas, CSVs e logs de worker, com checksums;
  • +
  • tool registry e snapshots dos schemas efetivamente expostos por turno;
  • +
  • decisões de gating: por que uma tool foi incluída, bloqueada, exigiu aprovação ou foi omitida.
  • +
+
+

1.1. Tabela de roteamento rápido

+
+ + + + + + + + +
Necessidade do turnoFerramenta certaMecanismo de controle
Resumo/Q&A sobre documento legívelVisão nativa, sem code toolGating: nenhuma code tool no payload
Crop/zoom/rotação/contraste, validar número pequeno em scanCode Interpreter (OpenAI) · Code Execution (Gemini/Anthropic)Gating inclui a tool; tool_choice: auto
CLI, repositório, build/test, multimedia, scripts de sistemaShell (OpenAI) · Code Execution com Bash (Anthropic)Gating + sandbox + allowlist + auditoria
Catálogo com dezenas/centenas de custom functions ou MCPTool Search (OpenAI/Anthropic) · ToolRegistry no runtime (Gemini)defer_loading ou pré-seleção por turno
Provider sem code tool adequada / requisito de isolamento própriovision_preprocess_document em worker isoladoAllowlist de operações + quotas + artifact store
+
+ + +
+

Parte 2 — Code tools por provider

+

Os contratos verificados de cada ferramenta hospedada: parâmetros, limites, versões e exemplos + prontos para o padrão runtime-owned.

+
+ +
+

2. OpenAI Code Interpreter (python tool)

+

+ Code Interpreter permite ao modelo escrever e executar Python em sandbox hospedada. A + documentação cita explicitamente o uso para processar arquivos, gerar arquivos e melhorar a + inteligência visual com crop, zoom, rotação e transformações de imagem. Internamente, + o modelo conhece a ferramenta como python tool — e é assim que o system prompt + deve se referir a ela (ver §10). +

+

+ Visão nativa vem primeiro: PDFs entram como input_file (texto + imagens das páginas + em modelos com visão) e imagens como input_image com detail + (low/high/original/auto; em + gpt-5.5, auto e omitido equivalem a original). Arquivos + não-PDF como .docx e .pptx são texto-only nesse fluxo + — sem imagens das páginas. Para documentos grandes com retrieval, a doc aponta File Search; para + planilhas pesadas (agregações, cálculos, custom charts), o Hosted Shell (§5). O detalhe + completo de file inputs e visão nativa está em Multimodal e + File inputs sem storage; aqui interessa o que a + python tool acrescenta quando a visão nativa não basta. +

+

2.1. Configuração do container

+
+ + + + + + + +
ConfigSignificadoRecomendação
container.type = "auto"Cria/reusa um container ativo presente no contexto do modelo.Usar em chamadas simples quando o runtime não precisa gerenciar o container ID.
memory_limitRAM do container: 1g (default), 4g, 16g, 64g.4g para agente de visão/PDF; 16g só para PDFs/imagens pesados; 64g é exceção justificada.
Arquivos no inputArquivos presentes no input são automaticamente disponibilizados no container.Mesmo assim, preferir file_id em produção para robustez e replay.
ExpiraçãoContainer auto expira após 20 minutos sem uso.Tratar como efêmero: baixar e persistir artefatos no artifact store do runtime a cada turno.
+

2.2. Exemplo runtime-owned com gating

+
from openai import OpenAI
+
+client = OpenAI()
+
+def build_tools(route: dict) -> list[dict]:
+    """Gating: code tools so entram no payload quando o roteador decide."""
+    tools = []
+    if route.get("needs_agentic_vision"):
+        tools.append({
+            "type": "code_interpreter",
+            "container": {"type": "auto", "memory_limit": "4g"},
+        })
+    if route.get("needs_shell"):
+        # Hosted shell; use local shell apenas quando seu runtime executar shell_call com sandbox.
+        tools.append({"type": "shell", "environment": {"type": "container_auto"}})
+    if route.get("needs_file_retrieval"):
+        tools.append({"type": "file_search", "vector_store_ids": ["vs_..."]})
+    return tools
+
+# Runtime-owned: o DB/orquestrador monta o historico completo; o provider nao guarda estado.
+history = runtime_db.load_normalized_history(thread_id="thr_123")
+route = runtime_router.classify(history)
+
+response = client.responses.create(
+    model="gpt-5.5",
+    store=False,
+    instructions=runtime_db.load_system_prompt() + "\n\n" + VISION_TOOL_SYSTEM_SECTION,
+    input=runtime_adapter.to_openai_input(history),
+    tools=build_tools(route),
+    tool_choice="auto",
+    include=["reasoning.encrypted_content"],
+)
+
+runtime_db.persist_provider_output(
+    thread_id="thr_123",
+    provider="openai",
+    raw_output=response.output,
+    normalized_events=runtime_adapter.from_openai_output(response.output),
+)
+
+ Custo: Code Interpreter cobra container por tier de memória, além dos tokens — + e desde 2026-06-02 a cobrança é por minuto, com mínimo de 5 minutos (detalhes e + tabela em §11). Mais um motivo para o gating: container não usado é + dinheiro queimado por turno. +
+ +
+ +
+

3. Gemini Code Execution

+

+ O Gemini Code Execution gera e executa Python em ambiente hospedado pelo Google. + Na Interactions API, habilita-se com tools=[{"type": "code_execution"}]. É a rota de + agentic vision do Gemini: o modelo escreve código que renderiza, recorta e amplia regiões de + imagens/PDFs e recebe os resultados de volta no mesmo turno. +

+
+ Vertex AI (agora Gemini Enterprise Agent Platform): code execution via Interactions API. + A Interactions API existe em duas superfícies com status e documentação diferentes. + Na Gemini Developer API (AI Studio) — endpoint + generativelanguage.googleapis.com/v1beta/interactions, auth x-goog-api-key, + status Beta — o code_execution dentro de Interactions é + documentado e exemplificado por inteiro. Na Vertex AI / Gemini Enterprise + Agent Platform — endpoint + aiplatform.googleapis.com/v1beta1/projects/{project}/locations/global/interactions, + auth OAuth/ADC, status experimental — CodeExecution aparece no + schema de ferramentas, mas a página oficial de execução de código da Vertex documenta o + recurso apenas via generateContent (sem exemplo de + code_execution dentro de Interactions). + Observado (não é limitação oficial): em teste, code_execution via + Interactions API falhou autenticando por Vertex e funcionou pela Developer API — os + docs nem confirmam nem negam essa combinação na Vertex. + Recomendação: use Developer API + Interactions para + code_execution, ou na Vertex use generateContent + + code_execution (caminho oficialmente documentado). O exemplo 3.2 abaixo + assume a Developer API. Verificado em 2026-06-19 contra fontes oficiais Google. +
+

3.1. Limites documentados

+
+ + + + + + + + + + +
DimensãoFato verificado
LinguagemSomente Python — sem Bash, sem shell, sem outras linguagens.
Runtime máximo30 segundos por execução.
RetriesAté 5 tentativas automáticas em caso de erro.
BibliotecasConjunto fixo, sem pip install: inclui pillow, opencv-python, PyPDF2, python-docx, python-pptx, numpy, pandas, matplotlib, entre outras.
Entrada preferidaFunciona melhor com texto/CSV; imagens entram pelo fluxo "Code Execution with images".
ImagensCode Execution with images é oficialmente documentado em Gemini 3 Flash e herdado pela linha GA gemini-3.5-flash — use gemini-3.5-flash nos exemplos e valide por evals.
Custo extraNenhum além de tokens: código gerado e resultados são cobrados como intermediate tokens (ver §11 e Token counting).
+

3.2. Exemplo runtime-owned (Interactions API)

+
from google import genai
+
+client = genai.Client()   # Developer API (GEMINI_API_KEY); em Vertex use generateContent + code_execution (ver aviso da secao 3)
+
+# Runtime-owned: store=False, sem previous_interaction_id, sem background provider-managed.
+# O runtime monta o input/historico e preserva id/signature dos steps retornados.
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",   # Code Execution with images: documentado em Gemini 3 Flash, herdado pela linha 3.5 GA
+    store=False,
+    input=runtime_adapter.to_gemini_interactions_input(thread_id="thr_123"),
+    tools=[
+        {"type": "code_execution"},
+        {   # tool combination: custom function de busca no registry (loop de duas fases, ver §7.3)
+            "type": "function",
+            "name": "search_internal_tools",
+            "description": "Search the runtime tool registry for relevant custom tools allowed for this tenant/user.",
+            "parameters": {
+                "type": "object",
+                "properties": {
+                    "goal": {"type": "string", "description": "Capability needed by the model."},
+                    "max_tools": {"type": "integer", "description": "Maximum tools to return."},
+                },
+                "required": ["goal"],
+            },
+        },
+    ],
+)
+
+runtime_db.persist_gemini_steps(
+    thread_id="thr_123",
+    steps=interaction.steps,
+    preserve_fields=["id", "signature"],  # integridade estrutural do protocolo, nao memoria do provider
+)
+
+ Steps, signatures e modo stateless: quando o Gemini roda em modo + store:false com Code Execution ou combinação de tools, o runtime deve preservar e + reenviar os campos estruturais id e signature dos steps — isso é + integridade de protocolo, não estado semântico. A mecânica completa da Interactions API + (steps, tool combination, background) está em + Gemini Interactions API. +
+
+ Sem Tool Search nativo: o Gemini não tem equivalente de + defer_loading. Para catálogos grandes, a melhor prática oficial é manter o conjunto + ativo pequeno — idealmente 10–20 tools por chamada — com a seleção dinâmica + feita pelo runtime (§6.3 e §7). +
+ +
+ +
+

4. Anthropic Code Execution

+

+ O Code Execution da Anthropic é a code tool mais ampla dos três providers: executa + Python e Bash em sandbox server-side, com comandos shell, operações de arquivo + (criar/editar/processar) e acesso aos arquivos enviados no request. Está GA — não exige + beta header. A arquitetura de agentic vision resultante é composição: visão/PDF nativa + para entender, Code Execution para manipular e processar, runtime para persistir artefatos. + Disponibilidade: Claude API, Claude Platform on AWS e Microsoft Foundry — + não em Amazon Bedrock nem Vertex AI (verificado em 2026-06-19; mesmo recorte do + guia Claude API). +

+

4.1. Versões da ferramenta

+
+ + + + + + + + + + + + + +
VersãoCapacidadesModelos suportados
code_execution_20250825Python + Bash + file operations em sandbox server-side; execução por turno.Todos os modelos com tool use.
code_execution_20260120Tudo da versão anterior + REPL persistence (estado Python mantido entre execuções no mesmo container) + programmatic tool calling (o código pode invocar outras tools).Opus 4.5+ e Sonnet 4.5+ — não disponível em Haiku 4.5.
+
+ Modelos (verificado em 2026-06-10): claude-fable-5 (GA em + 2026-06-09) é o modelo mais novo da Anthropic; claude-opus-4-8 segue ativo e + excelente para produção. Os exemplos deste guia usam claude-opus-4-8; ambos + satisfazem o requisito "Opus 4.5+" da versão 20260120. +
+

4.2. Exemplo runtime-owned

+
import anthropic
+
+client = anthropic.Anthropic()
+
+response = client.messages.create(
+    model="claude-opus-4-8",   # claude-fable-5 (GA 2026-06-09) tambem suporta; Haiku 4.5 exige a versao 20250825
+    max_tokens=4096,
+    messages=runtime_adapter.to_anthropic_messages(thread_id="thr_123"),
+    tools=[
+        # 20260120: REPL persistente + programmatic tool calling (Opus 4.5+ / Sonnet 4.5+)
+        {"type": "code_execution_20260120", "name": "code_execution"},
+        {
+            "name": "vision_preprocess_document",
+            "description": (
+                "Render, crop, zoom, rotate, or enhance visual regions from a document/image. "
+                "Use only when native vision is insufficient for small text, charts, tables, "
+                "stamps, signatures, or diagrams."
+            ),
+            "input_schema": {
+                "type": "object",
+                "properties": {
+                    "file_id": {"type": "string", "description": "Runtime artifact/file identifier."},
+                    "operations": {"type": "array", "items": {"type": "object"}},
+                },
+                "required": ["file_id", "operations"],
+            },
+            "strict": True,
+        },
+    ],
+    tool_choice={"type": "auto"},
+)
+runtime_db.persist_anthropic_response(thread_id="thr_123", response=response)
+
+ Quando usar cada versão: use code_execution_20260120 por padrão em + Opus/Sonnet 4.5+ — REPL persistente reduz re-renderizações de página em fluxos de visão com + múltiplos crops, e programmatic tool calling permite que o código consulte outras tools sem + round-trip. Recue para code_execution_20250825 quando o roteador puder cair em + Haiku 4.5 ou modelos anteriores. +
+

+ Client tools continuam rodando no seu runtime e server tools na infraestrutura da Anthropic — + em ambos os casos o runtime persiste tool_use/tool_result e artefatos. + Server tools não substituem o DB do orquestrador. Visão/PDF nativos (resolução alta em Opus 4.7+ + e posteriores, custo em tokens) estão detalhados em Multimodal. +

+ +
+ +
+

5. OpenAI Shell tool

+

+ O Shell dá ao modelo um ambiente de terminal completo. Há dois modos: containers + hospedados pela OpenAI (hosted shell) e um runtime local que você hospeda e executa + (local shell). O Shell está disponível apenas na Responses API — não existe na + Chat Completions API. +

+
+ Risco: executar comandos shell arbitrários é perigoso. Sempre sandbox a + execução, aplique allowlists/denylists onde possível e registre toda atividade da tool para + auditoria. Conteúdo obtido pela rede pode conter prompt injection — trate-o como adversarial e + exija revisão extra para ações que modificam dados ou sistemas. +
+

5.1. Hosted shell: container_auto e container_reference

+
    +
  • environment.type = "container_auto": a OpenAI provisiona e gerencia o container da request.
  • +
  • environment.type = "container_reference" + container_id: você cria o container via client.containers.create(...) (com memory_limit e expires_after ancorado em last_active_at) e o reutiliza entre requests para fluxos iterativos.
  • +
  • Runtime atual baseado em Debian 12; diretório de trabalho /mnt/data (caminho suportado para artefatos baixáveis); sem TTY interativo; sem sudo.
  • +
  • Sem rede de saída por padrão. Habilitar exige allowlist de domínios no dashboard da org + network_policy explícita na request; domain_secrets injeta credenciais como placeholders ($API_KEY) sem expô-las ao modelo.
  • +
+
from openai import OpenAI
+
+client = OpenAI()
+
+response = client.responses.create(
+    model="gpt-5.5",
+    store=False,
+    tools=[{"type": "shell", "environment": {"type": "container_auto"}}],
+    input=[
+        {
+            "type": "message",
+            "role": "user",
+            "content": [
+                {"type": "input_text",
+                 "text": "Execute: ls -lah /mnt/data && python --version && node --version"},
+            ],
+        }
+    ],
+    tool_choice="auto",
+)
+print(response.output_text)
+
+ Multi-turn sem estado provider-side: a doc oficial demonstra continuação com + previous_response_id — sob a política runtime-owned deste portal isso é + anti-padrão. Reutilize apenas o container via container_reference e + reenvie o histórico montado pelo runtime com store:false + (ver Estado, contexto & memória). +
+

5.2. Local shell: shell_call → shell_call_output

+

+ Hosted e local usam os mesmos tipos de output item: shell_call (comandos pedidos + pelo modelo) e shell_call_output (saída e exit outcome). No modo local, sua + aplicação executa cada shell_call e devolve shell_call_output na + request seguinte: +

+
# Loop de local shell: o SEU runtime executa, nunca o provider.
+pending_input = runtime_adapter.to_openai_input(history)
+
+while True:
+    response = client.responses.create(
+        model="gpt-5.5",
+        store=False,
+        tools=[shell_tool_local],   # shell tool configurada para execucao local (ver doc oficial / Agents SDK shell executor)
+        input=pending_input,
+    )
+    shell_calls = [item for item in response.output if item.type == "shell_call"]
+    if not shell_calls:
+        break
+
+    outputs = []
+    for call in shell_calls:
+        guard.enforce_allowlist(call)              # sandbox + allow/deny lists + limites
+        result = local_sandbox.run(call)           # captura stdout, stderr e outcome (inclusive exit != 0)
+        runtime_db.persist_shell_call(call, result)
+        outputs.append({
+            "type": "shell_call_output",
+            "call_id": call.call_id,
+            "output": result.to_provider_payload(),  # respeite max_output_length quando presente no shell_call
+        })
+    pending_input = outputs
+
    +
  • Timeout estourou? Devolva outcome de timeout com a saída parcial capturada.
  • +
  • Preserve outputs de exit code diferente de zero — o modelo precisa deles para raciocinar sobre recuperação.
  • +
  • Execução deve ser não-interativa; não dependa de comandos que esperam input.
  • +
+
+ Regra prática: para visão/PDF, prefira Code Interpreter/python tool. Use Shell + quando precisar de CLI, bibliotecas do sistema, scripts existentes, repositórios, build/test ou + worker local controlado. Para um simples crop/zoom, uma custom function restrita (§8) é mais + segura que shell arbitrário. +
+ +
+ + + + +
+

6. Tool Search & defer_loading por provider

+

+ Tool Search resolve um problema específico: catálogos grandes de definições de tools consomem + tokens e degradam a seleção. Com tools deferidas, o modelo vê inicialmente só nome e + descrição (ou só o nome/descrição do namespace/servidor MCP), busca quando precisa e carrega as + definições completas sob demanda. +

+
+ Reprise da decisão executiva: Tool Search serve para descobrir custom + functions/MCP em catálogos grandes. Ele não é o mecanismo para ligar/desligar + Code Interpreter, Shell ou Code Execution — isso é gating no runtime (§1). +
+ +

6.1. OpenAI — {"type":"tool_search"}

+
    +
  • Suportado apenas em gpt-5.4+.
  • +
  • Ativação: incluir {"type": "tool_search"} no array tools e marcar functions/MCP com defer_loading: true.
  • +
  • Hosted tool search: a busca roda na OpenAI sobre as tools declaradas na própria request. Comece por aqui.
  • +
  • Client-executed tool search: o modelo emite tool_search_call; sua aplicação responde com tool_search_output, podendo injetar definições novas via additional_tools — ideal quando a disponibilidade depende de tenant, projeto, permissões ou registry interno.
  • +
  • Namespaces: agrupe funções deferidas em namespaces ou MCP servers com descrições de alto nível; defer_loading aplica-se às funções dentro do namespace, não ao objeto namespace. Melhor prática oficial: menos de 10 functions por namespace. Um namespace pode misturar tools deferidas e não-deferidas.
  • +
  • Para função deferida individual, o modelo continua vendo nome e descrição — na prática o que se difere é principalmente o parameter schema.
  • +
+
{
+  "model": "gpt-5.5",
+  "store": false,
+  "tools": [
+    { "type": "tool_search" },
+    {
+      "type": "function",
+      "name": "billing_list_invoices",
+      "description": "List invoices for the authenticated customer, filtered by period.",
+      "parameters": { "type": "object", "properties": { "period": { "type": "string" } },
+                      "required": ["period"], "additionalProperties": false },
+      "defer_loading": true
+    },
+    {
+      "type": "mcp",
+      "server_label": "crm",
+      "server_url": "https://mcp.example.internal/crm",
+      "defer_loading": true
+    }
+  ],
+  "input": "..."
+}
+ +

6.2. Anthropic — Regex e BM25

+
    +
  • Duas variantes de server tool: tool_search_tool_regex_20251119 e tool_search_tool_bm25_20251119.
  • +
  • Tools do catálogo levam defer_loading: true; a busca cobre nomes, descrições e argumentos.
  • +
  • Pelo menos uma tool não-deferida é exigida no request.
  • +
  • Cada busca carrega tipicamente 3–5 tools para o contexto; o mecanismo escala até ~10.000 tools no catálogo.
  • +
+
{
+  "model": "claude-opus-4-8",
+  "max_tokens": 4096,
+  "tools": [
+    { "type": "tool_search_tool_bm25_20251119", "name": "tool_search" },
+    {
+      "name": "orders_get_order_status",
+      "description": "Look up the current status of a customer order by order ID. ...",
+      "input_schema": { "type": "object", "properties": { "order_id": { "type": "string" } },
+                        "required": ["order_id"] }
+    },
+    {
+      "name": "billing_list_invoices",
+      "description": "List invoices for the authenticated customer, filtered by period. ...",
+      "input_schema": { "type": "object", "properties": { "period": { "type": "string" } },
+                        "required": ["period"] },
+      "defer_loading": true
+    }
+  ],
+  "messages": [ ... ]
+}
+

+ No exemplo, orders_get_order_status permanece não-deferida (requisito mínimo) e + atua como "hot tool"; o resto do catálogo é deferido e descoberto via BM25. +

+ +

6.3. Gemini — sem equivalente nativo

+

+ Não há, nas docs oficiais consultadas, equivalente direto ao Tool Search com + defer_loading nativo no Gemini. A recomendação oficial de function calling é manter + o conjunto ativo pequeno e relevante — idealmente 10–20 tools quando o catálogo + total é grande. Em outras palavras: a seleção dinâmica é responsabilidade do runtime, por + pré-seleção via registry antes da chamada ou por uma tool client-side + search_internal_tools com loop de duas fases (§7). +

+ +

6.4. Comparativo

+
+ + + + + + + + +
DimensãoOpenAIAnthropicGemini
Mecanismo nativo{"type":"tool_search"}tool_search_tool_regex_20251119 / tool_search_tool_bm25_20251119N/D — runtime decide
Flag de deferimentodefer_loading: true (functions, MCP, funções de namespace)defer_loading: true—
Modelosgpt-5.4+Modelos com tool use atuais—
ModosHosted e client-executed (tool_search_call/tool_search_output + additional_tools)Server tool (busca na Anthropic)Pré-seleção no runtime ou loop de duas fases
Restrições/escalaNamespaces <10 functions (melhor prática)≥1 tool não-deferida; 3–5 tools por busca; até ~10k tools10–20 tools ativas (melhor prática oficial)
+
+ Quando usar Tool Search: muitos custom functions, muitos MCP servers, + namespaces grandes, catálogo por tenant/permissão, schemas consumindo tokens ou selection errors + por excesso de opções. Quando não usar: catálogos pequenos (<20–30 tools) — + e nunca como substituto de gating de code tools. +
+ +
+ +
+

7. ToolRegistry & fallback de Tool Search no runtime

+

+ Para providers sem Tool Search nativo (Gemini) — ou quando você quer comportamento uniforme + entre providers — o runtime implementa um ToolRegistry e uma etapa de seleção + dinâmica. A meta: expor ao modelo apenas hot tools + tools relevantes para aquele turno, + preservando permissões, tenant, risco e custo. +

+
+ Dono do tema: o registry canônico, a ACL e a governança de capabilities são do + capability registry + (arquitetura) e dos contratos de + Ferramentas, MCP & RAG. Esta seção cobre apenas a + camada de busca e seleção por turno que emula Tool Search. +
+

7.1. Arquitetura em seis passos

+
    +
  1. Registry canônico: armazena schema, descrições, ACL, risco, side effects, versão, executor e tags.
  2. +
  3. Roteador: classifica a tarefa — texto simples, retrieval, tool-needed, agentic vision, shell-needed, high-risk.
  4. +
  5. Busca híbrida: BM25 sobre name/description/nomes de argumentos + embeddings sobre description_full + priors de namespace/tenant/uso.
  6. +
  7. Filtro de segurança: tenant, user scopes, plano, risk gates, classificação de dados e confirmações.
  8. +
  9. Chamada ao provider: payload com hot tools + top-k schemas; no Gemini, manter o conjunto ativo pequeno; em OpenAI/Anthropic, preferir o nativo quando disponível.
  10. +
  11. Loop de duas fases: se o modelo pedir capacidade não carregada via search_internal_tools, o runtime busca e refaz a chamada com os schemas carregados.
  12. +
+

7.2. Registry e busca

+
from dataclasses import dataclass
+from typing import Any, Literal
+
+@dataclass
+class ToolRegistryEntry:
+    name: str
+    namespace: str
+    version: str
+    description_short: str
+    description_full: str
+    parameters_json_schema: dict[str, Any]
+    executor_ref: str
+    tags: list[str]
+    required_scopes: list[str]
+    side_effects: Literal["none", "external_write", "payment", "message_send", "code_execution"]
+    read_only: bool
+    idempotent: bool
+    risk_level: Literal["low", "medium", "high", "critical"]
+    requires_confirmation: bool
+    hot: bool = False
+    defer_loading: bool = True
+
+class ToolRegistry:
+    def search(self, *, goal: str, tenant_id: str, user_scopes: list[str], max_tools: int = 5):
+        candidates = self._filter_by_tenant_acl(tenant_id, user_scopes)
+        # Hybrid rank: BM25 sobre names/descriptions/arg names + embeddings sobre description_full.
+        ranked = self._rank(goal, candidates)
+        return ranked[:max_tools]
+

7.3. Tool client-side de busca (loop de duas fases)

+
{
+  "type": "function",
+  "name": "search_internal_tools",
+  "description": "Search the runtime tool registry for relevant custom tools allowed for this tenant/user.",
+  "parameters": {
+    "type": "object",
+    "properties": {
+      "goal": { "type": "string", "description": "Capability needed by the model." },
+      "max_tools": { "type": "integer", "description": "Maximum tools to return." }
+    },
+    "required": ["goal"]
+  }
+}
+

7.4. Pseudoprotocolo provider-agnostic

+
# Phase 0: runtime-owned history
+history = db.load_history(thread_id)
+route = router.classify(history)
+
+# Phase 1: schema selection
+hot = registry.hot_tools(tenant_id, scopes)
+selected = registry.search(goal=route.goal, tenant_id=tenant_id, user_scopes=scopes, max_tools=route.max_tools)
+active_tools = merge_and_dedupe(hot, selected)
+
+# Phase 2: provider call
+request = adapter.build_request(
+    history=history,
+    tools=active_tools,
+    store_provider_state=False,
+    include_structural_roundtrip_fields=True,
+)
+response = provider.call(request)
+
+# Phase 3: execute client tools and persist
+for call in adapter.extract_tool_calls(response):
+    validate_args(call.schema, call.args)
+    enforce_acl(call, user, tenant)
+    if call.requires_confirmation:
+        pause_for_human_approval(call)
+    result = executor.run(call)
+    db.persist_tool_result(call, result)
+
+# Phase 4: continue until final or budget exhausted
+# Sempre persistir eventos raw + normalizados no runtime DB, nunca em sessions provider-managed.
+
+ Melhor prática: se o catálogo for pequeno, não use esse mecanismo. Se houver + >20–30 tools, múltiplos tenants, MCP servers grandes ou selection errors recorrentes, use. +
+
+ + +
+

Parte 4 — Fallback & contratos

+

O fallback local de visão em worker isolado, os schemas de custom functions que funcionam nos + três providers e o bloco de system prompt que disciplina o uso da code tool.

+
+ +
+

8. Fallback local de visão

+

8.1. Por que não expor shell arbitrário?

+

+ Para providers/cenários sem Code Interpreter/Code Execution adequado, o melhor fallback de visão + não é dar um shell livre ao modelo. É criar uma custom function restrita, com + operações visualmente úteis e allowlisted. Shell local só entra para workloads confiáveis, + coding agents, testes de repositório ou quando o runtime consegue isolar de verdade. +

+
@function_tool
+async def vision_preprocess_document(
+    file_id: str,
+    operations: list[dict],
+) -> dict:
+    """
+    Preprocess a visual document/image through allowlisted operations only.
+    Allowed operations: render_pdf_page, crop, zoom, rotate, enhance_contrast, split_grid, thumbnail.
+    Returns runtime artifact IDs that the orchestrator can feed back as images/files.
+    """
+    # 1. Resolve file_id a partir do object store do runtime, nunca caminhos arbitrarios.
+    # 2. Execute em worker/container isolado com limites de CPU/memoria/tempo.
+    # 3. Use PyMuPDF/Pillow/OpenCV atras de allowlists estritas.
+    # 4. Armazene artefatos derivados no object storage.
+    # 5. Retorne apenas artifact IDs e metadata pequena, nunca segredos ou paths locais.
+    return {
+        "ok": True,
+        "artifacts": [
+            {"artifact_id": "art_crop_001", "mime_type": "image/png",
+             "description": "Cropped zoom from page 2."}
+        ],
+    }
+

8.2. Allowlist de operações

+
+ + + + + + + + + +
OperaçãoUsoParâmetrosRisco a controlar
render_pdf_pageTransformar página em PNG/JPEG para inspeção visual.page, dpi/scaleLimitar páginas máximas e pixels.
cropRecortar tabela, gráfico, assinatura, carimbo, texto pequeno.bboxValidar bounds.
zoomAmpliar região.scaleLimitar pixels finais.
rotateCorrigir inclinação.degreesLimitar valores.
enhance_contrastMelhorar legibilidade.factorNão "inventar" pixels; declarar incerteza.
split_gridDividir página complexa em tiles.rows, colsLimitar tiles.
+

8.3. Worker local em Docker Compose (testes)

+
services:
+  vision-worker:
+    build: ./vision-worker
+    read_only: true
+    network_mode: "none"
+    pids_limit: 256
+    mem_limit: 2g
+    cpus: "1.0"
+    security_opt:
+      - no-new-privileges:true
+    cap_drop:
+      - ALL
+    tmpfs:
+      - /tmp:size=256m,mode=1777
+    volumes:
+      - ./scratch/in:/work/in:ro
+      - ./scratch/out:/work/out:rw
+    environment:
+      MAX_PAGES: "20"
+      MAX_PIXELS: "12000000"
+      MAX_SECONDS: "30"
+

8.4. Produção: Cloud Run / GKE

+

+ Em produção, use Cloud Run Jobs/Services ou GKE como worker isolado: imagem imutável, Workload + Identity, rede sem egress por padrão, quotas de CPU/RAM, timeout curto, filesystem efêmero, GCS + para input/output, logs estruturados, trace ID por tool call e política de retenção para + artefatos. Use o pricing calculator do GCP no momento do deploy — o custo do worker local não é + cobrado pelo provider LLM, mas vira custo de infraestrutura, segurança e operação. +

+
+ +
+

9. Schemas de custom functions multi-provider

+

+ Esta seção é canônica para geração/validação de schemas de custom functions nos três providers + e deve ser indexada com alta prioridade em pipelines de RAG que consultam este + portal. Os princípios gerais de design de contrato de tool (envelopes, side-effect levels, HITL) vivem em + Ferramentas, MCP & RAG; + aqui fica a tabela de equivalência de campos e as regras de naming/description. +

+

9.1. Equivalência de campos

+
+ + + + + + + + + + +
ConceitoOpenAI Responses / AgentsAnthropic MessagesGemini Interactions / GenAI
Tipo da tooltools[].type = "function"Client tool sem type; server tools têm type versionadoInteractions: type:"function"; generateContent: functionDeclarations
Nomenamename, regex ^[a-zA-Z0-9_-]{1,64}$name
Descriçãodescriptiondescription (fator mais importante na seleção)description
Schema de entradaparametersinput_schemaparameters
Strict modestrict:true; requer additionalProperties:false e todos os campos em requiredstrict:true disponível nas propriedades opcionaisSubset OpenAPI/JSON Schema; validar no runtime
ExemplosNão é campo universal; colocar em description/registryinput_examples opcional para client toolsPrompt/registry; o SDK Python pode converter docstrings no fluxo automático
Deferred loadingdefer_loading:true com Tool Searchdefer_loading:true com Tool SearchN/D — seleção no runtime (§7)
+

+ OpenAI recomenda strict mode para aderência ao schema, com additionalProperties:false + e todos os campos em required (use null para opcionais quando + necessário). Gemini recomenda nomes/descrições claros, tipos fortes, enums e conjunto ativo + pequeno. Anthropic dá peso especial à description — 3–4 frases ou mais para tools complexas, + cobrindo o que a tool faz, quando usar/não usar, parâmetros, caveats e limitações. +

+

9.2. Schema canônico interno

+
{
+  "name": "orders_get_order_status",
+  "namespace": "orders",
+  "version": "v1",
+  "description_short": "Look up the current status of a customer order.",
+  "description_full": "Look up the current status of a customer order by order ID. Use this when the user asks where an order is, whether it shipped, whether it was delivered, or when it will arrive. Do not use this for refunds, invoice questions, account profile changes, or product recommendations. Required input: the internal order ID, such as ord_12345.",
+  "parameters_json_schema": {
+    "type": "object",
+    "properties": {
+      "order_id": {
+        "type": "string",
+        "description": "The internal order ID, for example ord_12345."
+      }
+    },
+    "required": ["order_id"],
+    "additionalProperties": false
+  },
+  "examples": [
+    {
+      "user_intent": "Where is my order ord_12345?",
+      "arguments": { "order_id": "ord_12345" }
+    }
+  ],
+  "side_effects": "none",
+  "read_only": true,
+  "idempotent": true,
+  "risk_level": "low",
+  "requires_confirmation": false,
+  "required_scopes": ["orders:read"],
+  "timeout_ms": 10000
+}
+

9.3. Regras para nomes

+
    +
  • Use snake_case com prefixo por namespace: orders_get_order_status, billing_list_invoices, vision_preprocess_document.
  • +
  • Verbo + objeto. Evite get_data, process, run, lookup genérico.
  • +
  • Em Anthropic, respeite ^[a-zA-Z0-9_-]{1,64}$.
  • +
+

9.4. Regras para descriptions

+

+ A description deve responder: o que a tool faz; quando usar; quando não usar; quais inputs são + necessários; o que retorna; caveats/limites; se causa side effect. Calibre o tamanho: +

+
+ + + + + + +
Tipo de toolTamanho alvoExemplo
Simples (read-only, escopo óbvio)25–60 palavrasBoa: Look up the current status of a customer order by order ID. Use this when the user asks where an order is, whether it shipped, whether it was delivered, or when it will arrive. Do not use this for refunds, billing disputes, product recommendations, or account profile updates. Required input: the internal order ID, such as ord_12345.

Ruim: Gets order info.
De negócio, com fronteiras de uso60–120 palavras
Crítica / com side effects100–180 palavras (ou mais se Anthropic for o provider primário e a seleção estiver ambígua)
+

9.5. Parameters / input_schema

+
    +
  • Topo sempre object: {"type":"object","properties":...}.
  • +
  • Use required para indispensáveis; com OpenAI strict, todos os campos devem estar em required.
  • +
  • Use additionalProperties:false onde suportado.
  • +
  • Use enum para valores fechados.
  • +
  • Descreva formato: ISO date, timezone, currency code, prefixo de ID, unidades, locale.
  • +
  • Evite nested objects profundos; se passar de 2 níveis, reavalie.
  • +
  • Não use query genérico quando puder estruturar campos.
  • +
+

9.6. Side effects, guardrails e erros estruturados

+

+ O provider não é a autoridade de segurança. O registry interno marca read_only, + idempotent, risk_level, requires_confirmation, + required_scopes, timeout_ms e audit_required; o executor + valida JSON Schema, ACL, tenant, idempotency key, rate limits e approval antes de executar + (fluxo HITL completo em Ferramentas, MCP & RAG). + Erros voltam estruturados: +

+
{
+  "ok": false,
+  "error_code": "ORDER_NOT_FOUND",
+  "message": "No order was found for order_id ord_12345.",
+  "retryable": false
+}
+ +
+ +
+

10. Bloco de system prompt — uso da python/code tool para visão

+

+ Este é o bloco a injetar quando a chamada inclui uma ferramenta de code/vision. Ele não é o + system prompt inteiro; é apenas a seção de uso da tool. Injete-o condicionalmente — junto com o + gating do §1 — para não gastar tokens em turnos sem code tool. +

+
## Uso da python/code tool em tarefas de visão
+
+Quando houver PDFs, imagens, screenshots, scans, gráficos, tabelas visuais, diagramas, plantas,
+assinaturas, carimbos ou texto pequeno, use primeiro a visão nativa do modelo.
+
+Use a python/code tool somente quando a visão nativa não for suficiente ou quando a tarefa exigir
+manipulação visual do arquivo.
+
+Use a python/code tool para:
+- renderizar páginas específicas de PDF como imagem;
+- dar zoom em regiões pequenas ou densas;
+- recortar tabela, gráfico, assinatura, carimbo, selo, QR code, diagrama ou região visual relevante;
+- girar páginas ou imagens inclinadas;
+- melhorar contraste, nitidez, escala ou legibilidade;
+- dividir uma página grande em regiões menores;
+- comparar regiões entre páginas ou imagens;
+- validar números em gráficos, tabelas ou documentos escaneados;
+- criar artefatos derivados úteis para inspeção visual.
+
+Não use a python/code tool quando:
+- a pergunta for simples e a resposta estiver claramente visível;
+- o usuário pedir apenas um resumo geral;
+- o conteúdo textual já estiver disponível de forma confiável no input;
+- a manipulação visual não mudar a qualidade da resposta.
+
+Quando usar a python/code tool:
+1. Identifique a página, imagem ou região relevante antes de processar.
+2. Renderize ou abra apenas os arquivos/páginas necessários.
+3. Faça o menor crop suficiente para resolver a dúvida.
+4. Aplique zoom, rotação ou contraste somente quando isso ajudar a leitura.
+5. Salve artefatos derivados apenas quando forem úteis para a análise.
+6. Baseie a resposta final na visão nativa e nos artefatos processados.
+7. Declare explicitamente qualquer incerteza quando o detalhe continuar ilegível.
+
+Controle de custo e latência:
+- não renderize o documento inteiro em alta resolução sem necessidade;
+- não use a python/code tool para todas as respostas por padrão;
+- prefira chamadas pontuais e direcionadas;
+- use a tool como lupa/processador visual, não como substituto da visão nativa.
+
+ + +
+

Parte 5 — Operação & frameworks

+

Quanto custa, como decidir por turno, como cada framework encaixa e o que testar antes de + produção.

+
+ +
+

11. Custos & gating

+
+ Escopo: esta seção cobre o custo das code tools (containers e taxas de + execução). O custo detalhado de tokens por modalidade/provider — incluindo tokenização de + imagens e PDFs — é dono do guia Token counting. +
+

11.1. OpenAI

+

+ Tokens do gpt-5.5 (Standard, por 1M tokens): contexto curto (<272K tokens de + input) — US$5,00 input, US$0,50 cached input, US$30,00 output; contexto longo (≥272K) — + US$10,00 input, US$1,00 cached input, US$45,00 output. Batch tem preços menores. +

+

+ Containers de Hosted Shell e Code Interpreter têm preço-base por sessão de 20 minutos, por tier + de memória: +

+
+ + + + + + + +
memory_limitBase (20 min)Equivalente por minuto (derivado)
1g (default)US$0,03≈ US$0,0015/min
4gUS$0,12≈ US$0,006/min
16gUS$0,48≈ US$0,024/min
64gUS$1,92≈ US$0,096/min
+
+ Mudança de billing (2026-06-02): desde 02/06/2026, containers são cobrados + por minuto de atividade, com mínimo de 5 minutos por container + — os valores da tabela são a taxa-base de 20 minutos usada como referência de proporção. Um + container 4g usado por 6 minutos custa ~US$0,036; usado por 3 minutos, cobra o + mínimo de 5 (~US$0,03). Decisão comercial deve reconsultar o + pricing oficial. +
+
+ + + + + + +
ToolCusto adicional do providerUso recomendado
Code InterpreterContainer por tier (por minuto, mín. 5) + tokensPython, arquivos, crop/zoom visual, plots, análise numérica.
Hosted ShellMesma tabela de containers + tokensCLI, repositórios, builds, multimedia, scripts de sistema.
Local ShellSem container OpenAI; o custo é a sua infraQuando precisa de controle total do ambiente e aceita executar shell_call.
+

11.2. Anthropic

+
    +
  • Code Execution é gratuito quando usado junto com web_search_20260209 ou web_fetch_20260209.
  • +
  • Sem essas tools: cobrança por tempo de execução com mínimo de 5 minutos; 1.550 horas grátis por organização/mês; US$0,05 por hora/container além disso.
  • +
  • Arquivos incluídos no request podem gerar cobrança mesmo se a tool não for invocada, porque são pré-carregados no container.
  • +
+

11.3. Gemini

+

+ Code Execution não tem cobrança adicional por habilitação: paga-se apenas tokens do modelo, + incluindo o código gerado e os resultados de execução, contabilizados como intermediate + tokens. Runtime máximo de 30s e até 5 retries valem como teto prático de custo por turno. + Detalhe de contagem em Token counting. +

+

11.4. Regra de gating

+
def classify_tool_needs(turn):
+    if turn.has_file_or_image and turn.user_asks_zoom_crop_rotate_validate_visual:
+        return {"needs_agentic_vision": True}
+    if turn.has_pdf_with_small_text_or_visual_tables and turn.requires_exact_numbers:
+        return {"needs_agentic_vision": True}
+    if turn.requires_repo_build_cli_or_system_tools:
+        return {"needs_shell": True}
+    if turn.requires_large_document_retrieval:
+        return {"needs_file_retrieval": True}
+    return {"needs_native_model_only": True}
+

+ O retorno alimenta o build_tools(route) do §2.2: cada flag liga exatamente uma + ferramenta, e o caso default não inclui nenhuma code tool — zero custo de container, zero + superfície de risco. +

+ +
+ +
+

12. Mapeamento por framework

+

+ As code tools deste guia aparecem em qualquer framework de orquestração — o que muda é onde o + gating e a persistência se encaixam. A regra é a mesma em todos: o framework é + runner/abstração; o runtime DB é a fonte autoritativa de histórico, tool calls, + artefatos e checkpoints. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FrameworkPapel no stackRegras essenciais (runtime-owned)Guia dedicado
OpenAI Agents SDKRunner com agents, tools, guardrails, HITL, tracing; provider-agnostic.Defina agents especialistas com instructions e tools, mas monte o input a partir do runtime DB; decida tools por turno via wrapper (Code Interpreter, Shell, File Search, functions, MCP); em agents-as-tools o manager é dono da resposta final — subagents são ferramentas, não donos do estado; para Shell/local tools, logue tool call/output/exit code/artefatos no DB; não use sessões automáticas como fonte autoritativa.Agents SDK · Orquestração
LangGraphGrafo com camada de persistência (checkpoints/threads), HITL, time travel.Implemente o checkpointer contra o banco do runtime, nunca contra armazenamento temporário/local sem governança; guarde o estado normalizado do grafo e também os envelopes provider-specific por chamada; nós separados para router/gating → tool selection → provider call → tool execution → artifact handling → finalization; checkpoint de grafo não é conversation provider-side — o checkpoint é seu.LangGraph · Orquestração
DeepAgentsHarness opinativo sobre LangGraph: durable execution, planning, subagents, filesystem.Substitua/integre o backend de filesystem com o artifact store do runtime; filesystem efêmero não vira fonte de verdade; code execution do harness segue as mesmas regras de sandbox/allowlist/timeout/persistência.Deep Agents
Google ADK v2+Agentes multi-linguagem, graph workflows, deploy em Cloud Run/GKE.Sessions/events do ADK são projeção/adapter local, não estado autoritativo; o runtime DB guarda a timeline canônica e o ADK recebe uma visão montada dela; deploy em Cloud Run/GKE pode ser o runtime de execução, mas artifact store/checkpoints/ACL continuam sob seu controle; SessionService é cache operacional — reidrate do DB canônico.Google ADK · Orquestração
+

+ Sketch dos nós LangGraph sob estado runtime-owned (expansão da linha da tabela — o mesmo + desenho vale como referência para os demais frameworks): +

+
# Sketch: LangGraph nodes under runtime-owned state
+START -> load_runtime_history -> route_capabilities -> select_tools -> call_provider
+call_provider -> execute_client_tools -> persist_tool_results -> call_provider
+call_provider -> finalize_response -> END
+
+# A implementacao do checkpointer escreve no runtime DB: threads, checkpoints, eventos, artefatos.
+
+ Versões de SDK/pacotes: este guia não mantém matriz de versões própria + — versões são perecíveis. Consulte os badges "Verificado em" dos guias de framework acima e + faça o CI revalidar antes de cada release (pip index versions ..., + npm view <pkg> version e smoke tests reais por provider). +
+
+ +
+

13. Smoke tests & checklist de produção

+

13.1. Smoke tests por provider

+
    +
  • OpenAI: store:false + histórico manual + resposta final coerente.
  • +
  • OpenAI: PDF como input_file + visão nativa + Code Interpreter acionado só quando o prompt pede crop/zoom.
  • +
  • OpenAI: Hosted Shell (container_auto e container_reference) e Local Shell em cenários separados, com shell_call_output persistido.
  • +
  • OpenAI: Tool Search hosted e client-executed com function deferida, tool_search_call/tool_search_output e function call final.
  • +
  • Gemini Interactions: store:false sem previous_interaction_id; steps persistidos.
  • +
  • Gemini Interactions: Code Execution com imagem em gemini-3.5-flash; verificar retorno de code/result/text. Confirmar o backend de auth: este teste passa na Developer API e pode falhar em Vertex — se o alvo for Vertex, validar generateContent + code_execution como caminho alternativo (§3).
  • +
  • Gemini Interactions: tool combination stateless preservando id/signature.
  • +
  • Anthropic: custom tool com input_schema + strict + tool_result.
  • +
  • Anthropic: Code Execution com arquivo/imagem e artefatos persistidos no runtime — testar code_execution_20250825 e, em Opus/Sonnet 4.5+, code_execution_20260120 com REPL persistente entre execuções.
  • +
  • Anthropic: Tool Search BM25 e Regex com deferred tools e ≥1 tool não-deferida.
  • +
  • Fallback local: vision_preprocess_document em Docker sem rede, com quotas, timeouts e artifact IDs.
  • +
+

13.2. Checklist de produção

+
    +
  • ☐ Runtime DB é fonte autoritativa de histórico/envelope/tool calls/tool results.
  • +
  • ☐ Nenhum caminho depende de previous_response_id, previous_interaction_id ou conversations/sessions provider-side.
  • +
  • ☐ Gating decide as tools antes da request; Tool Search não é usado como liga/desliga de code tools.
  • +
  • ☐ Todos os schemas têm descriptions suficientes, enums, required e validação no runtime.
  • +
  • ☐ Tool executors têm ACL, tenant isolation, idempotency, approval e audit logs.
  • +
  • ☐ Artifact store tem checksums, validação de MIME, lifecycle policy e redaction.
  • +
  • ☐ Worker local tem no-new-privileges, sem rede, quotas, tmpfs e allowlist.
  • +
  • ☐ Custos de container monitorados por turno (billing por minuto, mínimos de 5 min na OpenAI e na Anthropic sem web tools).
  • +
  • ☐ CI revalida versões de SDK (PyPI/npm) e executa smoke tests reais por provider.
  • +
  • ☐ Preços são snapshot de 2026-06-10; decisão comercial reconsulta o pricing oficial.
  • +
+
+ + +
+

Fontes oficiais & verificação

+

+ Fatos perecíveis (parâmetros de tools, versões de ferramentas, limites, preços, modelos) foram + conferidos contra a documentação oficial em 2026-06-10. Padrões de registry, + fallback e schemas são recomendações de engenharia derivadas dos contratos oficiais. + O caveat de superfície Developer API vs Vertex AI (§1, §3, §4) e as versões de SDK + foram reconferidos em 2026-06-19. +

+

OpenAI

+ +

Google Gemini

+
+ + + + + + + + + + +
TemaFonte oficial
Interactions API — overviewai.google.dev/gemini-api/docs/interactions/interactions-overview
Interactions — Code Execution (com imagens)ai.google.dev/gemini-api/docs/interactions/code-execution
Interactions — Tool combinationai.google.dev/gemini-api/docs/interactions/tool-combination
Code Execution (limites, libs, billing)ai.google.dev/gemini-api/docs/code-execution
Function calling (best practices, 10–20 tools)ai.google.dev/gemini-api/docs/function-calling
Librariesai.google.dev/gemini-api/docs/libraries
Google ADK · PyPI — google-genai / google-adkadk.dev · pypi.org/project/google-genai · pypi.org/project/google-adk
+

Anthropic

+ +

Frameworks

+ +

+ Legenda dos selos: Verificado confirmado na doc oficial · + Novo recurso recente · + UNVERIFIED não confirmado dentro do orçamento de verificação · + N/D não documentado. +

+

Notas de verificação desta edição

+
    +
  • Corrigido Billing de containers OpenAI: a edição anterior do material-fonte descrevia cobrança "por sessão de 20 minutos"; desde 2026-06-02 a cobrança é por minuto com mínimo de 5 minutos — os valores por tier viram taxa-base proporcional (§11.1).
  • +
  • Atualizado Anthropic Code Execution: incluída a versão code_execution_20260120 (REPL persistence + programmatic tool calling; Opus 4.5+/Sonnet 4.5+, não Haiku 4.5), além da code_execution_20250825; GA sem beta header (§4).
  • +
  • Atualizado Modelos: claude-fable-5 (GA 2026-06-09) registrado como o mais novo da Anthropic; exemplos mantêm claude-opus-4-8 (ativo/excelente). Exemplos Gemini usam gemini-3.5-flash; Code Execution with images é documentado em Gemini 3 Flash e herdado pela linha 3.5 GA (§3–§4).
  • +
  • Removido Referência local: a citação a um arquivo local anexado em conversa, presente no material-fonte, foi removida — todas as fontes desta página são URLs oficiais públicas.
  • +
  • Delegado Matriz de versões: snapshots de versão de SDK saíram deste guia; consulte os badges dos guias de framework e a revalidação no CI (§12).
  • +
  • UNVERIFIED Shape exato da configuração local do Shell: a doc oficial documenta o loop shell_call/shell_call_output e o shell executor do Agents SDK; o literal de environment para modo local não foi reproduzido aqui — consulte a página oficial do Shell antes de implementar.
  • +
  • Novo Vertex AI vs Developer API (code execution + Interactions): a Interactions API existe na Developer API (AI Studio, generativelanguage.googleapis.com, status Beta) e na Vertex / Gemini Enterprise Agent Platform (aiplatform.googleapis.com, status experimental). code_execution dentro de Interactions é documentado/exemplificado só na Developer API; na Vertex a execução de código é documentada via generateContent. Observado em teste: code_execution via Interactions falhou em Vertex e funcionou na Developer API (não é limitação oficial). Caveats adicionados em §1, §3 e §4 (verificado em 2026-06-19, fontes oficiais Google).
  • +
  • Atualizado SDKs (varredura 2026-06-19): o tool code_execution_20260120 da Anthropic ganhou suporte tipado no SDK (anthropic 0.110.0 / @anthropic-ai/sdk 0.105.0) — a capacidade já estava documentada (§4); google-genai 2.9.0 reimplementou a Interactions internamente mantendo a API pública compatível. Sem mudança de comportamento nos exemplos.
  • +
+
+ +
+
+ +
+
+
+
Agentic vision & code tools Code Interpreter · Code Execution · Shell · Tool Search
+

+ Guia transversal de code tools construído a partir da documentação oficial pública de OpenAI, + Google Gemini e Anthropic, verificada em 2026-06-10. Preços, versões de tools e + modelos são perecíveis — reconsulte as fontes oficiais antes de + decisões de produção. +

+
+
+
Crédito de produção
+
Gerado por subagente Claude Fable 5
+
revisão e montagem pelo orquestrador · 2026-06-10
+
+ Transversal + OpenAI · Gemini · Anthropic +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_arquitetura_orquestracao.html b/references/agents_tools_best_guides/guia_arquitetura_orquestracao.html new file mode 100644 index 0000000..8eee1c1 --- /dev/null +++ b/references/agents_tools_best_guides/guia_arquitetura_orquestracao.html @@ -0,0 +1,1043 @@ + + + + + +Arquitetura & Orquestração de Agentes — Núcleo agnóstico + + + + + + + + +
+
+
Arquitetura & Orquestração Núcleo agnóstico de agentes
+
+ Verificado em 2026-06-11 + Núcleo · agnóstico de provider + Conceitual + referência + +
+
+
+ +
+ + +
+ +
+

Arquitetura & Orquestração de Agentes

+

+ O capítulo de fundação do núcleo agnóstico: como projetar o runtime que decide, + a cada ciclo, qual contexto projetar, qual modelo chamar, quais capabilities expor, como validar + chamadas, como reduzir resultados e como registrar evidência. Vale para qualquer provider + (OpenAI, Anthropic, Google) e qualquer framework de agentes. Os outros capítulos do núcleo — + estado, ferramentas, providers e operação — usam o vocabulário definido aqui. +

+
+ Núcleo · agnóstico de provider + Conceitual + referência + SOTA · verificado 2026-06-10 +
+
+ +
+

Sobre este guia

+

+ Este é um guia para IA e humanos: combina decisões de arquitetura ("quando usar + o quê") com contratos tipados prontos para copiar (capability registry, active plan, delegation + packet, skeleton de loop). Toda a prosa é em PT-BR; nomes de classes, parâmetros e código + permanecem em inglês, como nas APIs oficiais. +

+
+ Regra de desenho que atravessa todo o núcleo: o modelo pode planejar e + solicitar ações, mas o runtime governa autorização, execução, limites, persistência, + redaction e replay. O payload enviado ao provider é sempre uma projeção + reconstruída do seu estado durável — nunca a fonte única da verdade. +
+
+ Princípio agnóstico: nada neste capítulo depende de um provider específico. + As decisões valem se você orquestra com a Responses API da OpenAI, a Messages API da Anthropic, + o google-genai ou um framework como OpenAI Agents SDK, LangGraph ou Google ADK. + A camada de adapter (capítulo de providers) traduz estes contratos para cada API. +
+
+ O que este capítulo não faz: ele não reescreve a referência de cada framework + nem repete contagem de tokens, compaction detalhada ou parâmetros de provider. Quando o assunto + já tem guia dedicado, há um cross-link. Veja o mapa do núcleo. +
+
+ +
+

Fontes & verificação

+

+ As afirmações perecíveis (parâmetros de API, versões de spec, comportamento de SDK) foram + conferidas contra a documentação oficial em 2026-06-10 e consolidadas na folha + de fatos SOTA do projeto. Os contratos de arquitetura (registry, active plan, ledger) são + recomendações de engenharia derivadas dos padrões oficiais de cada provider. +

+
+ + + + + + + + + +
TemaFonte oficial
Orquestração multi-agente (LLM-orchestrated vs code-orchestrated)openai.github.io/openai-agents-python/multi_agent
OpenAI Agents SDK (primitivos: agents, handoffs, tools, guardrails)openai.github.io/openai-agents-python
OpenAI Responses API (loop próprio, tools, estado)developers.openai.com/api/docs/guides/tools
Model Context Protocol — spec 2025-11-25modelcontextprotocol.io/specification/2025-11-25
Multi-agente em LangGraph (supervisor/swarm)docs.langchain.com/oss/python/langgraph/multi-agent
Multi-agente em Google ADKgoogle.github.io/adk-docs/agents/multi-agents
+

+ Legenda dos selos: Verificado confirmado na doc oficial · + Novo recurso recente · + Experimental marcado experimental · + N/D não documentado. +

+
+ +
+

Mapa do núcleo — onde cada assunto mora

+

+ Este capítulo é a porta de entrada. Quando precisar de profundidade em um assunto adjacente, + siga o cross-link em vez de procurar duplicação aqui. +

+
+ + + + + + + + + + + +
Você procura…Vá para
Ledger canônico, compaction, reasoning/thinking carriers, budgets de contextoNúcleo · Estado, contexto & memória
Tool result envelopes, MCP como fronteira, RAG como capability, multimodalNúcleo · Ferramentas, MCP & RAG
Parâmetros de provider, adapters, provider-switching, Pydantic AINúcleo · Providers & adapters
Guardrails, tracing/cost ledger, evals, runbooks, threat modelNúcleo · Operação, segurança & evals
Como implementar este blueprint no OpenAI Agents SDKFramework · Orquestração no Agents SDK
Como implementar este blueprint em LangGraphFramework · Orquestração em LangGraph
Como implementar este blueprint no Google ADK (1.x/2.x)Framework · Orquestração no Google ADK
Autoria de Agent Skills (SKILL.md, ativação, progressive disclosure)Guia de Skills
+
+ + +
+

Parte 1 — Fundamentos

+

O vocabulário e os mapas de decisão que sustentam todo o restante: o que é um sistema agentic, + quais são as peças que você combina e como escolher entre elas.

+
+ +
+

1. Escopo universal de orquestração

+

+ Um sistema agentic universal não é "um chatbot com ferramentas". É um runtime + que decide, em cada ciclo, qual contexto projetar, qual modelo chamar, quais capabilities expor, + como validar chamadas, como reduzir resultados e como registrar evidência. A unidade de projeto + não é a mensagem isolada; é o turn bundle: instruções, histórico projetado, + assets, tools, planos ativos, políticas, budgets, traces e estado de execução. +

+
+ Decisão do modelo × decisão do código × política da organização. Um runtime + SOTA separa explicitamente os três. O modelo decide o conteúdo da resposta e quais ações pedir; + o código decide se, quando e como executar; a política define retenção, aprovação, quotas e + fronteiras. Misturar os três no prompt é a origem da maioria das falhas de segurança e custo. +
+

+ O OpenAI Agents SDK documenta dois estilos centrais de orquestração: deixar o LLM orquestrar com + tools e handoffs, ou orquestrar por código para mais determinismo. A arquitetura universal deve + permitir misturar os dois, com fronteiras explícitas — e é exatamente isso que os + primitivos abaixo viabilizam. +

+ +
+ +
+

2. Primitivos canônicos

+

+ Sete primitivos cobrem praticamente toda topologia agentic. Conhecê-los explicitamente evita o + erro de transformar todo problema em "um agente autônomo". +

+
+ + + + + + + + + + +
PrimitivoDefinição universalQuando usarRisco de mau uso
AgentEntidade com instructions, modelo, tools, guardrails e política de execução.Tarefas com objetivo claro, contexto controlado e capacidade de invocar tools.Tornar tudo um agente autônomo sem budget, avaliação ou fronteira.
Workflow determinísticoGrafo/código que chama modelos em pontos específicos.Processos com etapas estáveis, compliance forte ou baixa tolerância a variação.Forçar fluxo rígido quando o problema exige exploração/adaptação.
Agent-as-toolSubagente chamado como uma tool; o parent mantém controle e recebe output reduzido.Especialização delimitada: análise de arquivo, pesquisa, classificação, normalização.Permitir que o subagente despeje histórico bruto no parent.
HandoffTransferência de controle para outro agente ativo.Mudança real de ownership: atendimento, triagem, especialista humano/IA.Usar handoff quando bastava uma chamada subordinada.
MCP tool/resource/promptCapability publicada em protocolo padronizado, acessada por host/client.Integrar sistemas, dados e ferramentas reusáveis com schema e segurança.Tratar MCP como túnel irrestrito para ações perigosas.
Provider built-inTool executada no lado do provider (web/file/code conforme a API).Quando a ferramenta oficial reduz integração e oferece rastreabilidade adequada.Presumir retenção, ZDR, paralelismo e billing sem validar a doc.
Function toolSchema exposto ao modelo, execução feita pelo cliente/orquestrador.Integrações internas, chamadas a APIs próprias, validação local.Schemas vagos, side effects sem aprovação e tool result gigante.
+

+ O OpenAI Agents SDK cobre agents, handoffs, agents-as-tools, guardrails, sessions, tracing e MCP; + a Responses API subjacente é apropriada quando o runtime precisa possuir o loop e o + dispatch. A escolha entre os dois é tratada no + capítulo de providers e nos guias de framework. +

+ +
+ +
+

3. Arquitetura de referência

+

+ A figura abaixo separa as quatro camadas que nunca devem ser confundidas. Trocar de provider, + reduzir contexto, auditar tools e manter invariantes só é possível quando o estado real vive no + runtime, e o payload do provider é tratado como projeção. +

+
+ + Arquitetura de referência em camadas + Aplicação no topo; orquestrador agentic abaixo; e três pilares na base — ledger canônico, capability registry e provider adapters. + + + + + + Aplicação / Produto / Canal + autenticação · tenancy · UX · políticas e dados do usuário + + + Orquestrador agentic + active plan · budget · model router · guardrails · tracing + + + Ledger canônico + assets · compaction + provenance · replay + + + Capability registry + tools · MCP · RAG + functions · agents · approvals + + + Provider adapters + OpenAI · Anthropic · Google + Responses · Messages · Gemini + + + + + + + estado durável + capabilities tipadas + projeção / chamadas de API + +
+ As quatro camadas. O orquestrador lê e escreve no ledger canônico, expõe um subconjunto do + capability registry por turno e fala com os providers por meio de adapters que projetam o + estado durável. Nenhum segredo, token de tenant ou autorização trafega "pelo prompt". +
+
+
+ Detalhe de cada camada: o ledger canônico tem capítulo próprio + (Estado, contexto & memória); o capability + registry e os adapters também (Ferramentas, MCP & RAG + e Providers & adapters). Aqui interessa apenas a + relação entre elas. +
+
+ +
+

4. Matriz de escolha: agent, workflow, agent-as-tool ou handoff

+

+ A primeira decisão de arquitetura é a topologia. Use a situação concreta — não a preferência por + "ser agêntico" — para escolher. +

+
+ + + + + + + + + + +
SituaçãoEscolha recomendadaCritério operacional
Etapas conhecidas, dados sensíveis, pouca ambiguidadeWorkflow determinístico com chamadas LLM pontuaisMinimiza variabilidade e simplifica auditoria.
Tarefa exploratória, baixo risco e tools segurasAgent com loop controladoLimitar max turns, allowed tools, budgets e final reserve.
Especialista precisa analisar um subproblema e devolver sínteseAgent-as-toolO parent mantém a conversa; o child recebe pacote mínimo e retorna envelope reduzido.
O usuário deve passar para outro especialista/fluxo ativoHandoffA nova entidade assume o controle com contexto mínimo e consentimento quando necessário.
Integração reusável por muitos hostsMCP server/tool/resourceSchemas, auth, rate limits e escopo explicitados fora do prompt.
Consulta de conhecimento com provenanceRAG como capability/toolA tool retorna trechos, citações, score, freshness e limites de confiança.
Operação com side effect financeiro/legal/externoTool com HITL ou workflow aprovadoO modelo nunca autoriza sozinho; o runtime valida e pede aprovação.
+
+ Agent-as-tool ≠ handoff. A confusão entre os dois é tão comum que tem seção + própria (§8). Em resumo: agent-as-tool é delegação + subordinada; handoff é transferência de ownership. +
+
+ + +
+

Parte 2 — Contratos do runtime

+

Os artefatos tipados que tornam a orquestração auditável e portável: o registry de capabilities, + o estado de plano, o loop e os modos de delegação.

+
+ +
+

5. Contrato de capability registry

+

+ Toda ferramenta, subagente, handoff ou endpoint MCP deve ser registrado como uma + capability com metadados suficientes para roteamento, segurança e avaliação. O + registro não deve depender de nomes naturais no prompt — depende de um contrato. +

+
{
+  "capability_id": "retrieve_domain_evidence.v1",
+  "kind": "mcp_tool | function_tool | agent_as_tool | handoff | provider_builtin",
+  "description_for_model": "Recupera evidências com proveniência e limites de confiança.",
+  "input_schema":  { "type": "object", "properties": {} },
+  "output_schema": { "type": "object", "required": ["summary", "citations", "confidence"] },
+  "side_effect_level": "none | read | write_low | write_high",
+  "auth_scope": "derived_from_runtime_not_model",
+  "tenant_boundary": "required",
+  "max_input_tokens": 2000,
+  "max_output_tokens": 1200,
+  "timeout_ms": 15000,
+  "approval_policy": "auto | human_required | forbidden",
+  "observability": ["trace_span", "cost", "source_hashes", "tool_args_redacted"]
+}
+

+ O mesmo contrato suporta ferramentas locais, MCP, RAG, agentes especializados e built-ins; o + adapter converte para o formato aceito por cada provider. As regras de design do schema de tool + (nomes, descrições, caps de output) e o envelope de resultado estão no + capítulo de ferramentas. +

+
+ Por que auth_scope deriva do runtime: se o escopo de autorização + viesse do modelo, um prompt injection em um documento poderia escalar privilégio. O runtime + resolve tenant e scope a partir de claims autenticados, nunca a partir do texto. +
+
+ +
+

6. Microcontextos & active plan

+

+ Dois padrões evitam que o contexto do parent vire um depósito e que o raciocínio fique implícito: +

+
+ + + + + + +
PadrãoO que éPor que importa
MicrocontextoSubexecução isolada com input mínimo, policy, budget, tools permitidas e envelope de retorno.Evita que subagentes herdem todo o histórico — só entram fatos necessários, assets autorizados e schema de saída.
Active planEstado explícito do que está em andamento: objetivo, etapas, pendências, constraints, decisões e condição de finalização.Substitui raciocínio implícito por estado auditável, com budgets e gates.
Delegation packetPacote tipado para agent-as-tool/handoff/MCP: tarefa, contexto reduzido, constraints, capabilities, output contract e trace do parent.Torna a delegação verificável e impede vazamento de contexto.
+

O active plan vive no ledger e é reprojetado a cada turno:

+
{
+  "active_plan": {
+    "goal": "produzir resposta verificável",
+    "stage": "collect_evidence | analyze | synthesize | finalize",
+    "open_questions": [],
+    "constraints": ["não vazar dados sensíveis", "citar fontes"],
+    "budgets": { "turns_remaining": 3, "tool_calls_remaining": 8, "tokens_remaining": 24000 },
+    "finalization_policy": { "reserve_tokens": 4000, "reserve_seconds": 20 }
+  }
+}
+
+ Budgets aparecem aqui e no ledger. A fórmula de orçamento de contexto (entrada + projetada + reasoning + saída final + margem) e a contagem de tokens em si pertencem ao + capítulo de estado e ao + guia de token counting. Aqui o budget é apenas uma propriedade + do plano que o loop respeita. +
+
+ +
+

7. Skeleton de orquestrador

+

+ O loop é intencionalmente provider-neutral: registrar, validar, executar, + reduzir e reprojetar. Um framework de agentes pode gerenciar boa parte deste loop; quando o + projeto exige controle fino, implemente-o sobre a API direta do provider e adapters próprios. +

+
from dataclasses import dataclass
+from typing import Any
+
+@dataclass
+class TurnPolicy:
+    allowed_capabilities: list[str]
+    max_agent_turns: int
+    max_tool_calls: int
+    final_reserve_tokens: int
+    require_human_for: list[str]
+
+async def run_agent_turn(user_input: str, ledger, policy: TurnPolicy) -> dict[str, Any]:
+    ledger.record_user_input(user_input)
+    projected = ledger.project_for_provider(
+        provider="openai_responses",          # ou anthropic_messages, gemini, ...
+        allowed_capabilities=policy.allowed_capabilities,
+        reserve_tokens=policy.final_reserve_tokens,
+    )
+    for _step in range(policy.max_agent_turns):
+        response = await call_model(projected)
+        ledger.ingest_provider_response(response)
+        calls = ledger.extract_pending_tool_calls(limit=policy.max_tool_calls)
+        if not calls:
+            return ledger.final_answer()
+        safe_calls = authorize_tool_calls(calls, policy)   # runtime decide, não o modelo
+        results = await execute_capabilities(safe_calls)
+        ledger.record_tool_results(results)                # reduzir + provenance antes de registrar
+        projected = ledger.project_for_provider(provider="openai_responses")
+    return ledger.force_wind_down_summary()                # respeita o final reserve
+
+ Mesmo quando o framework gerencia o loop, mantenha registro externo de traces, + usage, tool results e decisões críticas se o sistema precisa ser auditável. O mapeamento deste + skeleton para cada framework está nos guias de + Agents SDK, + LangGraph e + Google ADK. +
+
+ +
+

8. Handoff versus agent-as-tool em detalhe

+

+ Agent-as-tool é delegação subordinada: o parent formula a tarefa, envia um + pacote mínimo e consome o retorno. Handoff é transferência de ownership: o + agente-alvo vira a entidade ativa e deve receber contexto suficiente para continuar. Confundir + os dois aumenta o risco de vazamento de contexto e de loops. +

+
+ + + + + + + + +
DimensãoAgent-as-toolHandoff
Controle da conversaPermanece com o parent.Passa para o target.
Contexto enviadoMínimo e específico da tarefa.Resumo de continuidade + consentimentos/políticas.
Output esperadoEnvelope tipado e reduzido.Nova interação ou resolução no fluxo alvo.
Uso típicoPesquisa, análise, extração, validação.Especialista ativo, humano, atendimento, workflow setorial.
Risco principalO child retornar demais.Transferir dados/autoridade demais.
+
+ Implementações concretas: handoffs e agents-as-tools no OpenAI Agents SDK + (incluindo filtros de input e collapse de transcript) estão no + guia do Agents SDK; o equivalente multi-agente + em LangGraph (supervisor/swarm) e no Google ADK (coordenador + subagentes) está nos respectivos + guias de framework e nos guias dedicados LangGraph e + Google ADK. +
+
+ +
+

9. Skill packs e modos de injeção

+

+ Skills devem ser versionadas, testadas e injetadas no menor escopo possível. O + erro mais comum é carregar tudo sempre — isso degrada o contexto, aumenta o custo e cria + conflitos de instrução. Os modos de injeção são uma decisão de arquitetura; a autoria + das skills (formato SKILL.md, progressive disclosure, ativação por description) tem + guia próprio. +

+
+ + + + + + + + +
ModoDescriçãoQuando usar
catalog_onlyO modelo vê apenas nomes/descrições de skills.Muitos recursos disponíveis, mas poucos necessários por turno.
hot_dynamicO runtime injeta o corpo completo da skill só quando relevante.Especialização contextual sem poluir o prompt base.
pinned_systemSkill crítica fica sempre nas instruções.Regras de segurança ou formato que nunca podem faltar.
child_frozen_packO subagente recebe um pacote fixo e isolado.Especialista repetível com contrato estável.
specialist_catalogO parent conhece especialistas e delega via agent-as-tool/handoff.Arquiteturas multiagente com fronteiras claras.
+
+ Cross-link: a autoria de skills portáveis, os contratos de ativação, o orçamento + de skills e a eviction sem perder autoridade estão no Guia de Skills. + A teoria de budget/compaction que sustenta o hot_dynamic está no + capítulo de estado e no + guia de contexto & compactação. +
+
+ + +
+

Parte 3 — Operação & escala

+

Como evitar as armadilhas conhecidas, fazer o sistema crescer sem virar cosmético, rotear + modelos e modelar execuções longas — culminando no blueprint SOTA.

+
+ +
+

10. Antipadrões arquiteturais

+

Cada antipadrão abaixo corresponde a um invariante violado em algum lugar do núcleo:

+
    +
  • ☐ Contexto bruto sem fronteira: anexar toda saída de tool/RAG/subagente no histórico do parent.
  • +
  • ☐ Provider como banco de estado: depender de previous_response_id, cache ou session como único histórico durável.
  • +
  • ☐ Tool schema permissivo: aceitar argumentos arbitrários ou filtros definidos pelo modelo sem sanitização.
  • +
  • ☐ Subagente sem envelope: permitir que o child retorne narrativa longa em vez de output tipado e reduzido.
  • +
  • ☐ Handoff opaco: transferir controle sem registrar por quê, para quem, com qual contexto e qual consentimento.
  • +
  • ☐ Paralelismo sem fase: misturar built-ins, funções externas, side effects e síntese no mesmo boundary.
  • +
  • ☐ Sem wind-down: continuar abrindo tools quando o orçamento da resposta final já acabou.
  • +
+
+ O antipadrão mais caro costuma ser "provider como banco de estado": quando um + incidente exige replay e o histórico só existia no lado do provider (sujeito a retenção, ZDR e + expiração de cache), a auditoria fica impossível. O ledger canônico existe para evitar isso — + ver Estado, contexto & memória. +
+
+ +
+

11. Padrões de runtime por maturidade

+

+ O salto de maturidade não deve ser cosmético: cada fase adiciona uma peça verificável + — política, schema, trace, eval ou manifest. +

+
+ + + + + + + +
MaturidadeArquitetura aceitávelCritério para evoluir
Protótipo controladoUm agente com poucas tools read-only, logging básico e output schema simples.Quando houver side effects, dados sensíveis, múltiplos providers ou necessidade de replay.
MVP auditávelFramework de agentes + ledger externo + capability registry + guardrails de entrada/saída.Quando subagentes, RAG, anexos e custos começarem a competir por contexto.
Produção reguladaLedger canônico, policy-as-code, ZDR/retention, evals, traces, approvals e compaction versionada.Quando volume ou criticidade pedirem roteamento multi-provider e runbooks.
Plataforma corporativaMúltiplos agentes/skills/MCP servers, active plans, provider adapters, eval harness e observabilidade central.Quando times diferentes criarem capabilities e precisarem de governança comum.
+
+ Critério de maturidade prático: se a equipe não consegue desenhar o fluxo com + entradas, saídas, estado, tools, budgets, aprovações e pontos de replay, o sistema ainda está em + protótipo — mesmo que responda bem em demonstrações. +
+
+ +
+

12. Model router e seleção de agente

+

+ O roteador deve considerar capacidade, latência, custo, janela de contexto, política de dados, + suporte a tools, suporte multimodal, structured outputs, reasoning/thinking e histórico + necessário. Não escolha o modelo apenas por "qualidade média". +

+
+ + + + + + + + + +
CritérioSinal de roteamentoExemplo de decisão
Context windowInput projetado + output + margem excede o modelo atual.Compactar ou trocar para um modelo com janela maior.
Tool semanticsO fluxo exige built-in específica ou MCP remoto.Usar o provider/SDK que suporte a capability com governança adequada.
Reasoning budgetA tarefa requer deliberação profunda ou matemática/código.Aumentar o esforço/budget de reasoning ou delegar para um especialista.
Data policyDados sensíveis não podem ser retidos pelo provider.Usar store=false quando aplicável, redaction ou rota autorizada.
Structured outputSchema crítico precisa de alta aderência.Usar structured outputs/validação e retry controlado.
Latency/costFan-out custoso com baixo valor marginal.Reduzir tools, limitar subagentes ou usar um modelo menor para triagem.
+
+ IDs de modelo são perecíveis. Este capítulo deliberadamente não fixa nomes de + modelo. Para o catálogo atual e os controles de reasoning/thinking por modelo, consulte os guias + dedicados: OpenAI (§ Seleção de modelo), + Claude API, + Gemini Interactions API e a matriz cruzada em + Paralelismo & tools. +
+
+ +
+

13. Long-running jobs e deep research

+

+ Execuções longas devem ser modeladas como jobs, não como uma conversa gigante. + Um job tem estado persistido, etapas, checkpoints, retries, evidência acumulada, budgets e + condição de encerramento. +

+
+ + Ciclo de vida de um long-running job + Sequência: criado, planning, coleta de evidência, revisão intermediária, síntese, validação, entrega final; com resume, checkpoints, provenance, budget gates, citations e eval gates por baixo. + + + + created + planning + evidence + review + synthesis + validation + + + + + + + resume / checkpoints + provenance + budget gates + citations + eval gates + final delivery + + +
Um job longo é uma máquina de estados persistida, não uma conversa. Cada transição + tem checkpoint, provenance e gate.
+
+
    +
  • ☑ Persistir o estado do job fora do provider.
  • +
  • ☑ Registrar checkpoints e permitir replay parcial.
  • +
  • ☑ Definir budget por etapa, não apenas global.
  • +
  • ☑ Reduzir evidências antes de cada síntese intermediária.
  • +
  • ☑ Encerrar com declaração de cobertura, lacunas e fontes.
  • +
+
+ Implementações de deep research e background jobs (com webhooks, retomada e + modo assíncrono) estão nos guias de provider/framework: + Deep Agents (receita de deep research), + Gemini Interactions API (Deep Research, background & webhooks) + e OpenAI (background & webhooks). +
+
+ +
+

14. Blueprint SOTA de orquestração

+

+ Um runtime de agentes moderno separa claramente o que é decisão do modelo, decisão do código e + política organizacional. As seis camadas abaixo são responsabilidades, não necessariamente + processos separados — em um sistema pequeno várias podem coexistir no mesmo código, desde que a + fronteira lógica seja clara. +

+
+ + + + + + + + + +
CamadaResponsabilidadeControle SOTAFalha típica evitada
Intent routerClassificar pedido, risco, dados e rota.Structured output + schema versionado.Delegar para o agente errado ou expor tool indevida.
PlannerConstruir o plano ativo e decompor subtarefas.Plano explícito com budgets e stop conditions.Loop indefinido, fan-out excessivo e perda de objetivo.
ManagerManter a conversa e consolidar especialistas.Agents-as-tools para subtarefas bounded.Vários agentes disputando a resposta final.
SpecialistExecutar competência estreita com contexto mínimo.Microcontexto, capability registry e output contract.Subagente herdando o histórico inteiro ou vazando dados.
Policy engineAplicar retenção, side effects, aprovação e quotas.Policy-as-code fora do prompt.Modelo tomando decisão de compliance sozinho.
ObserverRegistrar trace, custos, tool calls, decisões e erros.Spans por model/tool/guardrail/handoff.Incidente sem replay auditável.
+
pedido → classificação → plano ativo → exposição mínima de capabilities → execução
+       → validação de tool/result → síntese → checagem de saída → trace/replay
+
+ Onde cada camada é detalhada: policy engine e observer no + capítulo de operação; specialist/manager nos + guias de framework; intent router e structured output no + capítulo de providers. +
+
+ + +
+

Checklist de aceitação arquitetural

+

Use como gate antes de promover qualquer arquitetura de agentes para produção:

+
    +
  • ☐ Existe um ledger canônico separado dos payloads de provider.
  • +
  • ☐ Cada capability tem schema, side-effect level, auth scope, budget e policy de aprovação.
  • +
  • ☐ Agent-as-tool e handoff usam delegation packet e envelope de retorno.
  • +
  • ☐ O sistema separa as fases de recuperação, ação, análise e síntese.
  • +
  • ☐ O modelo nunca recebe segredos, tokens de tenant ou autorização "por prompt".
  • +
  • ☐ Há limites explícitos para turns, tool calls, fan-out, tempo, tokens, output e custo.
  • +
  • ☐ Traces e usage ledger permitem replay ou auditoria sem depender do provider.
  • +
+
+ +
+

Notas de verificação

+
    +
  • Resolvido Spec MCP = 2025-11-25. Versão alvo confirmada na folha de fatos SOTA (2026-05-25) e na documentação oficial do protocolo. Guias mais antigos do pacote podem citar revisões anteriores (2024-11-05 / 2025-03-26); a versão canônica do super-guia é 2025-11-25. Re-verificado em 2026-06-10: a revisão 2026-07-28 foi anunciada (ainda em draft; em evolução até a publicação) com breaking changes — protocolo stateless sem handshake initialize/Mcp-Session-Id, novo server/discover, Tasks como extensão; 2025-11-25 segue sendo a versão alvo até a nova revisão entrar em vigor.
  • +
  • Resolvido Agents SDK ↔ Responses API. O OpenAI Agents SDK usa a Responses API por baixo para modelos OpenAI; este capítulo trata o SDK como uma base de orquestração possível, não como a única.
  • +
  • Resolvido Sem IDs de modelo fixos. Nomes de modelo são perecíveis e ficam concentrados nos guias de provider e na folha de fatos SOTA; este capítulo permanece agnóstico (model="...").
  • +
  • Resolvido Cross-links robustos. Os links apontam para o arquivo do guia e nomeiam a seção em prosa; âncoras profundas só são usadas onde o guia-alvo expõe id estável.
  • +
+
+ +
+
+ +
+
+
+
Arquitetura & Orquestração Núcleo agnóstico de agentes
+

+ Capítulo de fundação do núcleo agnóstico, construído a partir da documentação oficial pública em + 2026-06-10. Para fatos perecíveis (modelos, versões, parâmetros), consulte + sempre os guias de provider e as + fontes oficiais. +

+
+
+
Crédito de produção
+
Gerado por subagentes Claude Opus 4.7 (xhigh)
+
revisão e montagem pelo orquestrador · 2026-05-25
+
+ Núcleo · agnóstico de provider + Conceitual + referência +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_claude_api.html b/references/agents_tools_best_guides/guia_claude_api.html new file mode 100644 index 0000000..544bed8 --- /dev/null +++ b/references/agents_tools_best_guides/guia_claude_api.html @@ -0,0 +1,6486 @@ + + + + + +Guia Claude API (Anthropic) — Referência completa · Opus 4.8 · Sonnet 4.6 · Haiku 4.5 + + + + + + + + +
+
+
Guia Claude API Anthropic · PT-BR · Referência completa
+
+ Verificado em 2026-06-25 + anthropic · @anthropic-ai/sdk + Opus 4.8 · Sonnet 4.6 · Haiku 4.5 + +
+
+
+ +
+ + +
+ +
+

Guia Claude API (Anthropic) — Referência completa

+

+ Documentação técnica exaustiva, em português brasileiro, da API da Anthropic (Claude), + focada nos modelos gerais mais recentes — Claude Opus 4.8, Claude Sonnet 4.6 + e Claude Haiku 4.5. Cobre a Messages API, streaming (SSE), raciocínio + (adaptive & extended thinking), tool use (todas as ferramentas client- e server-side), + multimodal (visão, PDF, Files), prompt caching, context editing, batch, structured outputs, + citations, embeddings, Agent Skills, MCP, Managed Agents, a referência REST/SDK completa, + governança (Admin, WIF, rate limits, compliance) e execução nas plataformas de nuvem + (Amazon Bedrock, Google Vertex AI, Microsoft Foundry). +

+
+ anthropic · Python ≥ 3.9 + @anthropic-ai/sdk · Node ≥ 20 + Opus 4.8 · Sonnet 4.6 · Haiku 4.5 + anthropic-version: 2023-06-01 + Verificado em 2026-06-25 +
+
+ +
+

Sobre este guia

+

+ Este é um guia técnico exaustivo, em português brasileiro, da API da Anthropic — + a interface para construir aplicações sobre os modelos Claude. O guia é deliberadamente restrito + aos modelos gerais mais recentes (Opus 4.8, Sonnet 4.6 e Haiku 4.5); modelos de + gerações anteriores foram omitidos por design. Para fatos perecíveis — IDs de modelo, preços, + limites, datas e headers beta — a documentação oficial em platform.claude.com é + sempre a fonte autoritativa. +

+

O conteúdo está organizado em seis partes e um apêndice:

+
    +
  • Parte A — Fundamentos, Modelos & Mensagens: primeira chamada, autenticação, + SDKs, a tabela de modelos, a Messages API, streaming, stop_reason, structured outputs, + effort, janelas de contexto, embeddings e batch.
  • +
  • Parte B — Raciocínio, Caching, Contexto & Multimodal: adaptive e extended thinking, + prompt caching, context editing, compaction, visão, PDF, Files, citations e search results.
  • +
  • Parte C — Ferramentas, Skills & MCP: tool use ponta a ponta, todas as ferramentas + (bash, computer use, code execution, text editor, memory, web search/fetch, tool search), + recursos avançados, Agent Skills e Model Context Protocol (MCP).
  • +
  • Parte D — Referência REST/SDK, Agentes Gerenciados, Governança & Nuvem: + SDKs oficiais, o schema REST completo, Message Batches, Models/Files API, Managed Agents, + Admin/Compliance/WIF e execução em Bedrock/Vertex/Foundry.
  • +
  • Parte E — SDK Python (anthropic) em profundidade: clientes + síncrono/assíncrono e todas as opções de construtor, streaming, ferramentas como funções + (@beta_tool/tool_runner), batches, paginação, hierarquia de erros, + retries/timeouts, respostas cruas, tipos, logging, namespace beta e clientes de plataforma.
  • +
  • Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk) em profundidade: + runtimes suportados (Node, Deno, Bun, Workers, navegador), opções do cliente, streaming por + event handlers, helpers de ferramentas (Zod/JSON + ToolError) e de MCP, batches, + toFile, paginação, erros, retries/timeouts, respostas cruas, logging, proxies, namespace + beta e pacotes de plataforma.
  • +
  • Apêndice: cookbook (notebooks oficiais), glossário e histórico do guia.
  • +
+
+ Como ler: cada capítulo expõe Python (anthropic), TypeScript + (@anthropic-ai/sdk) e REST/cURL em paralelo, preservando os exemplos oficiais. + Use o botão Tema no topo para alternar claro/escuro; o sumário à esquerda acompanha sua leitura. +
+
+ Legível por humanos e por IA: o documento é um único HTML autossuficiente, com + âncoras estáveis por seção, tabelas semânticas e blocos de código rotulados por linguagem, + para ser facilmente indexado, citado e consumido por assistentes. +
+ +
+ Escopo e cobertura — o que é exaustivo vs. resumido (explícito): +
    +
  • Cobertura exaustiva: a Messages API e todos os recursos da API + (streaming, adaptive/extended thinking, prompt caching, context editing, multimodal, citations, + structured outputs, batch, embeddings, tool use e todas as ferramentas, Agent Skills, MCP), + mais o SDK Python (anthropic) e o + SDK JavaScript/TypeScript (@anthropic-ai/sdk) em profundidade — + tudo restrito aos modelos atuais (Opus 4.8, Sonnet 4.6, Haiku 4.5).
  • +
  • Resumido (não detalhado página a página, com link canônico para aprofundar): + as subpáginas individuais de Managed Agents (cobertas em nível de + visão geral e superfície REST/governança, não uma a uma — veja a lista completa em + Fontes oficiais) e a integração legada do Amazon Bedrock + (InvokeModel/Converse; este guia foca a integração atual via Messages API) — + ver claude-on-amazon-bedrock-legacy.
  • +
  • Apenas referência (citados, não detalhados): os SDKs oficiais de + Java, Go, C#, Ruby e PHP — o foco deste guia é Python e JS/TS.
  • +
  • Fatos perecíveis: IDs de modelo, preços, limites e headers beta foram verificados + em 2026-06-10 contra platform.claude.com; para qualquer um deles a + documentação oficial ao vivo é sempre a fonte autoritativa.
  • +
+
+
+ +
+

TL;DR · Cartão de referência rápida

+ +

Setup em 4 passos (do zero à primeira resposta)

+
    +
  1. Obtenha uma chave de API: crie/entre numa conta e gere uma chave em + platform.claude.com/settings/keys + (Claude Console). Garanta que há crédito/billing ativo na organização.
  2. +
  3. Exporte a chave como variável de ambiente (os SDKs a leem automaticamente): +
    export ANTHROPIC_API_KEY="sua-chave-aqui" (Linux/macOS) · + setx ANTHROPIC_API_KEY "sua-chave-aqui" (Windows).
  4. +
  5. Instale o SDK: pip install anthropic (Python ≥ 3.9) ou + npm install @anthropic-ai/sdk (Node ≥ 20).
  6. +
  7. Faça a primeira chamada (código abaixo) e siga para + escolher o modelo e o SDK em profundidade: + Python ou JavaScript/TypeScript.
  8. +
+ +

Referência rápida dos valores essenciais:

+
+ + + + + + + + + + + +
ItemValor
Base URLhttps://api.anthropic.com
Endpoint principalPOST /v1/messages
AutenticaçãoHeader x-api-key: $ANTHROPIC_API_KEY
Versão da APIHeader anthropic-version: 2023-06-01 (obrigatório)
Features betaHeader anthropic-beta: <flag> (quando aplicável)
SDK Pythonpip install anthropic · anthropic.Anthropic()
SDK TypeScriptnpm install @anthropic-ai/sdk · new Anthropic()
+
+

Modelos gerais atuais (detalhes e preços em A3. Modelos Claude):

+
+ + + + + + + +
ModeloID de APIContextoSaída máx.RaciocínioMelhor para
Claude Opus 4.8claude-opus-4-81M tokens128KAdaptive thinking + effortTarefas complexas, coding, agentes
Claude Sonnet 4.6claude-sonnet-4-61M tokens128KeffortEquilíbrio capacidade/custo
Claude Haiku 4.5claude-haiku-4-5200K tokens64KExtended thinkingBaixa latência e custo
+
+
+
+ + + +
+
+
import anthropic
+
+client = anthropic.Anthropic()  # lê ANTHROPIC_API_KEY do ambiente
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude!"}],
+)
+print(message.content[0].text)
+
+
+
import Anthropic from '@anthropic-ai/sdk';
+
+const client = new Anthropic(); // lê ANTHROPIC_API_KEY do ambiente
+const message = await client.messages.create({
+  model: 'claude-opus-4-8',
+  max_tokens: 1024,
+  messages: [{ role: 'user', content: 'Olá, Claude!' }],
+});
+console.log(message.content[0].text);
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{"role": "user", "content": "Olá, Claude!"}]
+  }'
+
+
+
+ Política de modelos deste guia: citamos apenas os modelos gerais mais recentes + (Opus 4.8, Sonnet 4.6, Haiku 4.5). Gerações anteriores foram intencionalmente omitidas. +
+
+ +
+

Fontes oficiais

+

Este guia foi construído a partir da documentação oficial pública da Anthropic em + platform.claude.com/docs (verificada em 2026-06-10), do export + llms-full.txt e do repositório oficial de cookbooks. Sempre que houver divergência + entre este guia e a documentação em produção, a documentação oficial é a fonte autoritativa. + As 115 páginas oficiais consultadas:

+ + +
+ + + +
+

Parte A — Fundamentos, Modelos & API de Mensagens

+

Esta parte cobre o essencial para começar com a API da Anthropic: visão geral da plataforma, primeira chamada e autenticação, SDKs, a tabela definitiva dos modelos atuais (Claude Opus 4.8, Sonnet 4.6 e Haiku 4.5), a anatomia da API de Mensagens, geração de texto e streaming (SSE), o campo stop_reason, structured outputs, o parâmetro effort, fast mode, janelas de contexto e contagem de tokens, embeddings, suporte multilíngue e o processamento em lote (Message Batches API).

+
+ + +
+

1. Visão geral da plataforma Claude & primeira chamada

+

Claude é a família de modelos de linguagem da Anthropic, com desempenho de ponta em linguagem, raciocínio, análise e coding. Há duas formas de construir com Claude, cada uma para um caso de uso diferente:

+ +
+ + + + + +
 Messages APIClaude Managed Agents
O que éAcesso direto de prompting ao modeloHarness de agente pré-construído e configurável, executado em infraestrutura gerenciada
Melhor paraLoops de agente customizados e controle finoTarefas de longa duração e trabalho assíncrono
+ +

O caminho recomendado para um desenvolvedor novo é: (1) fazer a primeira chamada à API, (2) entender a Messages API, (3) escolher o modelo certo (ver seção 3), e (4) explorar ferramentas e recursos avançados.

+ +

Autenticação e primeira chamada

+

A autenticação usa um cabeçalho x-api-key com sua chave do Claude Console, e todo request exige o cabeçalho de versão anthropic-version: 2023-06-01. A URL base é https://api.anthropic.com e o endpoint principal é POST /v1/messages.

+ +
Dica: exporte a chave como variável de ambiente — export ANTHROPIC_API_KEY='sua-chave-aqui' — e adicione a linha ao seu perfil de shell (~/.zshrc ou ~/.bashrc) para persistir entre sessões. Os SDKs leem essa variável automaticamente.
+ +
+
+ + + +
+
+
import anthropic
+
+# Lê ANTHROPIC_API_KEY do ambiente automaticamente
+client = anthropic.Anthropic()
+
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1000,
+    messages=[
+        {
+            "role": "user",
+            "content": "O que devo pesquisar para achar avanços recentes em energia renovável?",
+        }
+    ],
+)
+print(message.content[0].text)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const message = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1000,
+  messages: [
+    {
+      role: "user",
+      content: "O que devo pesquisar para achar avanços recentes em energia renovável?",
+    },
+  ],
+});
+console.log(message.content);
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1000,
+    "messages": [
+      {"role": "user", "content": "O que devo pesquisar para achar avanços recentes em energia renovável?"}
+    ]
+  }'
+
+
+ +

A resposta é um objeto message com id, role: "assistant", um array content de blocos (aqui um bloco text), o model usado, o stop_reason (ver seção 6) e o objeto usage com input_tokens / output_tokens:

+ +
Resposta JSON (200) +
{
+  "id": "msg_01HCDu5LRGeP2o7s2xGmxyx8",
+  "type": "message",
+  "role": "assistant",
+  "content": [
+    { "type": "text", "text": "Aqui estão estratégias de busca eficazes..." }
+  ],
+  "model": "claude-opus-4-8",
+  "stop_reason": "end_turn",
+  "stop_sequence": null,
+  "usage": { "input_tokens": 21, "output_tokens": 305 }
+}
+
+ + +
+ + +
+

2. SDKs & instalação (visão rápida)

+

A Anthropic mantém SDKs oficiais em Python, TypeScript, Java, Go, Ruby, C# e PHP, além de uma CLI (ant). Esta seção cobre o mínimo para rodar; a referência completa de SDKs está na Parte D.

+ +
+ + + + + + +
LinguagemPacoteInstalaçãoVersão mínima
Pythonanthropicpip install anthropicPython 3.9+
TypeScript@anthropic-ai/sdknpm install @anthropic-ai/sdkTS 4.9+ / Node 20+
CLIantbrew install anthropics/tap/ant—
+ +

Em Python o cliente é anthropic.Anthropic() (síncrono) ou anthropic.AsyncAnthropic() (assíncrono). Em TypeScript é new Anthropic(). Ambos leem ANTHROPIC_API_KEY do ambiente; alternativamente passe api_key=... / { apiKey: ... } no construtor. Recursos beta são acessados pelo namespace beta (ex.: client.beta.messages.create(..., betas=["nome-da-feature"])).

+ +
Nota: os SDKs oferecem retries e tratamento de timeouts embutidos. Para max_tokens altos, prefira o modo streaming (ver seção 5) para evitar timeouts de HTTP.
+ + +
+ + +
+

3. Modelos Claude (Opus 4.8 · Sonnet 4.6 · Haiku 4.5)

+

Esta é a seção canônica de modelos do guia — as demais partes a referenciam. A geração atual tem três modelos de uso geral. Use apenas estes IDs em código novo.

+ +

Tabela comparativa

+
+ + + + + + + + + + + + + + + + +
CaracterísticaClaude Opus 4.8Claude Sonnet 4.6Claude Haiku 4.5
DescriçãoO modelo GA mais capaz, para raciocínio complexo e coding agênticoA melhor combinação de velocidade e inteligênciaO modelo mais rápido, com inteligência quase de fronteira
ID de APIclaude-opus-4-8claude-sonnet-4-6claude-haiku-4-5
Snapshot fixoclaude-opus-4-8 o ID puro já é o snapshot (geração 4.6+)claude-sonnet-4-6 o ID puro já é o snapshot (geração 4.6+)claude-haiku-4-5-20251001 alias: claude-haiku-4-5
Janela de contexto1M tokens1M tokens200k tokens
Máx. de saída (Messages API)128k tokens128k tokens64k tokens
ModalidadesTexto + imagem → texto; PDFTexto + imagem → texto; PDFTexto + imagem → texto; PDF
Adaptive thinkingSim (modo recomendado)SimNão
Extended thinking (manual)NãoSimSim
effortlow·medium·high·xhigh·maxlow·medium·high·maxNão suportado
Latência comparativaModeradaRápidaA mais rápida
Knowledge cutoff (confiável)Jan 2026Ago 2025Fev 2025
+ +
+ IDs dateless são snapshots fixos (geração 4.6+). A partir da geração 4.6, o ID + sem data — claude-opus-4-8, claude-sonnet-4-6 — é o snapshot + canônico e imutável: ele mapeia para um único conjunto de pesos fixos e não é um + ponteiro evergreen. Uma versão atualizada sempre sai sob um ID novo. Modelos de gerações anteriores + (como o Haiku 4.5) trazem a data no ID — claude-haiku-4-5-20251001 — e + expõem um alias curto (claude-haiku-4-5) que resolve para o snapshot datado mais recente + daquela versão menor. Os pesos são fixos por ID, mas a infraestrutura de serviço (roteador, classificadores, + sampling) pode evoluir e causar diferenças mínimas de comportamento. + model-ids-and-versions +
+ +

Preços por MTok (milhão de tokens, USD)

+

Todos os preços abaixo são da API de primeira parte (Claude API), em rota global (padrão). A janela completa de 1M tokens (Opus 4.8 e Sonnet 4.6) é cobrada na mesma taxa por token em todo o contexto — um request de 900k tokens custa por token o mesmo que um de 9k.

+
+ + + + + + + + +
ModeloEntradaSaídaCache write 5mCache write 1hCache hit (leitura)
Claude Opus 4.8$5$25$6.25$10$0.50
Claude Sonnet 4.6$3$15$3.75$6$0.30
Claude Haiku 4.5$1$5$1.25$2$0.10
+

O cache write de 5 minutos custa 1,25× o preço de entrada base; o de 1 hora custa 2×; a leitura de cache (hit) custa 0,1× (10%) do preço de entrada. Pela Batch API os tokens saem com 50% de desconto (ver seção 12):

+
+ + + + + + +
ModeloBatch entradaBatch saída
Claude Opus 4.8$2.50$12.50
Claude Sonnet 4.6$1.50$7.50
Claude Haiku 4.5$0.50$2.50
+ +
Atenção: Opus 4.8 usa um tokenizer novo em relação a gerações anteriores, o que contribui para seu desempenho — mas pode consumir até 35% mais tokens para o mesmo texto. Considere isso ao estimar custos ao migrar de versões anteriores.
+ +
Opus 4.8 — atual e recomendado (verificado 2026-06-03): o claude-opus-4-8 é o Opus atual e sucessor direto do 4.7 (agora Legacy). As specs centrais são idênticas às do 4.7 (confirmado em models/overview): janela de 1M tokens, saída de 128k, adaptive thinking (sem extended), preço $5 / $25 por MTok. Diferença de comportamento: no 4.8 o effort assume high por padrão em todas as superfícies (Claude API e Claude Code) — defina-o explicitamente para usar outro nível. O suporte a ferramentas e headers beta (computer use, code execution, web fetch, fast mode, inference_geo) é herdado da superfície do 4.7; para betas de borda, confirme sempre na documentação oficial.
+ +
Atualização 2026-06-25: a Anthropic lançou o Claude Fable 5 (claude-fable-5, GA em 2026-06-09, mas indisponível no momento — confirme o status atual em models/overview antes de planejar uso) — o modelo mais capaz amplamente lançado da Anthropic: $10 / $50 por MTok, contexto de 1M tokens, saída máxima de 128k e adaptive thinking sempre ativo — thinking: {"type": "disabled"}, budget manual (enabled + budget_tokens) e prefill do turno assistant retornam 400; thinking.display assume "omitted" por padrão. Usa o tokenizer do Opus 4.7 (~30% mais tokens que gerações pré-4.7 para o mesmo texto), traz classificadores de segurança com stop_reason: "refusal" (sem cobrança se nada for gerado — política de toda a Claude API desde 02/06/2026, não exclusiva do Fable 5) e o parâmetro fallbacks Beta, exige retenção de 30 dias (não elegível a ZDR) e tem cache mínimo de 512 tokens. O Claude Mythos 5 (claude-mythos-5) está em disponibilidade limitada. O Opus 4.8 segue ativo e recomendado — este guia permanece centrado nele (com Sonnet 4.6 e Haiku 4.5). Deprecações: Sonnet 4 e Opus 4 aposentam em 2026-06-15; Opus 4.1 (anúncio de 2026-06-05) aposenta em 2026-08-05. Desde 2026-05-27, a API reporta usage.output_tokens_details.thinking_tokens no message_delta final. + models/overview · model-deprecations +
+ +

Quando usar cada modelo

+
    +
  • Opus 4.8 — tarefas complexas, raciocínio profundo e coding agêntico de longo horizonte. Comece com effort: "xhigh" para coding/agentes; é o padrão recomendado para os casos mais difíceis.
  • +
  • Sonnet 4.6 — equilíbrio de velocidade, custo e inteligência para a maioria das cargas de produção (coding, agentes, fluxos enterprise). Defina effort explicitamente (recomendado medium) para evitar latência inesperada.
  • +
  • Haiku 4.5 — baixa latência e baixo custo: classificação, lookups rápidos, subagentes e volumes altos onde ganhos marginais de qualidade não compensam latência/custo.
  • +
+ +

Aliases vs. snapshots & política de deprecação

+

Todo ID de modelo identifica um snapshot fixo: enquanto o ID existir, os pesos não mudam. A partir da geração 4.6 os IDs adotam um formato sem data (claude-{nome}-{maior}-{menor}, ex.: claude-sonnet-4-6, claude-opus-4-8) que ainda assim é um snapshot fixo — não um ponteiro "evergreen". Quando há uma versão atualizada, ela é lançada sob um novo ID.

+
Nota: em modelos anteriores à 4.6, IDs incluíam a data (claude-haiku-4-5-20251001) e havia aliases de conveniência (ex.: claude-haiku-4-5) que apontavam para o snapshot datado mais recente. Para 4.6+, o ID sem data é o snapshot — não é um alias. Por isso, na tabela acima, Sonnet 4.6 não tem ID datado separado.
+

Os pesos do modelo são fixos por ID, mas a infraestrutura de serviço (roteador, classificadores de segurança, lógica de sampling) pode mudar; isso ocasionalmente produz pequenas diferenças observáveis mesmo com ID e pesos inalterados. Cada ID tem seu próprio cronograma de deprecação e retirada — consulte a página de model deprecations antes de migrar.

+ + +
+ + +
+

3.1 Endpoint Models API (descoberta programática)

+

A Models API permite listar os modelos disponíveis e resolver um alias para um ID, retornando limites e capacidades de cada modelo. É útil para roteamento dinâmico e para descobrir features suportadas em runtime, sem hard-coding.

+ +
+ + + + + +
OperaçãoMétodo / rotaDescrição
List ModelsGET /v1/modelsLista modelos (mais recentes primeiro). Paginação por after_id/before_id, limit 1–1000 (padrão 20).
Get a ModelGET /v1/models/{model_id}Retorna info de um modelo específico; aceita ID ou alias.
+ +

Cada item (ModelInfo) traz: id, display_name, created_at (RFC 3339), type: "model", e os campos-chave para roteamento:

+
    +
  • max_input_tokens — tamanho máximo da janela de contexto de entrada.
  • +
  • max_tokens — valor máximo do parâmetro max_tokens para esse modelo.
  • +
  • capabilities — objeto com flags { supported: boolean } por capacidade: batch, citations, code_execution, image_input, pdf_input, structured_outputs, context_management (com estratégias datadas), effort (níveis low/medium/high/xhigh/max) e thinking (tipos adaptive e enabled).
  • +
+ +
+
+ + + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+# Lista modelos (paginação automática)
+for model in client.models.list(limit=20):
+    print(model.id, model.display_name)
+
+# Resolve um alias / inspeciona limites e capacidades
+info = client.models.retrieve("claude-opus-4-8")
+print(info.max_input_tokens, info.max_tokens)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+for await (const model of client.models.list({ limit: 20 })) {
+  console.log(model.id, model.display_name);
+}
+
+const info = await client.models.retrieve("claude-opus-4-8");
+console.log(info.max_input_tokens, info.max_tokens);
+
+
+
curl https://api.anthropic.com/v1/models \
+  --header "anthropic-version: 2023-06-01" \
+  --header "x-api-key: $ANTHROPIC_API_KEY"
+
+curl https://api.anthropic.com/v1/models/claude-opus-4-8 \
+  --header "anthropic-version: 2023-06-01" \
+  --header "x-api-key: $ANTHROPIC_API_KEY"
+
+
+ + +
+ + +
+

4. API de Mensagens — anatomia

+

A Messages API (POST /v1/messages) é o coração da integração. Os parâmetros centrais de um request são:

+
+ + + + + + + + + + +
ParâmetroTipoDescrição
modelstring (obrigatório)ID do modelo (ex.: claude-opus-4-8).
max_tokensinteger (obrigatório)Máximo de tokens a gerar. Limitado pelo max_tokens do modelo (ver seção 3).
messagesarray (obrigatório)Histórico de turnos. Cada item tem role (user ou assistant) e content (string ou array de blocos).
systemstring ou arrayPrompt de sistema — instruções, persona, regras. Não é um turno de messages; é um campo de topo.
temperaturenumber (0–1)Aleatoriedade da amostragem. Mais baixo → mais determinístico.
stop_sequencesarray de stringsSequências que, ao serem geradas, encerram a resposta (stop_reason: "stop_sequence").
streambooleantrue para streaming via SSE (ver seção 5).
+ +

Conversas multiturno (API stateless)

+

A Messages API é stateless: você sempre envia o histórico completo a cada chamada. Para continuar uma conversa, anexe a resposta do assistant e o novo turno do user ao array messages. Turnos anteriores não precisam ter vindo de fato do Claude — você pode inserir mensagens assistant sintéticas.

+ +
+
+ + + +
+
+
message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    system="Você é um tutor paciente de física.",
+    messages=[
+        {"role": "user", "content": "Olá, Claude"},
+        {"role": "assistant", "content": "Olá! Como posso ajudar?"},
+        {"role": "user", "content": "Você pode me descrever LLMs?"},
+    ],
+)
+print(message.content[0].text)
+
+
+
const message = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  system: "Você é um tutor paciente de física.",
+  messages: [
+    { role: "user", content: "Olá, Claude" },
+    { role: "assistant", content: "Olá! Como posso ajudar?" },
+    { role: "user", content: "Você pode me descrever LLMs?" },
+  ],
+});
+console.log(message.content[0].text);
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "system": "Você é um tutor paciente de física.",
+    "messages": [
+      {"role": "user", "content": "Olá, Claude"},
+      {"role": "assistant", "content": "Olá! Como posso ajudar?"},
+      {"role": "user", "content": "Você pode me descrever LLMs?"}
+    ]
+  }'
+
+
+ +

Prefill ("colocando palavras na boca do Claude")

+

Historicamente, era possível pré-preencher o início da resposta colocando uma mensagem assistant na última posição de messages para moldar a saída (ex.: forçar um formato).

+
Cuidado: o prefill não é suportado em claude-opus-4-8 nem em claude-sonnet-4-6 — requests com prefill nesses modelos retornam erro 400. Para moldar o formato da resposta, use structured outputs (JSON outputs) ou instruções no system prompt.
+ +

Entradas de visão (resumo)

+

Os blocos de content podem ser de tipo image além de text. A fonte da imagem pode ser base64, url ou file (referência a um arquivo da Files API). Tipos de mídia suportados: image/jpeg, image/png, image/gif, image/webp. O detalhamento de visão, PDFs e Files API está na Parte B.

+ + +
+ + +
+

5. Geração de texto & streaming (SSE)

+

Com "stream": true, a resposta é entregue incrementalmente via Server-Sent Events (SSE). Os SDKs oferecem helpers idiomáticos: em Python, client.messages.stream(...) com iteração sobre stream.text_stream; em TypeScript, o método .stream({...}) com o evento .on("text", ...).

+ +
Transporte: a Messages API usa HTTP request-response; o streaming é SSE (stream: true) sobre a mesma conexão HTTP — um único endpoint (POST /v1/messages) atende mensagens, tools, thinking e caching, mudando só o corpo. Não há transporte WebSocket para a Messages API. WebSocket aparece apenas no transporte de servidores MCP (streamable-HTTP/WebSocket), uma camada de ferramentas separada da chamada ao modelo.
+ +
+
+ + + +
+
+
with client.messages.stream(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá"}],
+) as stream:
+    for text in stream.text_stream:
+        print(text, end="", flush=True)
+
+    # Acumula tudo e retorna o Message completo (igual ao .create())
+    final = stream.get_final_message()
+
+
+
const stream = client.messages.stream({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Olá" }],
+});
+
+for await (const event of stream) {
+  if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
+    process.stdout.write(event.delta.text);
+  }
+}
+
+const final = await stream.finalMessage();
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "messages": [{"role": "user", "content": "Olá"}],
+    "max_tokens": 256,
+    "stream": true
+  }'
+
+
+ +
Dica: mesmo quando você não precisa processar texto incremental, use streaming para requests com max_tokens grande. get_final_message() (Python) / finalMessage() (TS) mantêm a conexão HTTP viva e acumulam tudo, evitando timeouts.
+ +

Fluxo e tipos de eventos

+

Cada SSE traz um nome de evento (event: ...) e dados JSON com um campo type correspondente. O fluxo de um stream é:

+
    +
  1. message_start — objeto Message com content vazio.
  2. +
  3. Uma série de blocos de conteúdo, cada um com content_block_start → um ou mais content_block_delta → content_block_stop. Cada bloco tem um index que corresponde à sua posição no array content final.
  4. +
  5. Um ou mais message_delta — mudanças de topo no Message (ex.: stop_reason, usage).
  6. +
  7. Um message_stop final.
  8. +
+

Podem aparecer eventos ping em qualquer ponto, e eventos error (ex.: overloaded_error, equivalente a HTTP 529 fora do streaming). Conforme a política de versionamento, novos tipos de evento podem surgir — trate tipos desconhecidos com tolerância.

+ +
+ + + + + + + +
Tipo de deltaEm que blocoObservação
text_deltatextFragmento de texto: {"type":"text_delta","text":"olá frien"}.
input_json_deltatool_useFragmentos parciais de JSON no campo partial_json; acumule e parseie ao receber content_block_stop.
thinking_deltathinkingConteúdo de raciocínio (extended/adaptive thinking).
signature_deltathinkingAssinatura criptográfica enviada antes do content_block_stop, verifica a integridade do bloco de thinking.
+ +
Atenção: os contadores em usage dentro de eventos message_delta são cumulativos. O stop_reason é null em message_start e só aparece preenchido em message_delta.
+ +
Exemplo de stream SSE completo +
event: message_start
+data: {"type":"message_start","message":{"id":"msg_...","type":"message","role":"assistant","content":[],"model":"claude-opus-4-8","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":25,"output_tokens":1}}}
+
+event: content_block_start
+data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
+
+event: ping
+data: {"type":"ping"}
+
+event: content_block_delta
+data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Olá"}}
+
+event: content_block_stop
+data: {"type":"content_block_stop","index":0}
+
+event: message_delta
+data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":15}}
+
+event: message_stop
+data: {"type":"message_stop"}
+
+ + +
+ + +
+

6. O campo stop_reason

+

Toda resposta bem-sucedida da Messages API inclui stop_reason, indicando por que o Claude parou de gerar. Ao contrário de erros (que indicam falhas no request), stop_reason faz parte de uma resposta válida. Sempre cheque esse campo na sua lógica de tratamento.

+ +
+ + + + + + + + + + +
ValorSignificadoComo tratar
end_turnClaude terminou naturalmente (o mais comum).Processe a resposta completa.
max_tokensAtingiu o limite de max_tokens do request — resposta truncada.Reenvie com max_tokens maior, ou continue a geração.
stop_sequenceEncontrou uma das suas stop_sequences personalizadas.O campo stop_sequence indica qual sequência disparou.
tool_useClaude está chamando uma ferramenta e espera que você a execute.Execute a ferramenta e devolva o tool_result (ver Parte C).
pause_turnO loop de sampling do servidor atingiu o limite de iterações ao executar server tools (web search/fetch). Padrão: 10 iterações.Continue a conversa reenviando a resposta como está (anexe o assistant e chame de novo).
refusalClaude recusou por motivos de segurança.HTTP 200, mas a saída pode não seguir o schema. Reformule o pedido.
model_context_window_exceededAtingiu o limite da janela de contexto do modelo antes do max_tokens.A resposta é válida, mas limitada pela janela. Veja a nota abaixo.
+ +
Nota: model_context_window_exceeded está disponível por padrão em modelos Claude 4.5 e mais recentes. Em modelos anteriores, habilite com o header beta model-context-window-exceeded-2025-08-26. Ele permite pedir o máximo possível de tokens sem conhecer o tamanho exato da entrada.
+ +

Pegadinha — respostas vazias com end_turn: às vezes o Claude retorna conteúdo vazio (2–3 tokens) com end_turn, tipicamente após tool_result. Causas comuns: (1) adicionar um bloco text logo após um tool_result (o Claude aprende a esperar input do usuário após cada uso de ferramenta), e (2) reenviar a resposta já concluída sem nada novo. Soluções: nunca adicione texto imediatamente após tool_result; e, se persistir, anexe um novo turno user ("Por favor, continue") em vez de reenviar a resposta vazia.

+ +
+
+ + +
+
+
def handle_response(response):
+    if response.stop_reason == "tool_use":
+        return handle_tool_use(response)
+    elif response.stop_reason in ("max_tokens", "model_context_window_exceeded"):
+        return handle_truncation(response)
+    elif response.stop_reason == "pause_turn":
+        return handle_pause(response)
+    elif response.stop_reason == "refusal":
+        return handle_refusal(response)
+    else:  # end_turn e demais
+        return response.content[0].text
+
+
+
function handleResponse(response) {
+  switch (response.stop_reason) {
+    case "tool_use": return handleToolUse(response);
+    case "max_tokens":
+    case "model_context_window_exceeded": return handleTruncation(response);
+    case "pause_turn": return handlePause(response);
+    case "refusal": return handleRefusal(response);
+    default: { // end_turn e demais
+      const block = response.content.find((b) => b.type === "text");
+      return block?.text;
+    }
+  }
+}
+
+
+ +
Dica: em streaming, stop_reason é null no message_start e é fornecido no message_delta (não em outros eventos). Ao truncar por max_tokens durante tool_use, verifique se o último bloco é um tool_use incompleto e reenvie com max_tokens maior.
+ + +
+ + +
+

7. Structured outputs GA

+

Structured outputs restringem a resposta do Claude a um schema, garantindo saída válida e parseável via constrained decoding. São dois recursos complementares, usáveis isolada ou conjuntamente:

+
    +
  • JSON outputs (output_config.format): força a resposta em um formato JSON específico (o que o Claude diz).
  • +
  • Strict tool use (strict: true em uma ferramenta): garante validação de schema nos nomes e inputs de ferramentas (como o Claude chama suas funções).
  • +
+ +
Nota: GA na Claude API para Claude Opus 4.8, Sonnet 4.6 e Haiku 4.5 (entre outros). O antigo parâmetro beta output_format migrou para output_config.format e o header beta não é mais necessário — o caminho antigo segue funcionando por um período de transição.
+ +

JSON outputs

+

Defina um JSON Schema e inclua-o em output_config.format com type: "json_schema". A resposta vem como JSON válido em response.content[0].text.

+ +
+
+ + + +
+
+
response = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Extraia os dados deste e-mail: John Smith (john@example.com), interesse no plano Enterprise, quer demo terça às 14h."}],
+    output_config={
+        "format": {
+            "type": "json_schema",
+            "schema": {
+                "type": "object",
+                "properties": {
+                    "name": {"type": "string"},
+                    "email": {"type": "string"},
+                    "plan_interest": {"type": "string"},
+                    "demo_requested": {"type": "boolean"},
+                },
+                "required": ["name", "email", "plan_interest", "demo_requested"],
+                "additionalProperties": False,
+            },
+        }
+    },
+)
+print(response.content[0].text)  # JSON válido garantido
+
+
+
const response = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Extraia os dados deste e-mail: John Smith (john@example.com)..." }],
+  output_config: {
+    format: {
+      type: "json_schema",
+      schema: {
+        type: "object",
+        properties: {
+          name: { type: "string" },
+          email: { type: "string" },
+          plan_interest: { type: "string" },
+          demo_requested: { type: "boolean" },
+        },
+        required: ["name", "email", "plan_interest", "demo_requested"],
+        additionalProperties: false,
+      },
+    },
+  },
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  -H "content-type: application/json" \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -d '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{"role": "user", "content": "Extraia os dados deste e-mail..."}],
+    "output_config": {
+      "format": {
+        "type": "json_schema",
+        "schema": {
+          "type": "object",
+          "properties": {
+            "name": {"type": "string"},
+            "email": {"type": "string"},
+            "plan_interest": {"type": "string"},
+            "demo_requested": {"type": "boolean"}
+          },
+          "required": ["name", "email", "plan_interest", "demo_requested"],
+          "additionalProperties": false
+        }
+      }
+    }
+  }'
+
+
+ +
Dica: os SDKs têm helpers que aceitam definições nativas e validam automaticamente: em Python, client.messages.parse(..., output_format=ModeloPydantic) retorna response.parsed_output; em TypeScript, zodOutputFormat(schema) ou jsonSchemaOutputFormat(schema) com client.messages.parse(...).
+ +

Strict tool use & uso combinado

+

Marque uma ferramenta com strict: true para que seus inputs sejam validados contra o input_schema por sampling guiado por gramática. JSON outputs e strict tool use resolvem problemas diferentes e funcionam juntos no mesmo request — útil em fluxos agênticos onde você precisa de chamadas de ferramenta confiáveis e de uma saída final estruturada.

+ +

Limitações de JSON Schema & complexidade

+

Structured outputs suportam um subconjunto do JSON Schema. Recursos como enum (tipos simples), const, anyOf/allOf (com restrições), $ref/$defs internos, default, e formatos de string (date-time, date, email, uri, uuid, etc.) são suportados. Não são suportados: schemas recursivos, $ref externo, restrições numéricas (minimum/maximum/multipleOf), restrições de string (minLength/maxLength) e additionalProperties diferente de false. Usar um recurso não suportado gera erro 400.

+
+ + + + + + +
Limite explícitoValorDescrição
Ferramentas strict por request20Máx. de tools com strict: true.
Parâmetros opcionais24Total de parâmetros não-required em todos os schemas strict + JSON output.
Parâmetros com union types16Total que usa anyOf ou arrays de tipo (custo de compilação exponencial).
+

Caching de gramática: a primeira request com um schema tem latência extra de compilação; gramáticas compiladas são cacheadas por 24h desde o último uso (mudanças em name/description não invalidam o cache, mas mudar a estrutura ou o conjunto de tools sim). Há um timeout de compilação de 180s.

+ +
Atenção: structured outputs são incompatíveis com Citations (retorna 400 se combinado com output_config.format) e com prefilling de mensagem. São compatíveis com batch, token counting e streaming. Em ZDR, prompts/respostas não são retidos, mas o JSON schema é cacheado por até 24h — não inclua PHI/dados sensíveis em nomes de propriedade, enum, const ou pattern.
+ + +
+ + +
+

8. Effort & Fast mode

+

O parâmetro effort

+

O parâmetro effort (em output_config.effort) controla quão "disposto" o Claude está a gastar tokens, equilibrando completude e eficiência. Não exige header beta e afeta todos os tokens da resposta — texto, chamadas de ferramenta e o thinking (quando ativo). É suportado em Claude Opus 4.8 e Sonnet 4.6 (Haiku 4.5 não suporta).

+ +
+ + + + + + + + +
NívelDescriçãoDisponível em
maxCapacidade máxima absoluta, sem restrição de tokens.Opus 4.8, Sonnet 4.6
xhighCapacidade estendida para trabalho de longo horizonte (agentes/coding > 30 min, budgets na casa dos milhões).Apenas Opus 4.8
highAlta capacidade. Equivale a não setar o parâmetro (é o padrão da API).Todos os suportados
mediumEquilíbrio com economia moderada de tokens.Todos os suportados
lowMais eficiente; economia significativa com alguma redução de capacidade.Todos os suportados
+ +
+
+ + + +
+
+
response = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=4096,
+    messages=[{"role": "user", "content": "Analise trade-offs entre microsserviços e monólito."}],
+    output_config={"effort": "medium"},
+)
+print(response.content[0].text)
+
+
+
const response = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 4096,
+  messages: [{ role: "user", content: "Analise trade-offs entre microsserviços e monólito." }],
+  output_config: { effort: "medium" },
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 4096,
+    "messages": [{"role": "user", "content": "Analise trade-offs entre microsserviços e monólito."}],
+    "output_config": {"effort": "medium"}
+  }'
+
+
+ +
Dica: para Opus 4.8, comece em xhigh para coding/agentes e use high como mínimo para cargas sensíveis a inteligência; reserve max para problemas de fronteira. Para Sonnet 4.6, defina effort explicitamente (recomendado medium) — caso contrário pode haver latência inesperada. Em xhigh/max no Opus 4.8, dê um max_tokens generoso (comece em 64k).
+ +

effort e thinking: em Opus 4.8 e Sonnet 4.6 o thinking é adaptativo (thinking: {type: "adaptive"}) e o effort é o controle recomendado da profundidade — no Opus 4.8, o thinking manual (type: "enabled", budget_tokens) não é mais suportado. effort também funciona sem thinking, controlando o gasto geral. (Detalhes de thinking na Parte B.)

+ +

Fast mode Beta (research preview)

+

O fast mode entrega geração de tokens de saída até 2,5× mais rápida rodando o mesmo modelo com uma configuração de inferência mais veloz (mesmos pesos, mesma inteligência). Ativa-se com speed: "fast" e o header beta fast-mode-2026-02-01, via namespace beta. Suportado em Claude Opus 4.8.

+ +
+
+ + + +
+
+
response = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=4096,
+    speed="fast",
+    betas=["fast-mode-2026-02-01"],
+    messages=[{"role": "user", "content": "Refatore este módulo para injeção de dependência"}],
+)
+print(response.usage.speed)  # "fast" ou "standard"
+
+
+
const response = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 4096,
+  speed: "fast",
+  betas: ["fast-mode-2026-02-01"],
+  messages: [{ role: "user", content: "Refatore este módulo para injeção de dependência" }],
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "anthropic-beta: fast-mode-2026-02-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 4096,
+    "speed": "fast",
+    "messages": [{"role": "user", "content": "Refatore este módulo para injeção de dependência"}]
+  }'
+
+
+ +
Atenção: fast mode custa 6× as taxas padrão do Opus em toda a janela de contexto: $30/MTok entrada · $150/MTok saída. O ganho é em tokens de saída por segundo (OTPS), não em time to first token. Tem rate limit dedicado (HTTP 429 com header retry-after) e não está disponível com a Batch API nem no Claude Platform on AWS. O usage.speed da resposta indica qual velocidade foi usada.
+ + +
+ + +
+

9. Janelas de contexto & contagem de tokens

+

A "janela de contexto" é todo o texto que o modelo consegue referenciar ao gerar uma resposta, incluindo a própria resposta — uma "memória de trabalho". Opus 4.8 e Sonnet 4.6 têm 1M tokens; Haiku 4.5 (e modelos com janela menor) têm 200k tokens. Um único request pode incluir até 600 imagens/páginas de PDF (100 em modelos de 200k).

+ +
Nota: mais contexto não é automaticamente melhor. À medida que o número de tokens cresce, precisão e recall degradam — fenômeno conhecido como context rot. Curar o que entra no contexto importa tanto quanto quanto cabe.
+ +

Contexto com thinking: tokens de thinking contam para a janela e são cobrados como saída, mas blocos de thinking de turnos anteriores são automaticamente removidos do cálculo da janela pela API — você não precisa removê-los manualmente. A exceção: durante um ciclo de tool_use, o bloco de thinking que acompanha o tool_use deve ser devolvido junto com os tool_result correspondentes (a API usa assinaturas criptográficas para verificar a integridade).

+ +

Context awareness: Sonnet 4.6 e Haiku 4.5 rastreiam o "token budget" restante ao longo da conversa, recebendo no início <budget:token_budget>1000000</budget:token_budget> e, após cada chamada de ferramenta, um aviso de capacidade restante. Isso melhora a execução em tarefas longas. Para janelas que se aproximam do limite, a estratégia recomendada é a compaction server-side (Parte B); context editing oferece estratégias finas adicionais.

+ +

Overflow: nos modelos atuais, se input_tokens + max_tokens exceder a janela, a API aceita o request e, se a geração atingir o limite, para com stop_reason: "model_context_window_exceeded" (ver seção 6). Em gerações anteriores a API retornava erro de validação.

+ +

Contagem de tokens (conceito)

+

O endpoint POST /v1/messages/count_tokens conta os tokens de entrada antes de enviar o request, ajudando a gerenciar rate limits/custos, decidir roteamento de modelo e otimizar o tamanho do prompt. Aceita a mesma lista estruturada de inputs (system, tools, imagens, PDFs) e retorna { "input_tokens": N }. Todos os modelos ativos suportam contagem de tokens.

+ +
+
+ + + +
+
+
response = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    system="Você é um cientista",
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+print(response.input_tokens)  # ex.: 14
+
+
+
const response = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  system: "Você é um cientista",
+  messages: [{ role: "user", content: "Olá, Claude" }],
+});
+console.log(response.input_tokens);
+
+
+
curl https://api.anthropic.com/v1/messages/count_tokens \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "system": "Você é um cientista",
+    "messages": [{"role": "user", "content": "Olá, Claude"}]
+  }'
+
+
+ +
Atenção: a contagem é uma estimativa — o número real de tokens pode diferir por uma pequena margem. A contagem pode incluir tokens adicionados pela Anthropic para otimizações de sistema, mas você não é cobrado por tokens adicionados pelo sistema; o faturamento reflete apenas seu conteúdo.
+ + +
+ + +
+

10. Embeddings

+

Embeddings são representações numéricas de texto que permitem medir similaridade semântica — base para busca, recomendação, RAG e detecção de anomalias. A Anthropic não oferece um modelo de embedding próprio; a documentação recomenda Voyage AI como parceiro (modelos de propósito geral, multilíngues e específicos de domínio como finanças, jurídico e código).

+ +
+ + + + + + + +
Modelo (Voyage 4)ContextoDimensãoFoco
voyage-4-large32.0001024 (padrão), 256, 512, 2048Melhor qualidade geral/multilíngue
voyage-432.0001024 (padrão), 256, 512, 2048Equilíbrio qualidade/eficiência
voyage-4-lite32.0001024 (padrão), 256, 512, 2048Menor latência e custo
voyage-code-332.0001024 (padrão), …Recuperação de código
+ +
+
+ + +
+
+
import voyageai
+
+vo = voyageai.Client()  # usa VOYAGE_API_KEY do ambiente
+
+# Use input_type para distinguir documento de consulta (melhora a recuperação)
+docs = vo.embed(["Texto exemplo 1", "Texto exemplo 2"],
+                model="voyage-4", input_type="document").embeddings
+query = vo.embed(["Minha pergunta"], model="voyage-4", input_type="query").embeddings[0]
+
+
+
curl https://api.voyageai.com/v1/embeddings \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $VOYAGE_API_KEY" \
+  -d '{
+    "input": ["Texto exemplo 1", "Texto exemplo 2"],
+    "model": "voyage-4"
+  }'
+
+
+ +
Dica: em tarefas de recuperação (RAG), sempre use input_type ("query" vs "document") — não omita. Os embeddings da Voyage são normalizados a comprimento 1, então similaridade por produto escalar e cosseno são equivalentes (o produto escalar é mais rápido). Quantização (output_dtype) e dimensões Matryoshka permitem reduzir armazenamento/custo.
+ + +
+ + +
+

11. Suporte multilíngue

+

Claude tem forte desempenho cross-lingual em relação ao inglês, com destaque em tarefas zero-shot. Para um guia em português, vale notar que o português (Brasil) está entre os idiomas de melhor desempenho relativo ao inglês — na avaliação MMLU traduzida por tradutores humanos, fica acima de 96% em relação ao baseline inglês nos modelos recentes, ao lado de espanhol, italiano e francês. O desempenho varia por idioma, sendo mais forte em línguas amplamente faladas, mas Claude mantém capacidade significativa mesmo em idiomas com menos recursos digitais.

+ +
Dica (boas práticas multilíngues): +
    +
  • Forneça contexto de idioma claro: embora o Claude detecte automaticamente, declarar explicitamente a língua de entrada/saída melhora a confiabilidade. Para mais fluência, peça "fala idiomática, como um falante nativo".
  • +
  • Use o script nativo em vez de transliteração.
  • +
  • Considere contexto cultural e regional — comunicação eficaz costuma exigir mais do que tradução literal.
  • +
+
+

Claude processa entrada e gera saída na maioria das línguas que usam caracteres Unicode padrão. Preserve acentuação (UTF-8) ponta a ponta.

+ + +
+ + +
+

12. Processamento em lote (Message Batches API)

+

A Message Batches API processa grandes volumes de requests de Mensagens de forma assíncrona, com 50% de desconto em entrada e saída e maior throughput. Ideal quando você não precisa de resposta imediata: avaliações em larga escala, moderação de conteúdo, análise de dados e geração em massa.

+ +

Fluxo: (1) você cria um batch enviando uma lista de requests no parâmetro requests; (2) o sistema processa cada request independentemente e de forma assíncrona; (3) você faz polling do status e recupera os resultados ao término. Cada request tem um custom_id (1–64 caracteres, ^[a-zA-Z0-9_-]{1,64}$) e um objeto params com os parâmetros padrão da Messages API. Todos os modelos ativos suportam batches, e qualquer request da Messages API pode ser incluído (visão, tool use, system, multiturno, features beta — podendo misturar tipos no mesmo batch).

+ +
+
+ + + +
+
+
from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
+from anthropic.types.messages.batch_create_params import Request
+
+batch = client.messages.batches.create(
+    requests=[
+        Request(
+            custom_id="req-1",
+            params=MessageCreateParamsNonStreaming(
+                model="claude-opus-4-8", max_tokens=1024,
+                messages=[{"role": "user", "content": "Olá, mundo"}],
+            ),
+        ),
+        Request(
+            custom_id="req-2",
+            params=MessageCreateParamsNonStreaming(
+                model="claude-opus-4-8", max_tokens=1024,
+                messages=[{"role": "user", "content": "Olá de novo, amigo"}],
+            ),
+        ),
+    ]
+)
+print(batch.id, batch.processing_status)
+
+# Recupera resultados (stream, eficiente em memória) ao término
+for result in client.messages.batches.results(batch.id):
+    if result.result.type == "succeeded":
+        print(result.custom_id, "ok")
+    elif result.result.type == "errored":
+        print(result.custom_id, result.result.error)
+
+
+
const batch = await client.messages.batches.create({
+  requests: [
+    {
+      custom_id: "req-1",
+      params: { model: "claude-opus-4-8", max_tokens: 1024,
+                messages: [{ role: "user", content: "Olá, mundo" }] },
+    },
+    {
+      custom_id: "req-2",
+      params: { model: "claude-opus-4-8", max_tokens: 1024,
+                messages: [{ role: "user", content: "Olá de novo, amigo" }] },
+    },
+  ],
+});
+
+for await (const result of await client.messages.batches.results(batch.id)) {
+  if (result.result.type === "succeeded") console.log(result.custom_id, "ok");
+}
+
+
+
curl https://api.anthropic.com/v1/messages/batches \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "requests": [
+      {"custom_id": "req-1", "params": {"model": "claude-opus-4-8", "max_tokens": 1024,
+        "messages": [{"role": "user", "content": "Olá, mundo"}]}},
+      {"custom_id": "req-2", "params": {"model": "claude-opus-4-8", "max_tokens": 1024,
+        "messages": [{"role": "user", "content": "Olá de novo, amigo"}]}}
+    ]
+  }'
+
+
+ +

O processing_status começa em in_progress e vira ended quando todos os requests terminam; o objeto traz request_counts com contadores por estado (processing, succeeded, errored, canceled, expired). Os resultados ficam em results_url — prefira streamar em vez de baixar tudo de uma vez. Há quatro tipos de resultado:

+
+ + + + + + + +
TipoSignificadoCobrança
succeededRequest bem-sucedido; inclui o resultado da mensagem.Cobrado
erroredErro (request inválido ou erro interno). invalid_request_error exige corrigir o corpo; outros podem ser repetidos.Não cobrado
canceledUsuário cancelou o batch antes deste request ser enviado.Não cobrado
expiredBatch atingiu a expiração de 24h antes do envio.Não cobrado
+ +
Atenção — limites: um batch é limitado a 100.000 requests ou 256 MB (o que vier primeiro). A maioria completa em menos de 1h; resultados ficam disponíveis quando tudo termina ou após 24h (o que vier primeiro) — batches que não completam em 24h expiram. Resultados ficam acessíveis para download por 29 dias. Batches têm escopo de Workspace. Cada request precisa de max_tokens ≥ 1 (max_tokens: 0 não é suportado em batch). A validação dos params é assíncrona — teste o formato com a Messages API primeiro.
+ +
Dica: como batches podem levar mais de 5 minutos, use o cache de 1 hora (prompt caching) para melhores taxas de acerto ao processar batches com contexto compartilhado. Não é ZDR-elegível.
+ + +
+ + + + +
+

Parte B — Raciocínio, Caching, Contexto & Multimodal

+

Esta parte cobre como controlar o raciocínio do Claude (adaptive thinking, extended thinking, efforto, raciocínio com ferramentas e orçamentos de tarefa), como reduzir custo e latência com prompt caching e diagnósticos de cache, como gerenciar janelas de contexto longas (context editing e compaction) e como enviar conteúdo multimodal (imagens, PDFs, Files API) com citações verificáveis e resultados de busca para RAG.

+
+ + +
+

1. Adaptive thinking (raciocínio adaptativo)

+

O adaptive thinking deixa o Claude decidir dinamicamente se vai raciocinar e quanto vai raciocinar, com base na complexidade de cada requisição — em vez de você fixar um orçamento de tokens de pensamento. É o modo recomendado de usar extended thinking nos modelos atuais e o único modo suportado no Claude Opus 4.8.

+ + +

1.1. Quando usar

+

Adaptive thinking costuma superar o extended thinking de orçamento fixo em muitas cargas — sobretudo em tarefas bimodais (mistura de perguntas simples e difíceis) e em fluxos agênticos de horizonte longo, pois o modelo gasta raciocínio só onde compensa. Nenhum header beta é necessário. Se você precisa de latência previsível ou de controle preciso do custo de raciocínio, o extended thinking manual com budget_tokens ainda funciona no Claude Sonnet 4.6 (ver capítulo 2).

+ +

1.2. Suporte por modelo

+

O modo de raciocínio e o suporte a effort variam por modelo. Para a tabela completa de capacidades dos modelos, veja Modelos Claude (Parte A).

+
+ + + + + + +
ModeloAdaptive thinkingeffortObservação
claude-opus-4-8único modosim (inclui xhigh)Raciocínio desligado por padrão; ative com thinking: {type: "adaptive"}. type: "enabled" com budget_tokens é rejeitado com erro 400. Não expõe extended thinking manual.
claude-sonnet-4-6suportadosimAceita adaptive + effort e também o modo manual enabled (ainda funcional).
claude-haiku-4-5nãonãoUsa extended thinking manual: thinking: {type: "enabled", budget_tokens: N}. Não tem adaptive nem effort.
+
Atenção: o parâmetro effort está disponível em claude-opus-4-8 (com xhigh) e claude-sonnet-4-6; com adaptive thinking é o controle de profundidade recomendado, mas effort também funciona sem thinking, controlando o gasto geral da resposta. No claude-haiku-4-5 não há adaptive nem effort: controle o raciocínio apenas via budget_tokens (ver capítulo 2).
+ +

1.3. Como usar

+

Defina thinking.type como "adaptive". No nível padrão de effort (high), o Claude quase sempre raciocina; em níveis mais baixos pode pular o raciocínio em perguntas simples.

+
+
+ + + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+response = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=16000,
+    thinking={"type": "adaptive"},
+    messages=[
+        {
+            "role": "user",
+            "content": "Explique por que a soma de dois números pares é sempre par.",
+        }
+    ],
+)
+
+for block in response.content:
+    if block.type == "thinking":
+        print(f"\nPensamento: {block.thinking}")
+    elif block.type == "text":
+        print(f"\nResposta: {block.text}")
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const response = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 16000,
+  thinking: { type: "adaptive" },
+  messages: [
+    { role: "user", content: "Explique por que a soma de dois números pares é sempre par." },
+  ],
+});
+
+for (const block of response.content) {
+  if (block.type === "thinking") console.log(`\nPensamento: ${block.thinking}`);
+  else if (block.type === "text") console.log(`\nResposta: ${block.text}`);
+}
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 16000,
+    "thinking": { "type": "adaptive" },
+    "messages": [
+      { "role": "user", "content": "Explique por que a soma de dois números pares é sempre par." }
+    ]
+  }'
+
+
+ +

1.4. Adaptive thinking com o parâmetro effort

+

Combine thinking: {type:"adaptive"} com output_config.effort para guiar (orientação soft) quanto o Claude raciocina. O effort só existe junto de adaptive thinking — portanto em claude-opus-4-8 e claude-sonnet-4-6; o claude-haiku-4-5 não o suporta (use budget_tokens). Para o panorama de capacidades por modelo, veja Modelos Claude (Parte A).

+
+ + + + + + + + +
effortComportamento de raciocínio
maxSempre raciocina, sem restrição de profundidade. Em claude-opus-4-8 e claude-sonnet-4-6.
xhighSempre raciocina profundamente com exploração estendida. Disponível em claude-opus-4-8.
high (padrão)Sempre raciocina. Raciocínio profundo em tarefas complexas.
mediumRaciocínio moderado; pode pular pensamento em perguntas muito simples.
lowMinimiza o raciocínio; pula o pensamento em tarefas simples onde a velocidade importa.
+
+
+ + + +
+
+
response = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=16000,
+    thinking={"type": "adaptive"},
+    output_config={"effort": "medium"},
+    messages=[{"role": "user", "content": "Qual é a capital da França?"}],
+)
+print(response.content[0].text)
+
+
+
const response = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 16000,
+  thinking: { type: "adaptive" },
+  output_config: { effort: "medium" },
+  messages: [{ role: "user", content: "Qual é a capital da França?" }],
+});
+console.log(response.content[0].text);
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 16000,
+    "thinking": { "type": "adaptive" },
+    "output_config": { "effort": "medium" },
+    "messages": [ { "role": "user", "content": "Qual é a capital da França?" } ]
+  }'
+
+
+ +

1.5. Considerações importantes

+
    +
  • Interleaved thinking automático: o modo adaptive ativa automaticamente o raciocínio intercalado entre chamadas de ferramenta — ideal para fluxos agênticos. No Opus 4.8, o raciocínio entre ferramentas sempre vive dentro de blocos thinking.
  • +
  • Validação mais flexível: turnos anteriores do assistente não precisam começar com um bloco thinking (no modo manual a API exige isso).
  • +
  • Prompt caching: requisições consecutivas com o mesmo modo (adaptive) preservam os breakpoints de cache. Alternar entre adaptive e enabled/disabled quebra os breakpoints das mensagens (system prompt e definições de ferramenta continuam em cache).
  • +
  • Display padrão no Opus 4.8: thinking.display assume "omitted" por padrão (mudança silenciosa em relação ao comportamento anterior). Para receber o resumo do pensamento, defina display: "summarized" explicitamente. Veja o capítulo 2.
  • +
  • Controle de custo: use max_tokens como limite rígido do total de saída (pensamento + texto). Em high/max o modelo pode esgotar max_tokens; se vir stop_reason: "max_tokens", aumente max_tokens ou reduza o effort.
  • +
+
Dica: o disparo do raciocínio é promptável. Se o Claude raciocina demais (ou de menos), oriente no system prompt — por exemplo: “Use raciocínio estendido apenas quando melhorar de forma significativa a qualidade da resposta; na dúvida, responda diretamente.” Meça o impacto antes de levar para produção.
+
+ + +
+

2. Extended thinking (raciocínio estendido) e blocos de pensamento

+

O extended thinking dá ao Claude uma fase de raciocínio interno antes da resposta final. Você pode controlá-lo de forma adaptativa (cap. 1) ou manual com um orçamento de tokens. Este capítulo detalha o modo manual, a exibição/criptografia dos blocos de pensamento e a preservação dos blocos entre turnos.

+ + +

2.1. Modos de raciocínio

+
+ + + + + + +
ModoConfigDisponibilidadeQuando usar
Adaptivethinking: {type: "adaptive"}claude-opus-4-8 (único modo), claude-sonnet-4-6. Não em claude-haiku-4-5.O Claude decide quando/quanto raciocinar. Use effort para guiar.
Manualthinking: {type: "enabled", budget_tokens: N}claude-sonnet-4-6 (ainda funcional) e claude-haiku-4-5 (único modo de raciocínio do Haiku). Rejeitado em claude-opus-4-8 (400).Quando você precisa de controle preciso do gasto de tokens de pensamento.
DisabledOmitir thinking ou {type: "disabled"}Todos os modelosQuando não precisa de raciocínio e quer a menor latência.
+ +

2.2. Modo manual (orçamento fixo)

+

No modo manual você define budget_tokens — o número alvo de tokens que o Claude pode usar para raciocinar. Deve ser menor que max_tokens (o max_tokens cobre pensamento + texto da resposta). Exemplo no Sonnet 4.6:

+
+
+ + + +
+
+
response = client.messages.create(
+    model="claude-sonnet-4-6",
+    max_tokens=16000,
+    thinking={"type": "enabled", "budget_tokens": 10000},
+    messages=[{"role": "user", "content": "Quantos números primos há entre 100 e 200?"}],
+)
+
+
+
const response = await client.messages.create({
+  model: "claude-sonnet-4-6",
+  max_tokens: 16000,
+  thinking: { type: "enabled", budget_tokens: 10000 },
+  messages: [{ role: "user", content: "Quantos números primos há entre 100 e 200?" }],
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-sonnet-4-6",
+    "max_tokens": 16000,
+    "thinking": { "type": "enabled", "budget_tokens": 10000 },
+    "messages": [ { "role": "user", "content": "Quantos números primos há entre 100 e 200?" } ]
+  }'
+
+
+
Nota: no Claude Opus 4.8 o modo manual enabled é rejeitado (erro 400). Use sempre adaptive + effort nesse modelo.
+ +

2.3. Thinking resumido (summarized)

+

Com extended thinking ativo, a Messages API retorna um resumo do raciocínio completo (não o texto bruto de pensamento), preservando os ganhos de inteligência e prevenindo uso indevido. Pontos-chave:

+
    +
  • Você é cobrado pelos tokens completos de pensamento gerados, não pelos tokens do resumo. A contagem de tokens de saída faturada não bate com os tokens visíveis na resposta.
  • +
  • A sumarização é feita por um modelo diferente do que você chamou; o modelo de raciocínio não vê o resumo.
  • +
  • O resumo preserva as ideias-chave com latência adicional mínima e é streamável.
  • +
+ +

2.4. Controlando a exibição: thinking.display

+

O campo display controla como o conteúdo de pensamento volta na resposta:

+
+ + + + + +
ValorComportamentoPadrão em
"summarized"Blocos contêm o texto resumido do pensamento.Sonnet 4.6 e modelos Claude 4 anteriores
"omitted"Blocos voltam com thinking vazio; o campo signature ainda carrega o pensamento completo criptografado para continuidade multi-turno.claude-opus-4-8
+
Atenção: no claude-opus-4-8, display é "omitted" por padrão — os blocos de pensamento aparecem no stream, mas com thinking vazio. Para receber o resumo, defina explicitamente display: "summarized". display é inválido com thinking.type: "disabled". Mesmo com "omitted", você continua sendo cobrado pelos tokens completos de pensamento — omitir reduz latência, não custo.
+
# Restaurar resumo do pensamento no Opus 4.8:
+thinking = {"type": "adaptive", "display": "summarized"}
+
+# Omitir (default no Opus 4.8) — menor time-to-first-text-token no streaming:
+thinking = {"type": "adaptive", "display": "omitted"}
+ +

2.5. Criptografia e signature

+

O conteúdo completo de pensamento é criptografado e devolvido no campo signature, usado para verificar que os blocos foram gerados pelo Claude quando você os reenvia. Considerações:

+
    +
  • No streaming, a signature chega via signature_delta dentro de um content_block_delta, logo antes do content_block_stop.
  • +
  • signature é um campo opaco — não interprete nem faça parsing.
  • +
  • Valores de signature são compatíveis entre plataformas (Claude API, Amazon Bedrock e Vertex AI).
  • +
+
Nota: só é estritamente necessário reenviar blocos de pensamento quando se usa ferramentas com extended thinking (ver capítulo 3). Caso reenvie, passe tudo exatamente como recebeu.
+ +

2.6. Redacted thinking

+

Ocasionalmente o raciocínio interno é sinalizado pelos sistemas de segurança e volta criptografado como um bloco redacted_thinking (em vez de thinking). Ele é decriptado quando reenviado ao modelo. Trate-o como um bloco normal: reenvie-o sem modificação em conversas multi-turno; ele não afeta a qualidade das respostas.

+ +

2.7. Preservação de blocos de pensamento entre turnos

+

Se você reenvia blocos de pensamento, o que a API mantém em contexto depende do modelo:

+
+ + + + + + +
ModeloBlocos de pensamento de turnos anteriores
claude-opus-4-8Mantidos em contexto por padrão (todos os turnos).
claude-sonnet-4-6Mantidos em contexto por padrão (todos os turnos).
claude-haiku-4-5Removidos (stripped) por padrão.
+

Use context editing para configurar esse comportamento. O faturamento de tokens de pensamento mantidos em contexto conta como tokens de input nos turnos seguintes.

+ +

2.8. max_tokens, janela de contexto e stop_reason

+

O max_tokens limita o total de saída (pensamento + texto). Se o raciocínio mais a resposta atingirem o limite, a resposta volta com stop_reason: "max_tokens" e o texto pode ficar truncado. Em effort alto, deixe folga em max_tokens. Sobre o tamanho da janela e a contabilidade de tokens, veja janelas de contexto; sobre os demais valores de término, veja stop_reason (Parte A).

+
+ + +
+

3. Raciocínio com uso de ferramentas (extended thinking + tool use)

+

Ao combinar raciocínio com tool use, há uma regra central: você deve reenviar os blocos de pensamento do turno do assistente — sem modificá-los — junto com o bloco tool_use, para que o Claude continue o raciocínio de onde parou ao receber o tool_result.

+ + +

3.1. O ciclo com preservação de pensamento

+
    +
  1. Você envia a mensagem do usuário com thinking ativo e as tools definidas.
  2. +
  3. O assistente responde com um ou mais blocos thinking seguidos de um bloco tool_use (stop_reason: "tool_use").
  4. +
  5. Você executa a ferramenta e devolve um turno user com o bloco tool_result.
  6. +
  7. No próximo turno do assistente, você reenvia o turno anterior do assistente incluindo os blocos de pensamento intactos (com sua signature).
  8. +
+
Atenção: não edite, reordene nem remova os blocos de pensamento ao reenviá-los. A API valida a signature; alterações causam erro. No claude-opus-4-8 (e no modo adaptive em geral), o interleaved thinking é automático — o Claude pode raciocinar entre múltiplas chamadas de ferramenta.
+ +

3.2. Exemplo: continuação após tool_result

+
+
+ + + +
+
+
tools = [{
+    "name": "get_weather",
+    "description": "Obtém o clima atual de uma cidade.",
+    "input_schema": {
+        "type": "object",
+        "properties": {"city": {"type": "string"}},
+        "required": ["city"],
+    },
+}]
+
+# 1) Primeira chamada — Claude raciocina e pede a ferramenta
+first = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=16000,
+    thinking={"type": "adaptive"},
+    tools=tools,
+    messages=[{"role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?"}],
+)
+
+# 2) Execute a ferramenta e devolva o turno do assistente INTACTO (com os blocos thinking)
+tool_use = next(b for b in first.content if b.type == "tool_use")
+second = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=16000,
+    thinking={"type": "adaptive"},
+    tools=tools,
+    messages=[
+        {"role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?"},
+        {"role": "assistant", "content": first.content},  # blocos thinking + tool_use preservados
+        {
+            "role": "user",
+            "content": [{
+                "type": "tool_result",
+                "tool_use_id": tool_use.id,
+                "content": "Chuva forte prevista para a tarde.",
+            }],
+        },
+    ],
+)
+print(second.content[-1].text)
+
+
+
const tools = [{
+  name: "get_weather",
+  description: "Obtém o clima atual de uma cidade.",
+  input_schema: {
+    type: "object",
+    properties: { city: { type: "string" } },
+    required: ["city"],
+  },
+}];
+
+const first = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 16000,
+  thinking: { type: "adaptive" },
+  tools,
+  messages: [{ role: "user", content: "Devo levar guarda-chuva em São Paulo hoje?" }],
+});
+
+const toolUse = first.content.find((b) => b.type === "tool_use");
+const second = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 16000,
+  thinking: { type: "adaptive" },
+  tools,
+  messages: [
+    { role: "user", content: "Devo levar guarda-chuva em São Paulo hoje?" },
+    { role: "assistant", content: first.content }, // thinking + tool_use intactos
+    {
+      role: "user",
+      content: [{
+        type: "tool_result",
+        tool_use_id: toolUse.id,
+        content: "Chuva forte prevista para a tarde.",
+      }],
+    },
+  ],
+});
+
+
+
# O turno do assistente (content) deve conter os blocos thinking originais
+# com sua signature, seguidos do bloco tool_use, e depois o tool_result do usuário.
+curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 16000,
+    "thinking": { "type": "adaptive" },
+    "tools": [ { "name": "get_weather", "input_schema": {"type":"object","properties":{"city":{"type":"string"}},"required":["city"]} } ],
+    "messages": [
+      { "role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?" },
+      { "role": "assistant", "content": [ {"type":"thinking","thinking":"...","signature":"..."}, {"type":"tool_use","id":"toolu_01","name":"get_weather","input":{"city":"São Paulo"}} ] },
+      { "role": "user", "content": [ {"type":"tool_result","tool_use_id":"toolu_01","content":"Chuva forte prevista para a tarde."} ] }
+    ]
+  }'
+
+
+ +

3.3. Interleaved thinking

+

O interleaved thinking permite ao Claude raciocinar entre chamadas de ferramenta — refletindo sobre o resultado de uma ferramenta antes de decidir a próxima. Disponibilidade:

+
+ + + + + +
ConfiguraçãoInterleaved thinking
Adaptive em claude-opus-4-8 / claude-sonnet-4-6Automático (sem header beta).
Manual (enabled) em claude-sonnet-4-6Via header anthropic-beta: interleaved-thinking-2025-05-14.
+ +

3.4. tool_choice e raciocínio

+

Quando o raciocínio está ativo, há limitações com tool_choice: você não pode forçar uma ferramenta específica (tool_choice: {type: "tool", ...}) nem tool_choice: {type: "any"} de forma incompatível com o pensamento. Use tool_choice: {type: "auto"} (padrão) com raciocínio ativo e deixe o Claude decidir.

+
+ + +
+

4. Orçamentos de tarefa (task budgets)

+

Os task budgets definem um teto de tokens para uma tarefa inteira — somando múltiplas requisições/turnos de um fluxo agêntico — em vez de limitar token a token por chamada. Servem para controlar custo e horizonte de tarefas longas com ferramentas.

+ +

Beta Requer o header anthropic-beta: task-budgets-2026-03-13 (verificado em 2026-06-10). Apenas Claude Opus 4.8 — não suportado em Sonnet 4.6 nem Haiku 4.5. Defina output_config.task_budget = {"type":"tokens","total": N} (campo opcional remaining para retomar após compactação). O mínimo é 20.000 tokens (valores menores retornam 400); o orçamento é advisory (hint suave), enquanto max_tokens continua sendo o teto rígido por requisição.

+ +

4.1. Como usar

+

Defina output_config.task_budget com o tipo e o total. Combine com effort para orientar a alocação de raciocínio dentro do orçamento. No SDK Python, use o namespace client.beta.messages e passe betas=[...].

+
+
+ + + +
+
+
message = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=16000,
+    thinking={"type": "adaptive"},
+    output_config={
+        "effort": "high",
+        "task_budget": {"type": "tokens", "total": 64000},
+    },
+    betas=["task-budgets-2026-03-13"],
+    messages=[{"role": "user", "content": "Refatore este módulo e rode os testes."}],
+)
+
+
+
const message = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 16000,
+  thinking: { type: "adaptive" },
+  output_config: {
+    effort: "high",
+    task_budget: { type: "tokens", total: 64000 },
+  },
+  betas: ["task-budgets-2026-03-13"],
+  messages: [{ role: "user", content: "Refatore este módulo e rode os testes." }],
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "anthropic-beta: task-budgets-2026-03-13" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 16000,
+    "thinking": { "type": "adaptive" },
+    "output_config": {
+      "effort": "high",
+      "task_budget": { "type": "tokens", "total": 64000 }
+    },
+    "messages": [ { "role": "user", "content": "Refatore este módulo e rode os testes." } ]
+  }'
+
+
+
Dica: diferencie os três controles: max_tokens limita a saída de uma requisição; task_budget limita o consumo da tarefa toda (várias requisições); effort é orientação soft de quanto raciocinar. Use os três juntos para custo previsível em agentes de horizonte longo.
+
+ + +
+

5. Prompt caching (cache de prompt)

+

O prompt caching permite reutilizar prefixos grandes e estáveis do prompt (system prompt extenso, definições de ferramenta, documentos, exemplos few-shot) entre requisições, cortando custo e latência drasticamente. Você marca pontos de cache (breakpoints) com cache_control.

+ + +

5.1. Mínimos de tokens cacheáveis (por modelo)

+

Prompts menores que o mínimo são processados sem cache e nenhum erro é retornado. Verifique usage.cache_creation_input_tokens e usage.cache_read_input_tokens: se ambos forem 0, o prompt não foi cacheado.

+
+ + + + + + +
ModeloMínimo de tokens cacheáveis
claude-opus-4-84.096 tokens
claude-sonnet-4-61.024 tokens
claude-haiku-4-54.096 tokens
+ +

5.2. TTL e preços

+
+ + + + + + +
Tipo de tokenMultiplicador vs. preço base de input
Cache write (TTL 5 min, padrão)1,25× (refrescado sem custo extra a cada uso)
Cache write (TTL 1 h)2× (opt-in com "ttl": "1h")
Cache hit / refresh (read)0,1× (10% do preço base)
+

Exemplo para claude-opus-4-8 ($5/MTok base): cache write 5m = $6,25/MTok; cache write 1h = $10/MTok; cache read = $0,50/MTok.

+ +

5.3. Caching automático (breakpoint no nível superior)

+

Adicione um único cache_control no nível superior do corpo da requisição. A API aplica o breakpoint ao último bloco cacheável e move o breakpoint para a frente automaticamente conforme a conversa cresce.

+
+
+ + + +
+
+
response = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    cache_control={"type": "ephemeral"},  # breakpoint automático no último bloco cacheável
+    system="Você é um assistente jurídico... (system prompt longo e estável)",
+    messages=[{"role": "user", "content": "Resuma o contrato anexo."}],
+)
+print(response.usage.cache_creation_input_tokens, response.usage.cache_read_input_tokens)
+
+
+
const response = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  cache_control: { type: "ephemeral" }, // breakpoint automático
+  system: "Você é um assistente jurídico... (system prompt longo e estável)",
+  messages: [{ role: "user", content: "Resuma o contrato anexo." }],
+});
+console.log(response.usage.cache_creation_input_tokens, response.usage.cache_read_input_tokens);
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "cache_control": { "type": "ephemeral" },
+    "system": "Você é um assistente jurídico... (system prompt longo e estável)",
+    "messages": [ { "role": "user", "content": "Resuma o contrato anexo." } ]
+  }'
+
+
+
Nota: caching automático está disponível na Claude API e na Claude Platform na AWS / Microsoft Foundry (beta). Não é suportado em Amazon Bedrock nem Vertex AI (use breakpoints explícitos lá).
+ +

5.4. Breakpoints explícitos em blocos de conteúdo

+

Para controle fino, coloque cache_control diretamente em blocos específicos (system, tools, document, etc.). Há no máximo 4 breakpoints por requisição. Tudo antes de um breakpoint (inclusive) entra no prefixo cacheável.

+
{
+  "model": "claude-opus-4-8",
+  "max_tokens": 1024,
+  "tools": [ { "name": "...", "cache_control": { "type": "ephemeral" } } ],
+  "system": [
+    { "type": "text", "text": "Instruções base..." },
+    { "type": "text", "text": "Base de conhecimento longa...", "cache_control": { "type": "ephemeral" } }
+  ],
+  "messages": [ { "role": "user", "content": "..." } ]
+}
+ +

5.5. TTL de 1 hora

+
{ "cache_control": { "type": "ephemeral", "ttl": "1h" } }
+

Útil para prefixos reaproveitados ao longo de minutos a uma hora (ex.: documento grande consultado várias vezes). Custa 2× o input base na escrita, mas economiza em muitas leituras subsequentes (0,1×).

+ +

5.6. Pré-aquecimento (pre-warming) do cache

+

Para garantir que o prefixo já esteja em cache antes do primeiro uso real, faça uma requisição de aquecimento com max_tokens mínimo. Isso paga a escrita do cache uma vez e deixa as leituras seguintes baratas.

+
# Aquece o cache do prefixo sem gerar resposta longa
+client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1,
+    cache_control={"type": "ephemeral"},
+    system="... prefixo grande e estável ...",
+    messages=[{"role": "user", "content": "ok"}],
+)
+ +

5.7. Pegadinhas (edge cases)

+
    +
  • Se o último bloco já tem cache_control explícito com o mesmo TTL do automático → no-op.
  • +
  • Se o último bloco tem cache_control explícito com TTL diferente → erro 400.
  • +
  • Se os 4 slots de breakpoint explícito já estão usados → erro 400 ao adicionar o automático.
  • +
  • Misturar TTLs: você pode ter breakpoints de 5m e 1h na mesma requisição, mas planeje a ordem (o prefixo mais estável com TTL maior).
  • +
+
Atenção: mudanças antes de um breakpoint invalidam o cache daquele ponto em diante. Mantenha conteúdo volátil (a pergunta do usuário) depois dos breakpoints e conteúdo estável (system, tools, documentos) antes.
+
+ + +
+

6. Diagnóstico de cache (cache diagnostics)

+

Quando o cache não está acertando como esperado, os diagnósticos de cache explicam por que houve cache miss, comparando a requisição atual com a anterior e apontando o primeiro ponto de divergência (modelo, system prompt, tools ou histórico de mensagens).

+ +

Beta Requer o header anthropic-beta: cache-diagnosis-2026-04-07 (verificado em 2026-05-24). Passe o id da resposta anterior em diagnostics.previous_message_id; a API retorna um objeto diagnostics descrevendo a divergência. Disponível apenas na Claude API — não suportado em Amazon Bedrock nem Vertex AI.

+ +

6.1. Como usar

+

Passe diagnostics com o previous_message_id da requisição anterior (ou None na primeira). A resposta inclui um cache_miss_reason indicando onde o prefixo divergiu.

+
+
+ + + +
+
+
message = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    diagnostics={"previous_message_id": None},  # ou o id da resposta anterior
+    betas=["cache-diagnosis-2026-04-07"],
+    cache_control={"type": "ephemeral"},
+    system="... prefixo grande ...",
+    messages=[{"role": "user", "content": "Continue."}],
+)
+# Inspecione o motivo de eventual cache miss
+print(getattr(message, "cache_miss_reason", None))
+
+
+
const message = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  diagnostics: { previous_message_id: null }, // ou o id da resposta anterior
+  betas: ["cache-diagnosis-2026-04-07"],
+  cache_control: { type: "ephemeral" },
+  system: "... prefixo grande ...",
+  messages: [{ role: "user", content: "Continue." }],
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "anthropic-beta: cache-diagnosis-2026-04-07" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "diagnostics": { "previous_message_id": null },
+    "cache_control": { "type": "ephemeral" },
+    "system": "... prefixo grande ...",
+    "messages": [ { "role": "user", "content": "Continue." } ]
+  }'
+
+
+
Dica: as causas mais comuns de cache miss são: alterar conteúdo antes de um breakpoint, alternar o modo de thinking (adaptive ↔ enabled/disabled) nas mensagens, ou ficar abaixo do mínimo de tokens cacheáveis do modelo. Use o cache_miss_reason para localizar exatamente o ponto de divergência.
+
+ + +
+

7. Edição de contexto (context editing)

+

A edição de contexto remove automaticamente conteúdo antigo da janela quando ela cresce demais — por exemplo, resultados de ferramentas já consumidos e blocos de pensamento antigos — preservando os mais recentes. Mantém agentes de horizonte longo dentro da janela sem você gerenciar o histórico manualmente.

+ +

Beta Requer o header anthropic-beta: context-management-2025-06-27.

+ +

7.1. Tipos de edição

+
+ + + + + +
Tipo de editO que limpa
clear_tool_uses_20250919Resultados de uso de ferramentas (tool_use/tool_result) antigos.
clear_thinking_20251015Blocos de pensamento (thinking) antigos.
+ +

7.2. Parâmetros de um edit clear_tool_uses

+
+ + + + + + + +
CampoDescrição
triggerQuando acionar a limpeza, ex. {"type": "input_tokens", "value": 30000}.
keepQuanto preservar, ex. {"type": "tool_uses", "value": 3} (mantém os 3 usos de ferramenta mais recentes).
clear_at_leastMínimo a limpar por acionamento (evita limpezas insignificantes).
exclude_toolsLista de ferramentas cujos resultados nunca devem ser limpos.
+ +

7.3. Exemplo

+
+
+ + + +
+
+
message = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=16000,
+    betas=["context-management-2025-06-27"],
+    context_management={
+        "edits": [
+            {
+                "type": "clear_tool_uses_20250919",
+                "trigger": {"type": "input_tokens", "value": 30000},
+                "keep": {"type": "tool_uses", "value": 3},
+                "clear_at_least": {"type": "input_tokens", "value": 5000},
+                "exclude_tools": ["get_critical_state"],
+            },
+            {"type": "clear_thinking_20251015"},
+        ]
+    },
+    tools=[...],
+    messages=[...],
+)
+
+
+
const message = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 16000,
+  betas: ["context-management-2025-06-27"],
+  context_management: {
+    edits: [
+      {
+        type: "clear_tool_uses_20250919",
+        trigger: { type: "input_tokens", value: 30000 },
+        keep: { type: "tool_uses", value: 3 },
+        clear_at_least: { type: "input_tokens", value: 5000 },
+        exclude_tools: ["get_critical_state"],
+      },
+      { type: "clear_thinking_20251015" },
+    ],
+  },
+  tools: [/* ... */],
+  messages: [/* ... */],
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "anthropic-beta: context-management-2025-06-27" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 16000,
+    "context_management": {
+      "edits": [
+        {
+          "type": "clear_tool_uses_20250919",
+          "trigger": { "type": "input_tokens", "value": 30000 },
+          "keep": { "type": "tool_uses", "value": 3 },
+          "clear_at_least": { "type": "input_tokens", "value": 5000 },
+          "exclude_tools": ["get_critical_state"]
+        },
+        { "type": "clear_thinking_20251015" }
+      ]
+    },
+    "messages": [ ... ]
+  }'
+
+
+
Atenção: limpar conteúdo invalida os breakpoints de cache a partir do ponto editado, pois o prefixo muda. Posicione o context editing levando em conta o cache. Use exclude_tools para nunca descartar resultados de ferramentas que carregam estado crítico (ex.: identificadores ou saldos que o agente ainda precisará).
+
+ + +
+

8. Compactação de contexto (compaction)

+

A compaction resume automaticamente o histórico antigo da conversa em uma forma condensada quando o contexto cresce, preservando as informações essenciais e liberando espaço — diferente do context editing, que remove blocos; a compaction resume. Sobre o tamanho da janela de contexto que esses mecanismos protegem, veja a Parte A.

+ +

Beta Requer o header anthropic-beta: compact-2026-01-12 (verificado em 2026-05-24). É distinto do header de context editing context-management-2025-06-27.

+ +

8.1. Como usar

+

Adicione um edit do tipo compact_20260112 em context_management.edits. A compaction pode coexistir com edits de limpeza (cap. 7).

+
+
+ + + +
+
+
message = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=16000,
+    betas=["compact-2026-01-12"],
+    context_management={"edits": [{"type": "compact_20260112"}]},
+    messages=[...],  # histórico longo de conversa agêntica
+)
+
+
+
const message = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 16000,
+  betas: ["compact-2026-01-12"],
+  context_management: { edits: [{ type: "compact_20260112" }] },
+  messages: [/* histórico longo */],
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "anthropic-beta: compact-2026-01-12" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 16000,
+    "context_management": { "edits": [ { "type": "compact_20260112" } ] },
+    "messages": [ ... ]
+  }'
+
+
+
Dica: use compaction para agentes que rodam por muitas dezenas de turnos (programação, pesquisa, automação) onde o histórico bruto explodiria a janela mas o significado precisa ser preservado. Para contextos onde só os blocos recentes importam e os antigos podem ser descartados sem resumir, prefira context editing (mais barato). Os dois podem ser combinados.
+
+ + +
+

9. Visão (entendimento de imagens)

+

As capacidades de visão deixam o Claude entender e analisar imagens: descrever cenas, ler texto, interpretar gráficos/diagramas, comparar várias imagens e dar suporte a computer use e leitura de telas.

+ + +

9.1. Limites

+
+ + + + + + + + +
LimiteValor
Imagens por requisição (API, modelos com janela de 200k)100
Imagens por requisição (API, demais modelos)600
Dimensões máximas por imagem8000×8000 px (reduz para 2000×2000 px se > 20 imagens na requisição)
Formatos suportadosJPEG, PNG, GIF, WebP (animações: só o 1º frame é usado)
Tamanho máximo da requisição32 MB (endpoints padrão; menor em algumas plataformas parceiras)
+
Nota: mesmo com a Files API, requisições com muitas imagens grandes podem falhar antes de atingir 600 imagens por causa do limite de tamanho do payload. Reduza dimensões/tamanho (downsampling) ou referencie por file_id.
+ +

9.2. Custo de tokens por imagem

+

Uma imagem usa aproximadamente width * height / 750 tokens (em pixels). Se exceder a resolução nativa do modelo, é redimensionada preservando o aspect ratio e preenchida (padding) até múltiplos de 28 px.

+
+ + + + + +
ModeloResolução nativa máximaTokens máximos por imagem
claude-opus-4-8até 2576 px na borda longa~4784 tokens (alta resolução)
claude-sonnet-4-6 / claude-haiku-4-5até 1568 px na borda longa~1568 tokens
+
Dica: o suporte a alta resolução (até 2576 px na borda longa) foi introduzido no Opus 4.7 e segue no claude-opus-4-8 — automático e sem header beta — ótimo para computer use, leitura de screenshots e análise de documentos. Mas pode usar até ~3× mais tokens por imagem (4784 vs. 1568). Se não precisa da fidelidade extra, faça downsampling antes de enviar para controlar custo.
+ +

9.3. Fontes de imagem e exemplo

+

Há três formas de fornecer imagens: base64, url e file (via Files API — ver capítulo 11). Coloque imagens antes do texto para melhores resultados.

+
+
+ + + +
+
+
import anthropic, base64, httpx
+
+client = anthropic.Anthropic()
+
+url = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
+img_data = base64.standard_b64encode(httpx.get(url).content).decode("utf-8")
+
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": img_data}},
+            {"type": "text", "text": "O que há nesta imagem?"},
+        ],
+    }],
+)
+print(message.content[0].text)
+
+
+
// Opção mais simples: imagem por URL
+const message = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "image", source: { type: "url", url: "https://exemplo.com/foto.jpg" } },
+      { type: "text", text: "O que há nesta imagem?" },
+    ],
+  }],
+});
+console.log(message.content[0].text);
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{
+      "role": "user",
+      "content": [
+        { "type": "image", "source": { "type": "url", "url": "https://exemplo.com/foto.jpg" } },
+        { "type": "text", "text": "O que há nesta imagem?" }
+      ]
+    }]
+  }'
+
+
+
Nota: em Amazon Bedrock e Vertex AI, apenas fontes base64 estão disponíveis atualmente. Ao pedir coordenadas (pontos, bounding boxes), elas vêm em relação à imagem redimensionada/com padding — reescale no cliente.
+
+ + +
+

10. Suporte a PDF

+

O Claude processa PDFs entendendo texto e elementos visuais (gráficos, tabelas, diagramas): cada página é convertida em imagem e tem o texto extraído, e o modelo analisa ambos. Útil para relatórios financeiros, documentos jurídicos, tradução e extração estruturada.

+ + +

10.1. Requisitos e limites

+
+ + + + + + +
RequisitoLimite
Tamanho máximo da requisição32 MB (varia por plataforma)
Máximo de páginas por requisição600 (100 para modelos com janela de 200k tokens)
FormatoPDF padrão, sem senha/criptografia
+

Os limites valem para o payload inteiro (PDF + qualquer outro conteúdo). Como o suporte a PDF usa as capacidades de visão, está sujeito às mesmas limitações da visão. Todos os modelos ativos suportam PDF.

+ +

10.2. Custo (estimativa de tokens)

+
    +
  • Texto: tipicamente 1.500–3.000 tokens por página, conforme densidade. Sem taxa adicional de PDF.
  • +
  • Imagem: como cada página vira imagem, aplica-se o mesmo cálculo de tokens da visão.
  • +
+
Atenção: PDFs densos (fontes pequenas, tabelas complexas, muitos gráficos) podem encher a janela de contexto antes de atingir o limite de páginas. Divida o documento em seções; para arquivos grandes, faça downsampling das imagens embutidas. Use a Files API para manter o payload pequeno.
+ +

10.3. Três formas de enviar um PDF

+

Via url, base64 ou file_id (Files API). Coloque o PDF antes do texto.

+
+
+ + + +
+
+
# Opção 1: PDF por URL (mais simples)
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {"type": "url", "url": "https://exemplo.com/relatorio.pdf"}},
+            {"type": "text", "text": "Quais são as conclusões principais deste documento?"},
+        ],
+    }],
+)
+print(message.content)
+
+
+
// Opção 1: PDF por URL
+const response = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "document", source: { type: "url", url: "https://exemplo.com/relatorio.pdf" } },
+      { type: "text", text: "Quais são as conclusões principais deste documento?" },
+    ],
+  }],
+});
+console.log(response);
+
+
+
# Opção 2: PDF em base64
+curl https://api.anthropic.com/v1/messages \
+  -H "content-type: application/json" \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -d '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{
+      "role": "user",
+      "content": [
+        { "type": "document", "source": { "type": "base64", "media_type": "application/pdf", "data": "JVBERi0xLj..." } },
+        { "type": "text", "text": "Quais são as conclusões principais deste documento?" }
+      ]
+    }]
+  }'
+
+
+ +

10.4. PDF via Files API + prompt caching

+

Para PDFs reutilizados, faça upload uma vez (Files API, cap. 11) e referencie por file_id; combine com prompt caching colocando cache_control no bloco document.

+
# PDF via Files API (beta) — depois referencie por file_id
+with open("relatorio.pdf", "rb") as f:
+    up = client.beta.files.upload(file=("relatorio.pdf", f, "application/pdf"))
+
+message = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    betas=["files-api-2025-04-14"],
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {"type": "file", "file_id": up.id},
+             "cache_control": {"type": "ephemeral"}},
+            {"type": "text", "text": "Resuma o documento."},
+        ],
+    }],
+)
+
Nota: em Amazon Bedrock e Vertex AI, apenas fontes base64 estão disponíveis. No Bedrock Converse API, a análise visual completa do PDF exige citações habilitadas; sem isso, há apenas extração de texto.
+
+ + +
+

11. Files API

+

A Files API permite fazer upload de arquivos (PDFs, imagens, e outros formatos) uma vez e referenciá-los por file_id em várias requisições — evitando reenviar base64, reduzindo o payload e a latência.

+ +

Beta Requer o header anthropic-beta: files-api-2025-04-14. No SDK, use o namespace client.beta.files e passe betas=["files-api-2025-04-14"] nas chamadas de mensagem.

+ +

11.1. Upload e uso

+
+
+ + + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+# 1) Upload
+with open("document.pdf", "rb") as f:
+    file_upload = client.beta.files.upload(file=("document.pdf", f, "application/pdf"))
+
+# 2) Referencie por file_id em uma mensagem
+message = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    betas=["files-api-2025-04-14"],
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {"type": "file", "file_id": file_upload.id}},
+            {"type": "text", "text": "Quais são as conclusões principais?"},
+        ],
+    }],
+)
+print(message.content)
+
+
+
import Anthropic, { toFile } from "@anthropic-ai/sdk";
+import fs from "fs";
+
+const anthropic = new Anthropic();
+
+// 1) Upload
+const fileUpload = await anthropic.beta.files.upload({
+  file: await toFile(fs.createReadStream("document.pdf"), undefined, { type: "application/pdf" }),
+});
+
+// 2) Referencie por file_id
+const response = await anthropic.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  betas: ["files-api-2025-04-14"],
+  messages: [{
+    role: "user",
+    content: [
+      { type: "document", source: { type: "file", file_id: fileUpload.id } },
+      { type: "text", text: "Quais são as conclusões principais?" },
+    ],
+  }],
+});
+console.log(response);
+
+
+
# 1) Upload
+curl -X POST https://api.anthropic.com/v1/files \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: files-api-2025-04-14" \
+  -F "file=@document.pdf"
+
+# 2) Use o file_id retornado
+curl https://api.anthropic.com/v1/messages \
+  -H "content-type: application/json" \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: files-api-2025-04-14" \
+  -d '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{
+      "role": "user",
+      "content": [
+        { "type": "document", "source": { "type": "file", "file_id": "file_abc123" } },
+        { "type": "text", "text": "Quais são as conclusões principais?" }
+      ]
+    }]
+  }'
+
+
+ +

11.2. Operações de gerenciamento

+
+ + + + + + + + +
OperaçãoEndpoint / SDK
UploadPOST /v1/files · client.beta.files.upload(...)
ListarGET /v1/files · client.beta.files.list()
MetadadosGET /v1/files/{file_id} · client.beta.files.retrieve_metadata(file_id)
Baixar conteúdoGET /v1/files/{file_id}/content · client.beta.files.download(file_id)
ExcluirDELETE /v1/files/{file_id} · client.beta.files.delete(file_id)
+
Dica: além de PDFs e imagens, a Files API aceita outros formatos (.csv, .xlsx, .docx, .md, .txt) — veja “Working with other file formats” na doc de Files. Para conteúdo reutilizado em muitas requisições, Files API + prompt caching é a combinação mais econômica.
+
+ + +
+

12. Citações e resultados de busca (citations & search results)

+

As citações fazem o Claude fundamentar afirmações em trechos exatos das fontes que você forneceu (documentos, PDFs, resultados de busca), retornando referências verificáveis. Os search results são um tipo de bloco para alimentar RAG com citações nativas.

+ + +

12.1. Habilitando citações

+

Adicione "citations": {"enabled": true} ao bloco document (ou search_result). Quando habilitado, blocos de texto da resposta podem conter um array citations apontando para o local exato na fonte.

+
+
+ + + +
+
+
message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {
+                "type": "document",
+                "source": {"type": "text", "media_type": "text/plain",
+                           "data": "O céu é azul devido ao espalhamento de Rayleigh..."},
+                "title": "Por que o céu é azul",
+                "citations": {"enabled": True},
+            },
+            {"type": "text", "text": "Por que o céu é azul? Cite a fonte."},
+        ],
+    }],
+)
+for block in message.content:
+    if block.type == "text":
+        print(block.text)
+        for c in (block.citations or []):
+            print("  citação:", c)
+
+
+
const message = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{
+    role: "user",
+    content: [
+      {
+        type: "document",
+        source: { type: "text", media_type: "text/plain",
+                  data: "O céu é azul devido ao espalhamento de Rayleigh..." },
+        title: "Por que o céu é azul",
+        citations: { enabled: true },
+      },
+      { type: "text", text: "Por que o céu é azul? Cite a fonte." },
+    ],
+  }],
+});
+
+
+
curl https://api.anthropic.com/v1/messages \
+  -H "content-type: application/json" \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -d '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{
+      "role": "user",
+      "content": [
+        { "type": "document",
+          "source": { "type": "text", "media_type": "text/plain", "data": "O céu é azul devido ao espalhamento de Rayleigh..." },
+          "title": "Por que o céu é azul",
+          "citations": { "enabled": true } },
+        { "type": "text", "text": "Por que o céu é azul? Cite a fonte." }
+      ]
+    }]
+  }'
+
+
+ +

12.2. Tipos de localização de citação

+
+ + + + + + + +
TipoFonteCampos de localização
char_locationDocumento de texto simplesstart_char_index, end_char_index
page_locationPDFstart_page_number, end_page_number
content_block_locationDocumento de conteúdo customizado (lista de blocos)start_block_index, end_block_index
search_result_locationBloco search_resultsearch_result_index, start_block_index, end_block_index
+

Cada citação inclui também o cited_text (o trecho exato citado) e o document_index/título, permitindo renderizar referências clicáveis.

+ +

12.3. Search results (RAG com citações nativas)

+

O bloco search_result representa um resultado de busca/recuperação que o Claude pode citar nativamente. Há dois jeitos de fornecê-los:

+
    +
  • Método 1 — retorno de ferramenta: uma ferramenta de busca devolve blocos search_result dentro do tool_result.
  • +
  • Método 2 — conteúdo de usuário no nível superior: você inclui blocos search_result diretamente no content de uma mensagem do usuário.
  • +
+

Schema do bloco search_result:

+
{
+  "type": "search_result",
+  "source": "https://exemplo.com/artigo",
+  "title": "Título do resultado",
+  "content": [ { "type": "text", "text": "Trecho recuperado..." } ],
+  "citations": { "enabled": true },
+  "cache_control": { "type": "ephemeral" }
+}
+

Campos: source, title e content são obrigatórios; citations e cache_control são opcionais. O conteúdo é somente texto.

+
+
+ + +
+
+
# Método 2: search_result direto no conteúdo do usuário
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {
+                "type": "search_result",
+                "source": "https://docs.exemplo.com/api/auth",
+                "title": "Guia de autenticação",
+                "content": [{"type": "text", "text": "Use o header x-api-key com sua chave de API..."}],
+                "citations": {"enabled": True},
+            },
+            {"type": "text", "text": "Como autenticar? Cite a fonte."},
+        ],
+    }],
+)
+
+
+
curl https://api.anthropic.com/v1/messages \
+  -H "content-type: application/json" \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -d '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{
+      "role": "user",
+      "content": [
+        { "type": "search_result",
+          "source": "https://docs.exemplo.com/api/auth",
+          "title": "Guia de autenticação",
+          "content": [ { "type": "text", "text": "Use o header x-api-key com sua chave de API..." } ],
+          "citations": { "enabled": true } },
+        { "type": "text", "text": "Como autenticar? Cite a fonte." }
+      ]
+    }]
+  }'
+
+
+
Nota: citações em search_result são tudo-ou-nada — habilite em todos os blocos de uma mesma requisição de forma consistente. Search results estão disponíveis na Claude API, no Amazon Bedrock e no Vertex AI. O conteúdo é somente texto (sem imagens dentro do search_result).
+
Dica: use search results em vez de injetar trechos como texto puro quando precisar de citações verificáveis num pipeline RAG: o Claude referencia o índice do resultado e os blocos exatos, e você pode renderizar a fonte clicável para o usuário final.
+
+ + + + + + + + +
+

Parte C — Ferramentas (Tool Use), Skills & MCP

+

Esta parte cobre como o Claude chama ferramentas: o contrato tool_use → tool_result, a definição de ferramentas client-side e server-side, o catálogo completo de ferramentas fornecidas pela Anthropic (bash, text editor, computer use, memory, code execution, web search, web fetch, tool search, advisor), os recursos avançados (uso paralelo, chamada programática, modo estrito, streaming refinado, gerenciamento de contexto, combinações, prompt caching), as Agent Skills (SKILL.md + recursos, com divulgação progressiva) e o Model Context Protocol (MCP connector, servidores remotos e MCP tunnels).

+
+ + + + +
+

1. Tool use — como funciona

+ + +

Tool use (uso de ferramentas / function calling) permite que o Claude chame funções que você define ou que a Anthropic fornece. O Claude decide quando chamar uma ferramenta com base no pedido do usuário e na description da ferramenta; ele então devolve uma chamada estruturada que sua aplicação executa (ferramentas client-side) ou que a Anthropic executa (ferramentas server-side). O modelo nunca executa nada por conta própria: ele emite uma requisição estruturada, alguém roda a operação, e o resultado volta para a conversa.

+ +
Nota: esse contrato faz o modelo se comportar menos como um gerador de texto e mais como uma função que você chama. A diferença é que quem decide qual função invocar é um modelo de linguagem, com base na conversa. Se você está escrevendo regex para extrair uma decisão da saída do modelo, essa decisão deveria ter sido uma chamada de ferramenta.
+ +

Onde as ferramentas rodam: os três tipos

+

O eixo principal que diferencia ferramentas é onde o código executa. Toda ferramenta cai em uma de três categorias, e a categoria determina pelo que sua aplicação é responsável.

+
+ + + + + + +
CategoriaQuem executaExemplosO que você faz
Ferramentas definidas pelo usuário (client-side)Sua aplicaçãoLógica de negócio, APIs internas, consultas a bancoEscreve o schema, executa o código, devolve o tool_result. É o grosso do tráfego de tool use.
Ferramentas de schema-Anthropic (client-side)Sua aplicaçãobash, text_editor, computer, memoryMesma mecânica das definidas pelo usuário, mas o schema é treinado-no-modelo, então o Claude as chama de forma mais confiável.
Ferramentas executadas no servidorAnthropicweb_search, web_fetch, code_execution, tool_searchVocê apenas habilita a ferramenta e lê a resposta final; nunca constrói um tool_result para elas.
+ +

O loop agêntico (ferramentas client-side)

+

Ferramentas client-side (tanto as definidas pelo usuário quanto as de schema-Anthropic) exigem que sua aplicação conduza um loop. O formato canônico é um while baseado em stop_reason:

+
    +
  1. Envie uma requisição com seu array tools e a mensagem do usuário.
  2. +
  3. O Claude responde com stop_reason: "tool_use" e um ou mais blocos tool_use.
  4. +
  5. Execute cada ferramenta e formate as saídas como blocos tool_result.
  6. +
  7. Envie uma nova requisição contendo as mensagens originais, a resposta do assistente e uma mensagem de usuário com os blocos tool_result.
  8. +
  9. Repita a partir do passo 2 enquanto stop_reason for "tool_use".
  10. +
+

O loop termina em qualquer outro motivo de parada ("end_turn", "max_tokens", "stop_sequence" ou "refusal"), o que significa que o Claude produziu uma resposta final ou parou por outro motivo.

+ +

O loop do lado servidor e pause_turn

+

Ferramentas server-side rodam seu próprio loop dentro da infraestrutura da Anthropic. Uma única requisição sua pode disparar várias buscas web ou execuções de código antes de a resposta voltar. Esse loop interno tem um limite de iterações; se o modelo ainda está iterando ao atingir o teto, a resposta volta com stop_reason: "pause_turn" em vez de "end_turn". Um turno pausado significa que o trabalho não terminou: reenvie a conversa (incluindo a resposta pausada) para o modelo continuar. Veja a seção Ferramentas server-side.

+ +

Quando usar (e quando não usar) ferramentas

+

Tool use serve quando a tarefa exige algo que o modelo não consegue fazer só com texto: ações com efeitos colaterais (enviar e-mail, escrever arquivo, atualizar registro), dados frescos ou externos (preços atuais, conteúdo de um banco), saídas estruturadas com formato garantido, e integração com sistemas existentes. Não serve quando o modelo pode responder só com o treino (resumo, tradução, conhecimento geral), quando a interação é Q&A de uma rodada sem efeitos colaterais, ou quando a latência da chamada dominaria uma resposta trivial.

+ +

Preço do tool use

+

Requisições com tool use são cobradas por: (1) total de tokens de entrada enviados ao modelo (incluindo o parâmetro tools); (2) tokens de saída gerados; (3) para ferramentas server-side, cobrança adicional por uso (ex.: web search cobra por busca). Ao usar tools, a API injeta automaticamente um system prompt especial que habilita o tool use. Em todos os modelos atuais, esse prompt de sistema custa 346 tokens para tool_choice auto/none e 313 tokens para any/tool (assumindo ao menos 1 ferramenta; com none e nenhuma ferramenta, 0 tokens). Esses tokens entram nos contadores normais de usage.

+ +
+ + + + + + +
Modeloauto / noneany / tool
Claude Opus 4.8 (claude-opus-4-8)346 tokens313 tokens
Claude Sonnet 4.6 (claude-sonnet-4-6)346 tokens313 tokens
Claude Haiku 4.5 (claude-haiku-4-5)346 tokens313 tokens
+
Nota: esta tabela mostra apenas o custo em tokens do system prompt de tool use por modelo. Para a tabela comparativa de modelos, preços por token, snapshots e orientação de escolha (Opus 4.8 para tarefas complexas/raciocínio, Sonnet 4.6 para equilíbrio, Haiku 4.5 para baixa latência/custo), veja Modelos Claude.
+ +

Exemplo mínimo (ferramenta server-side)

+

O exemplo mais simples usa uma ferramenta server-side, na qual a Anthropic cuida da execução:

+
+
+ + + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+response = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    tools=[{"type": "web_search_20260209", "name": "web_search"}],
+    messages=[{"role": "user", "content": "Qual a novidade mais recente do rover em Marte?"}],
+)
+print(response.content)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+const response = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  tools: [{ type: "web_search_20260209", name: "web_search" }],
+  messages: [{ role: "user", content: "Qual a novidade mais recente do rover em Marte?" }],
+});
+console.log(response.content);
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "tools": [{"type": "web_search_20260209", "name": "web_search"}],
+    "messages": [{"role": "user", "content": "Qual a novidade mais recente do rover em Marte?"}]
+  }'
+
+
+
+ + + + +
+

2. Definindo ferramentas

+ + +

Ferramentas client-side (tanto de schema-Anthropic quanto definidas pelo usuário) são declaradas no parâmetro de topo tools. Cada definição inclui:

+
+ + + + + + + +
ParâmetroDescrição
nameNome da ferramenta. Deve casar com a regex ^[a-zA-Z0-9_-]{1,64}$.
descriptionDescrição em texto puro, detalhada, do que a ferramenta faz, quando usá-la e como se comporta.
input_schemaObjeto JSON Schema definindo os parâmetros esperados.
input_examples(Opcional) Array de objetos de entrada de exemplo para ajudar o Claude a entender como usar a ferramenta.
+

Propriedades opcionais disponíveis em qualquer definição (cache_control, strict, defer_loading, allowed_callers, eager_input_streaming) estão na Referência de ferramentas.

+ +

Exemplo de definição simples

+
{
+  "name": "get_weather",
+  "description": "Get the current weather in a given location",
+  "input_schema": {
+    "type": "object",
+    "properties": {
+      "location": {
+        "type": "string",
+        "description": "The city and state, e.g. San Francisco, CA"
+      },
+      "unit": {
+        "type": "string",
+        "enum": ["celsius", "fahrenheit"],
+        "description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
+      }
+    },
+    "required": ["location"]
+  }
+}
+ +

Boas práticas para descrições

+
    +
  • Descrições extremamente detalhadas — de longe o fator mais importante. Explique o que a ferramenta faz, quando (e quando não) usar, o que cada parâmetro significa e quaisquer limitações. Mire em pelo menos 3–4 frases por ferramenta.
  • +
  • Considere input_examples para ferramentas complexas — com objetos aninhados, parâmetros opcionais ou formatos sensíveis. Cada exemplo deve ser válido perante o input_schema (exemplos inválidos retornam erro 400). Custo: ~20–50 tokens para exemplos simples, ~100–200 para objetos aninhados complexos. Não disponível em ferramentas server-side.
  • +
  • Consolide operações relacionadas em menos ferramentas — em vez de create_pr, review_pr, merge_pr, prefira uma ferramenta com um parâmetro action.
  • +
  • Use namespacing nos nomes — quando as ferramentas abrangem vários serviços, prefixe com o serviço (github_list_prs, slack_send_message). Isso é especialmente importante ao usar tool search.
  • +
  • Desenhe respostas com informação de alto sinal — retorne identificadores estáveis (slugs, UUIDs) e só os campos de que o Claude precisa. Respostas inchadas desperdiçam contexto.
  • +
+ +

Controlando a saída: tool_choice

+

Há quatro opções para o campo tool_choice:

+
+ + + + + + + +
ValorComportamento
autoO Claude decide se chama alguma ferramenta. Padrão quando há tools.
anyO Claude deve usar uma das ferramentas, sem forçar uma específica.
toolForça sempre uma ferramenta específica: {"type": "tool", "name": "get_weather"}.
noneImpede o uso de qualquer ferramenta. Padrão quando não há tools.
+
Atenção: com any ou tool, a API faz prefill da mensagem do assistente para forçar a ferramenta — o modelo não emite texto natural antes dos blocos tool_use. Com adaptive/extended thinking, tool_choice any e tool não são suportados e geram erro; apenas auto (padrão) e none são compatíveis. Mudar tool_choice sob prompt caching invalida blocos de mensagem em cache.
+
Dica: combine tool_choice: {"type": "any"} com strict tool use (strict: true) para garantir tanto que uma ferramenta será chamada quanto que os inputs seguem o schema exatamente.
+
+ +
+

2.1. Tratando chamadas de ferramenta (handle-tool-calls)

+ + +

Para ferramentas client-side, a resposta tem stop_reason: "tool_use" e um ou mais blocos tool_use com id (identificador único, casado depois pelo resultado), name e input (objeto conforme o input_schema). Ao receber, você deve: (1) extrair name, id e input; (2) rodar a ferramenta correspondente; (3) continuar a conversa enviando uma mensagem user com um bloco tool_result.

+ +

O bloco tool_result tem:

+
    +
  • tool_use_id: o id da requisição tool_use que este resultado responde.
  • +
  • content (opcional): o resultado, como string ("15 degrees"), lista de blocos aninhados, ou blocos de documento. Pode usar tipos text, image ou document.
  • +
  • is_error (opcional): true se a execução resultou em erro.
  • +
+ +
Cuidado — requisitos de formatação: os blocos tool_result devem vir imediatamente após os blocos tool_use correspondentes; não pode haver mensagens entre a mensagem do assistente (com tool_use) e a mensagem do usuário (com tool_result). Dentro da mensagem de usuário, os blocos tool_result devem vir primeiro no array de content; qualquer texto vem depois. Texto antes do tool_result causa erro 400 (tool_use ids were found without tool_result blocks immediately after).
+ +

Exemplo de resultado bem-sucedido e de resultado de erro:

+
{
+  "role": "user",
+  "content": [
+    { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "15 degrees" }
+  ]
+}
+
{
+  "role": "user",
+  "content": [
+    {
+      "type": "tool_result",
+      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
+      "content": "ConnectionError: the weather service API is not available (HTTP 500)",
+      "is_error": true
+    }
+  ]
+}
+ +
Dica: escreva mensagens de erro instrutivas. Em vez de "failed", inclua o que deu errado e o que o Claude deve tentar a seguir (ex.: "Rate limit exceeded. Retry after 60 seconds."). Se uma chamada é inválida ou falta um parâmetro, o Claude tenta de novo 2–3 vezes antes de se desculpar. Para servidor, o Claude trata erros transparentemente — você não precisa lidar com is_error em ferramentas server-side.
+ +

Para web search, os códigos de erro possíveis incluem: too_many_requests (limite de taxa), invalid_input (query inválida), max_uses_exceeded (limite de buscas excedido), query_too_long e unavailable (erro interno).

+ +
Nota — diferença de outras APIs: diferentemente de APIs que usam papéis especiais (tool/function), a Claude API integra ferramentas diretamente nas mensagens user e assistant. Mensagens contêm arrays de blocos text, image, tool_use e tool_result: mensagens user incluem conteúdo do cliente e tool_result; mensagens assistant contêm conteúdo gerado e tool_use.
+
+ + + + +
+

3. Tipos de ferramentas e referência (catálogo)

+ + +

A Anthropic fornece dois tipos: ferramentas server-side (executam na infraestrutura da Anthropic) e ferramentas client-side de schema-Anthropic (a Anthropic define o schema, sua aplicação executa). Ambas aparecem no array tools junto com suas ferramentas próprias. O catálogo abaixo lista os valores exatos de type e os headers beta — verificados na doc oficial.

+ +
+ + + + + + + + + + + + + +
FerramentatypeExecuçãoStatus
Web searchweb_search_20260209
web_search_20250305
ServidorGA
Web fetchweb_fetch_20260209
web_fetch_20250910
ServidorGA
Code executioncode_execution_20260120
code_execution_20250825
ServidorGA
Advisoradvisor_20260301ServidorBeta advisor-tool-2026-03-01
Tool searchtool_search_tool_regex_20251119
tool_search_tool_bm25_20251119
ServidorGA
MCP connectormcp_toolsetServidorBeta mcp-client-2025-11-20
Memorymemory_20250818ClienteGA
Bashbash_20250124ClienteGA
Text editortext_editor_20250728
text_editor_20250124
ClienteGA
Computer usecomputer_20251124
computer_20250124
ClienteBeta computer-use-2025-11-24 / computer-use-2025-01-24
+
Nota: os valores de tool search também aceitam aliases sem data (tool_search_tool_regex, tool_search_tool_bm25), que resolvem para a versão datada mais recente.
+ +

Versionamento de ferramentas

+

A maioria das ferramentas carrega o sufixo _YYYYMMDD no type. Uma nova versão sai quando o comportamento, o schema ou o suporte a modelos muda; as versões antigas continuam disponíveis. As relações variam:

+
    +
  • Por capacidade: web_search_20260209 / web_fetch_20260209 adicionam filtragem dinâmica de conteúdo; code_execution_20260120 adiciona chamada programática de ferramentas. Em cada caso, ambas as versões são atuais — você escolhe conforme precisa da nova capacidade.
  • +
  • Por modelo: text_editor_20250728 é para modelos Claude 4; text_editor_20250124 é para modelos anteriores.
  • +
  • Variante, não versão: tool_search_tool_regex_20251119 e tool_search_tool_bm25_20251119 são dois algoritmos lançados juntos; nenhum substitui o outro.
  • +
  • O mcp_toolset não é versionado por data — o versionamento vai no header anthropic-beta.
  • +
+ +

Propriedades opcionais de definição (em qualquer ferramenta)

+
+ + + + + + + + + +
PropriedadeFinalidadeDisponível em
cache_controlDefine um breakpoint de prompt cache nesta definiçãoTodas as ferramentas
strictGarante validação de schema sobre nomes e inputsTodas, exceto mcp_toolset
defer_loadingExclui a ferramenta do system prompt inicial; carrega sob demanda via tool searchTodas (para mcp_toolset, ver config do toolset)
allowed_callersRestringe quais chamadores podem invocar a ferramentaTodas, exceto mcp_toolset
input_examplesExemplos de inputFerramentas de usuário e de schema-Anthropic (não server-side)
eager_input_streamingHabilita streaming refinado de inputApenas ferramentas definidas pelo usuário
+

O allowed_callers é um array que aceita "direct" (o modelo chama diretamente num bloco tool_use — padrão) e/ou "code_execution_20260120" (código rodando dentro de um sandbox de code execution pode chamar a ferramenta). Omitir "direct" torna a ferramenta chamável só de dentro do code execution. Ferramentas com defer_loading: true são removidas do prefixo antes do cálculo da chave de cache, preservando o prompt cache.

+
+ + + + +
+

4. Ferramentas client-side detalhadas

+

As quatro ferramentas de schema-Anthropic client-side (bash, text_editor, computer, memory) mais a server-side code_execution (incluída aqui por proximidade conceitual). A vantagem de usar uma ferramenta de schema-Anthropic em vez de criar a sua equivalente é que esses schemas são treinados-no-modelo: o Claude foi otimizado em milhares de trajetórias bem-sucedidas com essas assinaturas exatas, então ele as chama de forma mais confiável.

+
+ +
+

4.1. Bash tool — bash_20250124

+ +

A bash tool permite ao Claude executar comandos shell em uma sessão bash persistente, viabilizando operações de sistema, scripts e automação de linha de comando. A sessão mantém estado (variáveis de ambiente, diretório de trabalho) entre comandos. GA · ZDR elegível.

+

É uma ferramenta schema-less: você não fornece input_schema — o schema está embutido no modelo e não pode ser modificado. Parâmetros: command (obrigatório, salvo quando se usa restart) e restart (opcional, true reinicia a sessão).

+
+
+ + + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+response = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    tools=[{"type": "bash_20250124", "name": "bash"}],
+    messages=[{"role": "user", "content": "List all Python files in the current directory."}],
+)
+print(response)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+const response = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  tools: [{ type: "bash_20250124", name: "bash" }],
+  messages: [{ role: "user", content: "List all Python files in the current directory." }],
+});
+console.log(response);
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "content-type: application/json" \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "tools": [{"type": "bash_20250124", "name": "bash"}],
+    "messages": [{"role": "user", "content": "List all Python files in the current directory."}]
+  }'
+
+
+
Cuidado: a bash tool dá ao Claude acesso a shell. Rode-a em um ambiente isolado (VM/contêiner com privilégios mínimos), restrinja o diretório de trabalho e considere uma allowlist de comandos quando o agente opera sobre código não confiável.
+
+ +
+

4.2. Text editor tool — text_editor_20250728

+ +

Permite ao Claude visualizar e modificar arquivos de texto — depurar, refatorar, gerar documentação, criar testes. A ferramenta tem o nome str_replace_based_edit_tool. Para modelos Claude 4 use text_editor_20250728; para modelos anteriores, text_editor_20250124. GA · ZDR elegível. Você pode opcionalmente passar max_characters para controlar a truncagem ao ler arquivos grandes (compatível com text_editor_20250728+).

+

Comandos suportados:

+
+ + + + + + + +
ComandoParâmetrosO que faz
viewpath, view_range (opcional, [início, fim], 1-indexado, -1 = fim do arquivo)Lê arquivo (ou intervalo de linhas) ou lista um diretório.
str_replacepath, old_str (deve casar exatamente, incluindo espaços), new_strSubstitui um trecho específico por outro. Edição precisa.
createpath, file_textCria um novo arquivo com o conteúdo dado.
insertpath, insert_line (0 = começo), insert_textInsere texto após a linha indicada.
+
{
+  "type": "tool_use",
+  "id": "toolu_01A09q90qw90lq917835lq9",
+  "name": "str_replace_based_edit_tool",
+  "input": {
+    "command": "str_replace",
+    "path": "primes.py",
+    "old_str": "for num in range(2, limit + 1)",
+    "new_str": "for num in range(2, limit + 1):"
+  }
+}
+
+ +
+

4.3. Computer use tool — computer_20251124

+ +

Permite ao Claude interagir com ambientes de desktop: captura de tela, controle de mouse/teclado, automação. Beta — exige um header beta:

+
    +
  • computer-use-2025-11-24 (tipo computer_20251124) para Claude Opus 4.8 e Sonnet 4.6.
  • +
  • computer-use-2025-01-24 (tipo computer_20250124) para Claude Haiku 4.5.
  • +
+

ZDR elegível. Parâmetros da definição: display_width_px, display_height_px e display_number. Frequentemente combinado com text_editor e bash.

+

Ações disponíveis:

+
+ + + + + + +
GrupoAções
Básicas (todas as versões)screenshot, left_click (com coordinate [x,y]), type, key (ex.: "ctrl+s"), mouse_move
Aprimoradas (computer_20250124)scroll, left_click_drag, right_click, middle_click, double_click, triple_click, left_mouse_down/left_mouse_up, hold_key, wait
Aprimoradas (computer_20251124)Todas as anteriores + zoom (ver uma região em resolução plena; exige enable_zoom: true e um region [x1,y1,x2,y2])
+

Para teclas modificadoras (Shift, Ctrl, Alt) durante clique/scroll, use o parâmetro text na própria ação (ex.: {"action": "left_click", "coordinate": [500,300], "text": "shift"}).

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+response = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    tools=[
+        {"type": "computer_20251124", "name": "computer",
+         "display_width_px": 1024, "display_height_px": 768, "display_number": 1},
+        {"type": "text_editor_20250728", "name": "str_replace_based_edit_tool"},
+        {"type": "bash_20250124", "name": "bash"},
+    ],
+    messages=[{"role": "user", "content": "Save a picture of a cat to my desktop."}],
+    betas=["computer-use-2025-11-24"],
+)
+print(response)
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "content-type: application/json" \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "anthropic-beta: computer-use-2025-11-24" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "tools": [
+      {"type": "computer_20251124", "name": "computer",
+       "display_width_px": 1024, "display_height_px": 768, "display_number": 1}
+    ],
+    "messages": [{"role": "user", "content": "Save a picture of a cat to my desktop."}]
+  }'
+
+
+
Cuidado: computer use tem riscos próprios, ampliados ao acessar a internet. Use uma VM/contêiner dedicado de privilégio mínimo, evite dar acesso a dados sensíveis, restrinja a internet a uma allowlist de domínios e peça confirmação humana para ações de consequência real. O Claude pode seguir instruções encontradas em conteúdo (prompt injection via páginas/imagens). A Anthropic treina o modelo para resistir e roda classificadores que pedem confirmação ao detectar injeções em screenshots — proteção que pode ser desativada via suporte para casos sem humano no loop. Há uma implementação de referência (contêiner Docker, ferramentas, loop de agente, UI web).
+
+ +
+

4.4. Memory tool — memory_20250818

+ +

Permite ao Claude armazenar e recuperar informação entre conversas, via um diretório de arquivos de memória. É o primitivo-chave para recuperação just-in-time: em vez de carregar tudo de uma vez, o agente guarda o que aprende e recupera sob demanda, mantendo o contexto ativo focado. GA · ZDR elegível.

+

A ferramenta é client-side: você controla onde e como os dados são guardados. O Claude faz chamadas de ferramenta e sua aplicação as executa localmente. Por segurança, restrinja todas as operações ao diretório /memories. Os SDKs trazem helpers (subclasse de BetaAbstractMemoryTool em Python; betaMemoryTool em TypeScript).

+

Comandos que sua implementação precisa tratar: view (lista diretório ou mostra arquivo, com view_range opcional), create (path, file_text), str_replace (old_str/new_str), insert (insert_line, insert_text), delete (recursivo para diretórios) e rename (old_path/new_path; não sobrescreve destino existente).

+

Quando habilitada, a Anthropic injeta automaticamente no system prompt o protocolo de memória: "IMPORTANT: ALWAYS VIEW YOUR MEMORY DIRECTORY BEFORE DOING ANYTHING ELSE", lembrando o Claude de checar progresso anterior e gravar status, pois o contexto pode ser resetado a qualquer momento.

+
Cuidado — path traversal: inputs maliciosos podem tentar acessar arquivos fora de /memories. Sua implementação DEVE validar todos os caminhos: confirmar que começam com /memories, resolver para a forma canônica e verificar que permanecem no diretório, rejeitar sequências como ../, ..\\ e variantes URL-encoded (%2e%2e%2f), e usar utilitários nativos (pathlib.Path.resolve() + relative_to() em Python). Considere também limitar tamanho de arquivos e expirar memórias antigas.
+

A memory tool combina com context editing (limpa tool_result antigos no cliente) e com compaction (sumariza a conversa no servidor): use ambos em fluxos longos — a memória persiste o que é crítico através das fronteiras de compactação.

+
+ +
+

4.5. Code execution tool — code_execution_20250825 / code_execution_20260120

+ +

Roda código Python e Bash em um contêiner isolado para analisar dados, gerar arquivos e iterar sobre soluções. É um primitivo central para agentes de alto desempenho — habilita a filtragem dinâmica de web search/web fetch. GA (server-side) desde 2026-02-17, sem header beta (confirmado na doc oficial em 2026-06-10; o header legado code-execution-2025-08-25 segue aceito por compatibilidade — alguns exemplos de SDK ainda o usam via namespace beta). Não é elegível para ZDR.

+
Dica: code execution é gratuito quando usado com web search ou web fetch — incluindo web_search_20260209 ou web_fetch_20260209, não há cobrança extra por chamadas de code execution além dos custos normais de token. As cobranças padrão de code execution aplicam-se quando essas ferramentas não estão presentes.
+

Versões: code_execution_20250825 suporta comandos Bash e operações de arquivo e roda em todos os modelos atuais; code_execution_20260120 adiciona persistência de estado do REPL e chamada programática de ferramentas a partir do sandbox, disponível em Opus 4.5+ e Sonnet 4.5+ (inclui Opus 4.8/4.7/4.6 e Sonnet 4.6; não Haiku 4.5). A legada code_execution_20250522 é só Python.

+
Atenção: versões antigas não têm compatibilidade retroativa garantida com modelos novos. Use a versão que corresponde ao seu modelo. Haiku 4.5 suporta apenas code_execution_20250825. Code execution está disponível na Claude API, Claude Platform on AWS e Microsoft Foundry; não está em Amazon Bedrock nem Vertex AI.
+

Contêiner (runtime): Python 3.11.12, Linux x86_64, 5 GiB de RAM, 5 GiB de disco, 1 CPU. Sem acesso à internet e isolamento total do host. Contêineres expiram 30 dias após a criação e são escopados ao workspace da API key. Bibliotecas pré-instaladas incluem pandas, numpy, scipy, scikit-learn, matplotlib, seaborn, pyarrow, openpyxl, pillow, python-pptx, python-docx, pypdf, pdfplumber, reportlab, sympy, sqlite, ripgrep, entre outras.

+

Você pode reutilizar um contêiner entre requisições passando o container ID de uma resposta anterior, mantendo arquivos criados. Para enviar seus próprios arquivos, use a Files API (header files-api-2025-04-14) e referencie-os com um bloco container_upload ({"type": "container_upload", "file_id": "file_abc123"}).

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+response = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=4096,
+    messages=[{"role": "user",
+               "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"}],
+    tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
+)
+print(response)
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 4096,
+    "messages": [{"role": "user", "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"}],
+    "tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
+  }'
+
+
+
+ + + + +
+

5. Ferramentas server-side

+ +

Ferramentas server-side (web_search, web_fetch, code_execution, tool_search) executam na infraestrutura da Anthropic. Quando uma roda, aparece um bloco server_tool_use na resposta, com id prefixado por srvtoolu_ (vs. toolu_ das ferramentas de cliente). O resultado aparece logo após, no mesmo turno do assistente — você não responde com tool_result.

+
{
+  "type": "server_tool_use",
+  "id": "srvtoolu_01A2B3C4D5E6F7G8H9",
+  "name": "web_search",
+  "input": { "query": "latest quantum computing breakthroughs" }
+}
+ +

Continuação com pause_turn

+

O loop interno tem limite de iterações; ao atingi-lo, a resposta volta com stop_reason: "pause_turn". Para continuar, reenvie a conversa passando a resposta pausada como mensagem assistant (preservando as mesmas ferramentas). Você pode opcionalmente modificar o conteúdo antes de continuar.

+ +

ZDR e allowed_callers

+

As versões básicas — web_search_20250305 e web_fetch_20250910 — são elegíveis para Zero Data Retention (ZDR). As versões _20260209 com filtragem dinâmica não são ZDR-elegíveis por padrão (a filtragem usa code execution internamente). Para usá-las com ZDR, desabilite a filtragem dinâmica com "allowed_callers": ["direct"], restringindo a ferramenta à invocação direta.

+ +

Filtragem de domínio

+

Ferramentas que acessam a web aceitam allowed_domains e blocked_domains (use um ou outro, nunca ambos na mesma requisição). Regras: domínios sem esquema HTTP/HTTPS (example.com, não https://example.com); subdomínios são incluídos automaticamente (example.com cobre docs.example.com); subcaminhos são suportados (example.com/blog casa example.com/blog/post-1); curinga (*) apenas um por entrada, e só após a parte do domínio (válido: example.com/*; inválido: *.example.com). Restrições no nível da requisição devem ser compatíveis com as do nível da organização no Console (só podem restringir mais, nunca ampliar).

+
Atenção: caracteres Unicode em nomes de domínio podem criar ataques de homógrafos (ex.: аmazon.com com 'а' cirílico parece amazon.com). Prefira nomes ASCII e teste seus filtros contra variações de homógrafos.
+
Atenção: incluir uma ferramenta code_execution autônoma ao lado das versões _20260209 dos tools web cria dois ambientes de execução, o que pode confundir o modelo. Use um ou outro, ou fixe ambos na mesma versão.
+
+ +
+

5.1. Web search — web_search_20260209 / web_search_20250305

+ +

Dá ao Claude acesso a conteúdo web em tempo real, com citações das fontes. A versão mais recente (web_search_20260209) suporta filtragem dinâmica em Claude Opus 4.8 e Sonnet 4.6: o Claude escreve e executa código para filtrar os resultados antes de chegarem ao contexto, melhorando a precisão e reduzindo tokens. A versão anterior (web_search_20250305) permanece disponível sem filtragem dinâmica. GA.

+
Nota: a filtragem dinâmica requer a ferramenta code execution habilitada. O administrador da organização deve habilitar web search no Console. A filtragem dinâmica está na Claude API, Claude Platform on AWS e Microsoft Foundry; em Vertex AI só a busca básica; não está em Amazon Bedrock.
+

Parâmetros da definição:

+
+ + + + + + +
ParâmetroDescrição
max_usesLimita o nº de buscas por requisição. Exceder gera erro max_uses_exceeded.
allowed_domains / blocked_domainsFiltragem de domínio (ver seção acima).
user_locationLocaliza resultados: type: "approximate", city, region, country, timezone (ID IANA).
+

A resposta inclui blocos server_tool_use (a query usada) e web_search_tool_result com web_search_result (url, title, encrypted_content, page_age), e o texto final com citações.

+
{
+  "type": "web_search_20250305",
+  "name": "web_search",
+  "max_uses": 5,
+  "allowed_domains": ["example.com", "trusteddomain.org"],
+  "user_location": {
+    "type": "approximate",
+    "city": "San Francisco",
+    "region": "California",
+    "country": "US",
+    "timezone": "America/Los_Angeles"
+  }
+}
+
+ +
+

5.2. Web fetch — web_fetch_20260209 / web_fetch_20250910

+ +

Recupera o conteúdo completo de páginas web e documentos PDF específicos (com extração automática de texto para PDFs) e responde com citações opcionais. A versão web_fetch_20260209 suporta filtragem dinâmica (Opus 4.8, Sonnet 4.6), útil para extrair seções de documentos longos. GA. Não suporta sites renderizados dinamicamente com JavaScript.

+
Cuidado — exfiltração de dados: habilitar web fetch em ambientes onde o Claude processa entrada não confiável junto a dados sensíveis cria risco de exfiltração. Para mitigar, o Claude não pode construir URLs dinamicamente — só busca URLs fornecidas explicitamente pelo usuário ou vindas de resultados anteriores de web search/web fetch. Ainda há risco residual: considere desabilitar a ferramenta, usar max_uses para limitar requisições, e allowed_domains para restringir a domínios seguros.
+

Parâmetros principais: max_uses, allowed_domains/blocked_domains, e citações (habilitadas via citations: { enabled: true } no resultado). O resultado (web_fetch_tool_result / web_fetch_result) traz a URL, um bloco document com o texto, title e retrieved_at. As citações usam char_location com document_index, start_char_index/end_char_index e cited_text.

+
+ + + +
+

5.4. Advisor tool — advisor_20260301

+ +

Pareia um modelo executor mais rápido e barato com um modelo advisor de maior inteligência que dá orientação estratégica no meio da geração. O advisor lê toda a conversa e produz um plano ou correção de rumo (tipicamente 400–700 tokens de texto), e o executor continua. Encaixa em cargas agênticas de longo horizonte (agentes de coding, computer use, pesquisa multi-passo) onde a maioria dos turnos é mecânica mas um excelente plano é crucial. Beta — header advisor-tool-2026-03-01. ZDR elegível.

+

O modelo executor (campo model de topo) e o advisor (campo model dentro da definição da ferramenta) devem formar um par válido — o advisor deve ser ao menos tão capaz quanto o executor:

+
+ + + + + + +
ExecutorAdvisor
Claude Haiku 4.5 (claude-haiku-4-5)Claude Opus 4.8 (claude-opus-4-8)
Claude Sonnet 4.6 (claude-sonnet-4-6)Claude Opus 4.8 (claude-opus-4-8)
Claude Opus 4.8 (claude-opus-4-8)Claude Opus 4.8 (claude-opus-4-8)
+

Par inválido retorna 400 invalid_request_error. Disponível em beta na Claude API e Claude Platform on AWS (não em Bedrock, Vertex AI ou Microsoft Foundry). Desde 02/06/2026, a definição da ferramenta aceita max_tokens (tools[].max_tokens) para limitar a saída do advisor por chamada — reduz latência e custo quando você não precisa de orientações longas.

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+response = client.beta.messages.create(
+    model="claude-sonnet-4-6",          # executor
+    max_tokens=4096,
+    betas=["advisor-tool-2026-03-01"],
+    tools=[{"type": "advisor_20260301", "name": "advisor", "model": "claude-opus-4-8"}],  # advisor
+    messages=[{"role": "user", "content": "Build a concurrent worker pool in Go with graceful shutdown."}],
+)
+print(response)
+
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "anthropic-beta: advisor-tool-2026-03-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-sonnet-4-6",
+    "max_tokens": 4096,
+    "tools": [{"type": "advisor_20260301", "name": "advisor", "model": "claude-opus-4-8"}],
+    "messages": [{"role": "user", "content": "Build a concurrent worker pool in Go with graceful shutdown."}]
+  }'
+
+
+
+ + + + +
+

6. Recursos avançados de tool use

+

Recursos que melhoram desempenho, confiabilidade, latência e custo de contexto em fluxos agênticos.

+
+ +
+

6.1. Uso paralelo de ferramentas

+ +

Por padrão, o Claude pode usar várias ferramentas para responder a uma query. As chamadas em um único turno são não ordenadas: você pode rodá-las concorrentemente (Promise.all, asyncio.gather) ou em sequência. Para desabilitar, use disable_parallel_tool_use=true: com tool_choice: auto garante no máximo uma ferramenta; com any/tool, garante exatamente uma.

+
Dica: envie todos os tool_result em uma única mensagem de usuário (não um por turno) para manter o paralelismo funcionando nos turnos seguintes. Se o Claude ocasionalmente agrupar chamadas que dependem entre si (ex.: criar e depois atualizar o mesmo recurso), não precisa detectar isso antes: despache tudo e, se uma falhar, devolva o erro natural em um tool_result com is_error: true — o Claude reconhece a dependência e refaz a chamada.
+
+ +
+

6.2. Chamada programática de ferramentas (programmatic tool calling)

+ +

Permite ao Claude escrever código que chama suas ferramentas programaticamente dentro do sandbox de code execution, em vez de exigir round trips pelo modelo a cada invocação. Reduz latência em fluxos multi-ferramenta e diminui o consumo de tokens (o Claude filtra/processa dados antes de chegarem ao contexto). Ex.: checar conformidade de orçamento de 20 funcionários — em vez de 20 round trips com milhares de linhas no contexto, um único script roda as 20 consultas, filtra e retorna só quem excedeu o limite.

+

Requer code_execution_20260120, suportado em Opus 4.5+ e Sonnet 4.5+ (inclui Opus 4.8/4.7/4.6 e Sonnet 4.6; não Haiku 4.5). Não é ZDR-elegível. Disponível na Claude API, Claude Platform on AWS e Microsoft Foundry (não em Bedrock/Vertex AI).

+

Marque a ferramenta com "allowed_callers": ["code_execution_20260120"] para torná-la chamável de dentro do sandbox. O bloco tool_use da resposta inclui um campo caller identificando quem chamou. Monitore expires_at do contêiner: se ele expira enquanto aguarda seu tool_result, o Claude pode tratar como timeout e refazer.

+
{
+  "type": "code_execution_20260120",
+  "name": "code_execution"
+}
+{
+  "name": "query_database",
+  "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
+  "input_schema": { "type": "object", "properties": { "sql": {"type": "string"} }, "required": ["sql"] },
+  "allowed_callers": ["code_execution_20260120"]
+}
+
+ +
+

6.3. Modo estrito (strict tool use)

+ +

Definir strict: true na definição de uma ferramenta garante que os inputs do Claude casem com seu JSON Schema, restringindo a amostragem de tokens a saídas válidas (grammar-constrained sampling). Sem modo estrito, o Claude pode retornar tipos incompatíveis ("2" em vez de 2) ou campos faltando. Use para validar parâmetros, construir fluxos agênticos e garantir chamadas type-safe — funções recebem argumentos corretamente tipados toda vez, sem precisar validar e refazer. Disponível em todas as ferramentas exceto mcp_toolset.

+
Atenção: a gramática usa apenas o subconjunto suportado de JSON Schema. Por exemplo, pattern com strict: true gera erro (string patterns are not supported) — remova o pattern ou o strict. Inclua "additionalProperties": false no schema.
+
{
+  "name": "get_weather",
+  "description": "Get the current weather in a given location",
+  "strict": true,
+  "input_schema": {
+    "type": "object",
+    "properties": {
+      "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA" },
+      "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
+    },
+    "required": ["location"],
+    "additionalProperties": false
+  }
+}
+
+ +
+

6.4. Streaming refinado de input (fine-grained tool streaming)

+ +

Permite fazer streaming dos valores de parâmetro de uma ferramenta sem buffering nem validação de JSON no servidor, reduzindo a latência para começar a receber parâmetros grandes. Disponível em todos os modelos e plataformas. Habilite com eager_input_streaming: true em qualquer ferramenta definida pelo usuário, e ative stream na requisição. ZDR elegível.

+
Atenção: com streaming refinado você pode receber JSON inválido ou parcial. Trate esses casos no seu código.
+
+ +
+

6.5. Gerenciando o contexto das ferramentas

+ +

Definições de ferramentas e blocos tool_result acumulados consomem o contexto. Quatro abordagens atacam fontes diferentes de pressão:

+
+ + + + + + + +
AbordagemO que reduzQuando encaixa
Tool searchDefinições carregadas no inícioToolsets grandes (20+) onde a maioria não é necessária a cada turno
Programmatic tool callingRound trips de tool_resultCadeias de chamadas que podem rodar como um único script
Prompt cachingCusto de tokens das definições repetidasToolsets estáveis em muitas requisições
Context editingBlocos tool_result antigos no históricoConversas longas onde resultados antigos já não importam
+

Elas compõem. Ponto de partida para um agente de alto volume: (1) habilite prompt caching nas definições desde o dia 1; (2) adicione tool search quando passar de ~20 ferramentas; (3) adicione context editing quando as conversas começarem a ficar longas; (4) considere programmatic tool calling se notar cadeias repetitivas de chamadas pequenas.

+
+ +
+

6.6. Combinações de ferramentas

+ +

Pareamentos comuns das ferramentas fornecidas pela Anthropic — pontos de partida, não prescrições:

+
+ + + + + + + + +
PadrãoFerramentasUso
Agente de pesquisaweb_search + code_executionBusca encontra fontes; code execution analisa e sintetiza (ex.: comparar resultados financeiros computando sobre os dados).
Agente de codingtext_editor + bashO loop canônico de dev: inspeciona código, edita, roda testes, repete. Pareie com diretório restrito e allowlist de comandos.
Cite-then-fetchweb_search + web_fetchBusca traz URLs candidatas; fetch recupera só as 2–3 relevantes, evitando baixar tudo.
Agente de longa duraçãomemory + qualquer toolsetMemória persiste estado entre conversas; é ortogonal ao resto do toolset.
Tudo-em-umcomputer_useOpera um desktop completo — alcança qualquer app que um humano alcança. É a opção mais geral e a mais lenta (cada ação é um round trip de screenshot).
+
+ +
+

6.7. Tool use com prompt caching

+ +

Coloque cache_control: {"type": "ephemeral"} na última ferramenta do array tools para cachear todo o prefixo de definições (da primeira até o breakpoint). Para mcp_toolset, coloque o breakpoint na própria entrada do toolset — a API o aplica à última ferramenta expandida. Ferramentas com defer_loading: true não entram no prefixo (são adicionadas inline como tool_reference quando descobertas), então adicionar ferramentas via tool search não quebra o cache.

+

O cache segue a hierarquia de prefixo tools → system → messages; mudar um nível invalida ele e tudo depois:

+
+ + + + + + + + + +
MudançaInvalida
Modificar definições de ferramentasCache inteiro (tools, system, messages)
Ligar/desligar web search ou citaçõesCaches de system e messages
Mudar tool_choiceCache de messages
Mudar disable_parallel_tool_useCache de messages
Alternar presença de imagensCache de messages
Mudar parâmetros de thinkingCache de messages
+
+ +
+

6.8. Tool Runner (SDK)

+ +

O Tool Runner é a abstração do SDK que conduz o loop agêntico, embrulha erros e dá segurança de tipos automaticamente — roda as ferramentas quando o Claude as chama, gerencia o ciclo requisição/resposta e o estado da conversa. Beta, disponível nos SDKs Python, TypeScript, C#, Go, Java, PHP e Ruby. Use o loop manual quando precisar de aprovação humana, logging customizado ou execução condicional.

+

Em Python, o decorador @beta_tool deriva o JSON Schema a partir das anotações de tipo e da docstring da função (use @beta_async_tool no cliente assíncrono). Em TypeScript, prefira betaZodTool() (validação Zod, requer Zod 3.25.0+) ou betaTool() (baseado em JSON Schema).

+
+
+ + +
+
+
import json
+from anthropic import Anthropic, beta_tool
+
+client = Anthropic()
+
+@beta_tool
+def get_weather(location: str, unit: str = "fahrenheit") -> str:
+    """Get the current weather in a given location.
+
+    Args:
+        location: The city and state, e.g. San Francisco, CA
+        unit: Temperature unit, either 'celsius' or 'fahrenheit'
+    """
+    return json.dumps({"temperature": "20°C", "condition": "Sunny"})
+
+runner = client.beta.messages.tool_runner(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    tools=[get_weather],
+    messages=[{"role": "user", "content": "What's the weather like in Paris?"}],
+)
+for message in runner:
+    print(message)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
+import { z } from "zod";
+
+const client = new Anthropic();
+
+const getWeatherTool = betaZodTool({
+  name: "get_weather",
+  description: "Get the current weather in a given location",
+  inputSchema: z.object({
+    location: z.string().describe("The city and state, e.g. San Francisco, CA"),
+    unit: z.enum(["celsius", "fahrenheit"]).default("fahrenheit"),
+  }),
+  run: async (input) => JSON.stringify({ temperature: "20°C", condition: "Sunny" }),
+});
+
+const finalMessage = await client.beta.messages.toolRunner({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  tools: [getWeatherTool],
+  messages: [{ role: "user", content: "What's the weather like in Paris?" }],
+});
+
+
+
+ +
+

6.9. Tutorial: construir um agente que usa ferramentas

+ +

O tutorial constrói um agente de gerenciamento de calendário em cinco "anéis" concêntricos, cada um um programa completo e executável que adiciona exatamente um conceito sobre o anterior. A ferramenta de exemplo é create_calendar_event, cujo schema usa objetos aninhados, arrays e campos opcionais (input realista):

+
    +
  1. Anel 1 — Uma ferramenta, um turno: o menor programa possível. Envia o array tools com a mensagem do usuário; a resposta volta com stop_reason: "tool_use" e um bloco tool_use; você executa e devolve o tool_result com tool_use_id casando o id.
  2. +
  3. Anel 2 — O loop agêntico: faz o while baseado em stop_reason à mão.
  4. +
  5. Anel 3 — Uso paralelo de ferramentas.
  6. +
  7. Anel 4 — Tratamento de erros com is_error.
  8. +
  9. Anel 5 — Tool Runner: substitui o loop manual pela abstração do SDK.
  10. +
+
Dica: cada anel roda standalone — copie qualquer um para um arquivo novo e ele executa sem o código dos anteriores.
+
+ +
+

6.10. Solução de problemas (troubleshooting)

+ +
+ + + + + + + + + + +
SintomaCausa provávelCorreção
Claude chama a ferramenta erradaAmbiguidade nas descriçõesAfie as descrições — diferencie por quando usar, não só o que fazem.
Claude nunca chama sua ferramentaColisão de nomes ou schema genéricoCheque nomes duplicados; adicione input_examples.
Tipos de parâmetro errados / parâmetro inexistenteModelo adivinhando sem modo estritoAdicione strict: true (se o schema estiver no subconjunto) ou input_examples.
Chamadas paralelas não funcionamFormatação do históricoEnvie vários tool_result em UMA mensagem de usuário.
Cache sempre invalidatool_choice variandoMantenha tool_choice estável ou ponha o breakpoint antes do ponto de variação.
tool_use ids ... without tool_result blocks immediately afterFalta tool_result ou ele não é o primeiro blocoUm tool_result por tool_use, antes de qualquer texto.
Comparação de string em inputs falha (modelos atuais)Escaping de Unicode/barra muda entre versõesFaça json.loads()/JSON.parse() — nunca compare strings serializadas cruas.
+
+ + + + +
+

7. Agent Skills

+ +

Agent Skills são capacidades modulares que estendem o Claude. Cada Skill empacota instruções, metadados e recursos opcionais (scripts, templates) que o Claude usa automaticamente quando relevantes. Diferentemente de prompts (instruções de conversa para tarefas pontuais), Skills carregam sob demanda e eliminam a necessidade de repetir a mesma orientação em várias conversas. Benefícios: especializar o Claude, reduzir repetição (criar uma vez, usar automaticamente) e compor capacidades. Não elegível para ZDR.

+ +

Divulgação progressiva: três níveis de carregamento

+

Skills são diretórios no sistema de arquivos da VM do Claude. A arquitetura habilita divulgação progressiva — o Claude carrega informação em estágios, conforme necessário:

+
+ + + + + + +
NívelQuando carregaCusto de tokensConteúdo
Nível 1: MetadadosSempre (no startup)~100 tokens por Skillname e description do frontmatter YAML
Nível 2: InstruçõesQuando a Skill é acionadaMenos de 5k tokensCorpo do SKILL.md com instruções e orientação
Nível 3+: RecursosConforme necessárioEfetivamente ilimitadoArquivos empacotados executados via bash sem carregar conteúdo no contexto
+

Skills rodam em um ambiente de code execution com acesso ao sistema de arquivos. Quando uma Skill é acionada, o Claude lê o SKILL.md via bash; se ele referencia outros arquivos (FORMS.md, schema), o Claude os lê também; quando há scripts executáveis, o Claude os roda via bash e recebe só a saída (o código do script nunca entra no contexto). Isso permite acesso a arquivos sob demanda, execução eficiente de scripts e nenhum limite prático de conteúdo empacotado não usado.

+ +

Estrutura de uma Skill (SKILL.md)

+

Toda Skill exige um arquivo SKILL.md com frontmatter YAML. Campos obrigatórios: name e description.

+
---
+name: pdf-processing
+description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
+---
+
+# PDF Processing
+
+## Instructions
+[Orientação clara, passo a passo, para o Claude seguir]
+
+## Examples
+[Exemplos concretos de uso]
+

Requisitos: name ≤ 64 caracteres, só minúsculas/números/hífens, sem tags XML, sem as palavras reservadas "anthropic"/"claude"; description não vazia, ≤ 1024 caracteres, sem tags XML, devendo incluir o que a Skill faz e quando usá-la.

+

Skills pré-construídas (mesmo mecanismo das custom): PowerPoint (pptx), Excel (xlsx), Word (docx) e PDF (pdf).

+ +
Cuidado — segurança: use Skills apenas de fontes confiáveis (criadas por você ou obtidas da Anthropic). Uma Skill maliciosa pode direcionar o Claude a invocar ferramentas ou executar código de formas que não correspondem ao propósito declarado. Audite todo o conteúdo (SKILL.md, scripts, recursos), desconfie de Skills que buscam dados de URLs externas, e trate a instalação com o mesmo rigor de instalar software em produção.
+
+ +
+

7.1. Quickstart de Agent Skills

+ +

O quickstart mostra como começar a usar as Skills pré-construídas (PowerPoint, Excel, Word, PDF) na API. As Skills integram-se à Messages API através da ferramenta code execution, especificando-se a Skill no parâmetro container (ver guia da API a seguir).

+
+ +
+

7.2. Usando Skills com a Claude API

+ +

Skills integram-se à Messages API via code execution, com a mesma estrutura container tanto para Skills da Anthropic quanto custom. Pré-requisitos: API key, a ferramenta code execution habilitada, e três headers beta: code-execution-2025-08-25 (Skills rodam no contêiner de code execution), skills-2025-10-02 (habilita Skills) e files-api-2025-04-14 (para upload/download de arquivos do contêiner).

+
+ + + + + + + + +
AspectoSkills da AnthropicSkills custom
typeanthropiccustom
skill_idNomes curtos: pptx, xlsx, docx, pdfGerado: skill_01AbCd...
Formato de versionPor data: 20251013 ou latestTimestamp epoch ou latest
GestãoPré-construídas e mantidas pela AnthropicUpload/gestão via Skills API (/v1/skills)
DisponibilidadeTodos os usuáriosPrivada ao seu workspace
+

As Skills vão no parâmetro container (até 8 Skills por requisição); especifique type e skill_id, opcionalmente version.

+
+
+ +
+
+
curl https://api.anthropic.com/v1/messages \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: code-execution-2025-08-25,skills-2025-10-02" \
+  -H "content-type: application/json" \
+  -d '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 4096,
+    "container": {
+      "skills": [
+        {"type": "anthropic", "skill_id": "pptx", "version": "latest"}
+      ]
+    },
+    "messages": [{"role": "user", "content": "Create a presentation about renewable energy"}],
+    "tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
+  }'
+
+
+
Nota — onde funcionam: Custom Skills não sincronizam entre superfícies (claude.ai, API, Claude Code são separadas). Escopo de compartilhamento: claude.ai (só o usuário individual), Claude API (todo o workspace), Claude Code (pessoal ~/.claude/skills/ ou de projeto .claude/skills/). Na Claude API, o runtime das Skills não tem acesso à internet, não permite instalação de pacotes em runtime — só os pré-instalados do code execution.
+
+ +
+

7.3. Boas práticas de autoria de Skills

+ +
    +
  • Concisão é a chave. O contexto é um bem público. Assuma que o Claude já é muito inteligente — só adicione contexto que ele não tem. Questione cada parágrafo: "o Claude realmente precisa disso?".
  • +
  • Ajuste os graus de liberdade à fragilidade da tarefa. Alta liberdade (instruções em texto) quando várias abordagens são válidas; média (pseudocódigo/scripts com parâmetros) quando há um padrão preferido; baixa (scripts específicos, poucos parâmetros) quando operações são frágeis e a consistência é crítica ("Run exactly this script... Do not modify").
  • +
+
+ +
+

7.4. Skills para empresas (governança)

+ +

Guia para admins e arquitetos que governam Skills em escala organizacional. Cobre revisão de segurança e vetting (avaliação de tier de risco contra indicadores: execução de código, manipulação de instruções, referências a MCP, padrões de rede, credenciais hardcoded, escopo de acesso a arquivos), uma checklist de revisão (ler todo o conteúdo, verificar comportamento dos scripts em sandbox, checar instruções adversariais e exfiltração, confirmar ausência de credenciais), e avaliação antes do deploy em cinco dimensões: precisão de acionamento, comportamento em isolamento, coexistência (a nova Skill degrada as outras?), seguimento de instruções e qualidade de saída.

+

Exija suites de avaliação com 3–5 queries representativas por Skill (casos que devem e não devem acionar + bordas ambíguas), testando nos modelos usados (Haiku, Sonnet, Opus), pois a eficácia varia por modelo. Ciclo de vida: Planejar → Criar e revisar → Testar → Implantar → Monitorar → Iterar ou descontinuar, com separação de funções (autores não revisam a si mesmos).

+
+ + + + +
+

8. MCP — Model Context Protocol

+ +

O MCP connector permite conectar a servidores MCP remotos diretamente da Messages API, sem implementar um cliente MCP separado. Beta — header mcp-client-2025-11-20 (a versão anterior mcp-client-2025-04-04 está depreciada). Não elegível para ZDR. Recursos: integração direta, chamada de ferramentas via Messages API, configuração flexível (habilitar todas, allowlist ou denylist), autenticação OAuth e múltiplos servidores numa requisição.

+
Atenção — limitações: da especificação MCP, apenas chamadas de ferramenta são suportadas hoje. O servidor deve ser exposto publicamente via HTTP (Streamable HTTP ou SSE); servidores STDIO locais não podem ser conectados diretamente (use MCP tunnels). Disponível na Claude API, Claude Platform on AWS e Microsoft Foundry (não em Bedrock/Vertex AI).
+ +

Os dois componentes

+

O MCP connector usa: (1) MCP Server Definition — o array mcp_servers, que define conexão (URL, autenticação); (2) MCP Toolset — entrada mcp_toolset no array tools, que configura quais ferramentas habilitar.

+

Campos de mcp_servers: type (apenas "url"), url (deve começar com https://), name (identificador único, referenciado por exatamente um toolset) e authorization_token (opcional, token OAuth se o servidor exigir).

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+response = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1000,
+    messages=[{"role": "user", "content": "What tools do you have available?"}],
+    mcp_servers=[
+        {"type": "url", "url": "https://example-server.modelcontextprotocol.io/sse",
+         "name": "example-mcp", "authorization_token": "YOUR_TOKEN"}
+    ],
+    tools=[{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}],
+    betas=["mcp-client-2025-11-20"],
+)
+print(response)
+
+
+
curl https://api.anthropic.com/v1/messages \
+  -H "Content-Type: application/json" \
+  -H "X-API-Key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: mcp-client-2025-11-20" \
+  -d '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1000,
+    "messages": [{"role": "user", "content": "What tools do you have available?"}],
+    "mcp_servers": [
+      {"type": "url", "url": "https://example-server.modelcontextprotocol.io/sse",
+       "name": "example-mcp", "authorization_token": "YOUR_TOKEN"}
+    ],
+    "tools": [{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}]
+  }'
+
+
+ +

Configuração do MCP toolset

+

O mcp_toolset tem mcp_server_name (deve casar com um name em mcp_servers), default_config (configuração padrão aplicada a todas as ferramentas do conjunto), configs (overrides por ferramenta) e cache_control. Cada config aceita enabled (padrão true) e defer_loading (padrão false). Precedência (maior → menor): config específica em configs, default_config, padrões do sistema.

+

Padrões comuns:

+
+ + + + + + +
PadrãoComo
Habilitar todasSó {"type": "mcp_toolset", "mcp_server_name": "..."}
Allowlist (só específicas)default_config: {enabled: false} + configs habilitando ferramentas específicas
Denylist (desabilitar específicas)Default habilitado + configs com enabled: false nas indesejadas
+
{
+  "type": "mcp_toolset",
+  "mcp_server_name": "google-calendar-mcp",
+  "default_config": { "enabled": false },
+  "configs": {
+    "search_events": { "enabled": true },
+    "create_event":  { "enabled": true }
+  }
+}
+
+ +
+

8.1. Servidores MCP remotos

+ +

Várias empresas implantaram servidores MCP remotos que desenvolvedores podem conectar via o MCP connector. Para conectar: revise a documentação do servidor, garanta credenciais de autenticação e siga as instruções específicas de cada empresa.

+
Atenção: esses servidores são serviços de terceiros, não são da Anthropic. Conecte-se apenas a servidores que você confia e revise as práticas de segurança e termos de cada um. Há centenas de servidores MCP no GitHub.
+
+ +
+

8.2. MCP tunnels

+ +

MCP tunnels conectam o Claude a servidores MCP que rodam dentro da sua rede privada. O tráfego flui por uma conexão somente de saída (outbound-only), então você não abre portas de entrada no firewall, não expõe serviços à internet pública nem precisa fazer allowlist dos IPs da Anthropic. Beta (research preview, exige solicitar acesso); depende de um provedor de rede terceiro (Cloudflare).

+ +

Como funciona

+

Uma implantação tem dois componentes na sua rede: cloudflared (o agente de túnel, que inicia conexões outbound-only para a borda do túnel operada pela Anthropic) e Proxy (componente de roteamento da Anthropic que termina o TLS interno, valida que os IPs upstream estão num intervalo permitido e roteia por hostname). Cada servidor MCP exposto ganha um hostname sob seu domínio de túnel (ex.: docs.<seu-dominio-de-tunel>), que você anexa a uma sessão de Managed Agent no Console ou passa à Messages API via MCP connector.

+ +

Modelo de segurança (três camadas)

+
+ + + + + + +
CamadaProtege contra
mTLS externo (Anthropic ↔ provedor de transporte) com validação de IPClientes não autorizados alcançarem o túnel
TLS interno (backend da Anthropic → seu proxy)Inspeção de payload pelo provedor de transporte ou intermediários
OAuth em cada servidor MCPUso não autorizado de ferramentas MCP por tráfego autenticado do túnel
+

Como o proxy termina o TLS interno com um certificado que só você possui, a Cloudflare não consegue ler payloads (recebe apenas metadados: IP de egresso, fingerprint do host cloudflared, timing/volume, e o subdomínio *.tunnel.anthropic.com).

+
Cuidado: se um atacante obtiver seu tunnel token e uma de suas chaves privadas TLS, poderá personificar seu proxy e ler payloads de requisições MCP. Trate ambos como segredos de alto valor.
+ +

Usando os servidores tunelados

+

Uma vez ativo o túnel (com certificado CA ativo e stack conectado), os servidores MCP roteados ficam acessíveis a partir de Claude Managed Agents e da Messages API. O túnel carrega o tráfego criptografado mas não autentica ao servidor — se o upstream exige OAuth/bearer próprio, forneça-o como faria com qualquer servidor MCP. Pela Messages API, passe a URL roteada no array mcp_servers: o host é <subdominio>.<seu-dominio-de-tunel> e o path é o que seu servidor upstream serve (FastMCP streamable-http usa /mcp). O corpo e o header anthropic-beta: mcp-client-2025-11-20 seguem o formato padrão do MCP connector — só a url é específica do túnel.

+
Nota: túneis MCP criados pelo Console não aparecem como conectores no claude.ai.
+ +

Quickstart, deploy e operação

+

Documentação operacional do MCP tunnels:

+
    +
  • Quickstart (doc): caminho mais curto, com Docker Compose e credenciais manuais. Um stack de três contêineres (servidor MCP de amostra, proxy do túnel, conector outbound); o servidor fica acessível em https://echo.<seu-dominio>/mcp sem nada escutando em porta pública. Precisa de Docker/Compose, papel no Console que gerencie túneis, e OpenSSL 1.1.1+.
  • +
  • Deploy com Docker Compose (doc): stack como contêineres endurecidos em um único host, replicável em vários hosts. Requer túnel criado no Console (ID tnl_...).
  • +
  • Deploy com Helm (doc): chart oficial da Anthropic que instala o stack como um único Deployment em um cluster Kubernetes.
  • +
  • Gerenciar no Console (doc): criar túnel, registrar certificado CA, recuperar o tunnel token e anexar servidores a agentes. Autenticação à Tunnels API por Workload Identity Federation (recomendado, escopo org:manage_tunnels) ou credenciais manuais.
  • +
  • Referência (doc): config do proxy (/etc/mcp-gateway/config.yaml) com listen_addr, tunnel_domain, tls.cert_file/key_file, routes (mapa subdomínio → upstream scheme://host:port), upstream.allowed_ips (defesa primária contra SSRF, padrão RFC1918); mais a Tunnels REST API e o CLI de setup.
  • +
  • Segurança (doc): exigir OAuth em cada servidor, habilitar SSO, restringir upstream.allowed_ips ao menor CIDR, monitorar logs, rotacionar credenciais, fixar imagens por digest SHA-256, limitar alcance de rede.
  • +
  • Troubleshooting (doc): diagnóstico de conectividade, TLS e roteamento.
  • +
+

Requisitos de rede (saída): api.anthropic.com (443 TCP, provisionamento/rotação de token); cloudflared para a borda do túnel (198.41.192.0/19, 2606:4700:a0::/44, porta 7844 TCP e UDP, contínuo); proxy para seus servidores MCP upstream.

+
+ + + + + + + + +
+

Parte D — Referência REST/SDK, Agentes Gerenciados, Governança & Nuvem

+

Esta parte é a referência canônica de baixo nível: os SDKs oficiais (com foco em Python e JavaScript/TypeScript; demais linguagens citadas como referência), o contrato REST language-neutral da API de Mensagens, Token Counting, Message Batches, Models e Files, os códigos de erro e rate limits, as plataformas de nuvem (Amazon Bedrock, Vertex AI, Microsoft Foundry, Claude Platform on AWS), os Claude Managed Agents (harness gerenciado) e o plano de governança/Admin (Admin API, workspaces, Workload Identity Federation, Usage & Cost, retenção e residência de dados, Compliance API).

+
+ + + + +
+

1. SDKs oficiais

+

A Anthropic mantém SDKs idiomáticos para oito superfícies, todos com tipagem, streaming, retries e tratamento de erros embutidos. Todos enviam automaticamente o header anthropic-version: 2023-06-01 e leem a chave da variável de ambiente ANTHROPIC_API_KEY. Os mesmos clientes suportam as plataformas de nuvem (Bedrock, Vertex AI, Foundry, Claude Platform on AWS) através de classes/pacotes específicos — veja a seção 9.

+ +
SDKs em profundidade: esta seção dá a visão geral e o contrato REST. Para uso completo dos SDKs, veja a Parte E — SDK Python (anthropic) e a Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk): clientes sync/async, todas as opções, streaming, helpers de ferramentas e MCP, batches, paginação, hierarquia de erros, retries/timeouts, respostas cruas, logging, namespace beta e clientes/pacotes de plataforma.
+ +

1.1. Pacotes, instalação e versão mínima

+
Foco deste guia: os SDKs cobertos em profundidade são Python + (Parte E) e JavaScript/TypeScript (Parte F). + A Anthropic também mantém SDKs oficiais para Java, Go, C#/.NET, Ruby e PHP, além de uma CLI — citados aqui apenas como + referência; consulte a doc oficial para detalhes deles.
+
+ + + + + + + + + + +
LinguagemPacoteInstalaçãoRuntime / referência
Python focoanthropicpip install anthropicPython 3.9+ · ver Parte E
JavaScript/TypeScript foco@anthropic-ai/sdknpm install @anthropic-ai/sdkTS 4.9+ (Node 20+, Deno, Bun, Workers) · ver Parte F
Java referênciacom.anthropic:anthropic-javaimplementation("com.anthropic:anthropic-java")Java 8+
Go referênciaanthropic-sdk-gogo get github.com/anthropics/anthropic-sdk-goGo 1.23+
C# / .NET referênciaAnthropicdotnet add package Anthropic.NET Standard 2.0+
Ruby referênciaanthropicbundle add anthropicRuby 3.2.0+
PHP referênciaanthropic-ai/sdkcomposer require anthropic-ai/sdkPHP 8.1.0+
+
Nota: versões de pacote são fatos perecíveis. Verifique a versão instalada com anthropic.__version__ (Python) ou pelo gerenciador de pacotes (npm ls @anthropic-ai/sdk). Repositórios oficiais: anthropics/anthropic-sdk-python e anthropics/anthropic-sdk-typescript (foco), além de -java, -go, -ruby, -csharp, -php.
+ +

1.2. Inicialização do client (síncrono e assíncrono)

+

O exemplo "Olá, Claude" em três superfícies. Em Python existem dois clients: Anthropic() (síncrono) e AsyncAnthropic() (assíncrono, mesma interface com await).

+
+
+ + + +
+
+
import os
+from anthropic import Anthropic, AsyncAnthropic
+
+# Síncrono — api_key é opcional (lê ANTHROPIC_API_KEY do ambiente)
+client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
+
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+print(message.content[0].text)
+
+# Assíncrono — mesma API, com await
+import asyncio
+aclient = AsyncAnthropic()
+
+async def main():
+    msg = await aclient.messages.create(
+        model="claude-opus-4-8",
+        max_tokens=1024,
+        messages=[{"role": "user", "content": "Olá, Claude"}],
+    )
+    print(msg.content[0].text)
+
+asyncio.run(main())
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic(); // lê ANTHROPIC_API_KEY do ambiente
+
+const message = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Olá, Claude" }],
+});
+console.log(message.content);
+
+
+
# CLI oficial (ant)
+ant messages create \
+  --model claude-opus-4-8 \
+  --max-tokens 1024 \
+  --message '{role: user, content: "Olá, Claude"}' \
+  --transform content
+
+
+ +

1.3. Recursos do SDK: streaming, retries, timeouts, paginação

+

Os SDKs encapsulam quatro comportamentos operacionais. Os valores abaixo são os defaults do SDK Python; outros SDKs seguem convenções equivalentes.

+
+ + + + + + + +
RecursoComportamento padrãoComo configurar
StreamingSSE evento a evento via stream=True; ou helper de contexto client.messages.stream(...) com text_stream e get_final_message()stream=True (iterável de eventos, menos memória) ou with client.messages.stream(...) as s:
Retries2 tentativas automáticas com backoff exponencial em erros de conexão, 408, 409, 429 e ≥500Anthropic(max_retries=0) ou client.with_options(max_retries=5)
Timeouts10 minutos por padrão; lança APITimeoutErrorAnthropic(timeout=20.0) ou httpx.Timeout(...) granular
Auto-paginaçãoItera entre páginas automaticamente em métodos list()for batch in client.messages.batches.list(limit=20): · ou .has_next_page()/.get_next_page()
+
+
+ + +
+
+
from anthropic import Anthropic
+
+client = Anthropic(max_retries=2, timeout=600.0)
+
+# Streaming com helper de contexto: acumula texto e mensagem final
+with client.messages.stream(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Escreva um haicai"}],
+) as stream:
+    for text in stream.text_stream:
+        print(text, end="", flush=True)
+    final = stream.get_final_message()
+    print("\n", final.usage)
+
+# Auto-paginação: percorre todas as páginas de batches
+for batch in client.messages.batches.list(limit=20):
+    print(batch.id)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic({ maxRetries: 2, timeout: 600_000 });
+
+// Streaming: helper com finalMessage()
+const stream = client.messages.stream({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Escreva um haicai" }],
+});
+for await (const event of stream) {
+  if (event.type === "content_block_delta") process.stdout.write(JSON.stringify(event.delta));
+}
+const finalMessage = await stream.finalMessage();
+console.log(finalMessage.usage);
+
+
+
Dica: em Python, pip install "anthropic[aiohttp]" habilita o backend DefaultAioHttpClient para melhor concorrência assíncrona. client.with_raw_response.create(...) expõe headers da resposta (por exemplo request-id); message._request_id é a propriedade pública para correlacionar requisições com o suporte.
+
Atenção (requisições longas): evite max_tokens alto sem streaming. O SDK lança ValueError se uma requisição não-streaming for estimada em > ~10 minutos. Use stream=True (ou o helper .stream() com get_final_message()) para gerações longas. O SDK define TCP keep-alive para mitigar quedas de conexões ociosas.
+
+ + + + +
+

2. Referência REST — endpoints & autenticação

+

A API REST da Anthropic é language-neutral: os SDKs são wrappers finos sobre os endpoints HTTP descritos aqui. Base URL (API de primeira parte): https://api.anthropic.com. As plataformas de nuvem usam base URLs próprias (veja a seção 9).

+ + +

2.1. Headers obrigatórios e versionamento

+
+ + + + + + + +
HeaderValorObrigatório
x-api-keyChave da API sk-ant-api... (ou bearer token em plataformas de nuvem)Sim (ou Authorization: Bearer com WIF/OAuth)
anthropic-version2023-06-01Sim
content-typeapplication/jsonSim (para corpos JSON)
anthropic-betaLista de features beta, ex. files-api-2025-04-14Apenas quando a feature exigir
+

A política de versionamento garante, para uma dada versão da Messages API, a preservação dos parâmetros de entrada e saída existentes. A Anthropic pode: adicionar inputs opcionais, adicionar valores à saída, alterar condições de erro e adicionar novas variantes a enums de saída (por exemplo, novos tipos de eventos de streaming). Trate enums de saída como abertos.

+ + +

2.2. Mapa de endpoints REST

+
+ + + + + + + + + + + + + + + + + + +
RecursoMétodo & caminhoDescrição
MessagesPOST /v1/messagesGera a próxima mensagem da conversa
Token CountingPOST /v1/messages/count_tokensConta tokens sem gerar
Batches — criarPOST /v1/messages/batchesCria lote de requisições
Batches — listarGET /v1/messages/batchesLista lotes (paginado)
Batches — recuperarGET /v1/messages/batches/{id}Estado do lote
Batches — resultadosGET /v1/messages/batches/{id}/resultsStream JSONL de resultados
Batches — cancelarPOST /v1/messages/batches/{id}/cancelInicia cancelamento
Batches — deletarDELETE /v1/messages/batches/{id}Remove lote (precisa estar ended)
Models — listarGET /v1/modelsModelos disponíveis
Models — recuperarGET /v1/models/{model_id}Metadados de um modelo
Files (beta)POST/GET/DELETE /v1/filesUpload/listagem/exclusão de arquivos
OAuth (WIF)POST /v1/oauth/tokenTroca de JWT por token de acesso
Admin / Organização/v1/organizations/*Admin API (requer chave sk-ant-admin...)
Compliance/v1/compliance/*Atividade, chats, arquivos (Claude Enterprise)
Managed Agents (beta)/v1/agents, /v1/sessions, /v1/environments …Harness de agentes gerenciados
+
+ + + + +
+

3. POST /v1/messages — corpo da requisição & resposta

+

Envia uma lista estruturada de mensagens de entrada (texto e/ou imagem) e o modelo gera a próxima mensagem. Pode ser usado para consultas únicas ou conversas multi-turno stateless.

+ + +

3.1. Parâmetros do corpo (request body)

+
+ + + + + + + + + + + + + + + + + + + + + + +
ParâmetroTipoObrig.Descrição
modelstring (Model)SimID do modelo, ex. claude-opus-4-8
messagesarray de MessageParamSimTurnos alternados user/assistant. content é string ou array de blocos. Limite de 100.000 mensagens por requisição
max_tokensnumberSimMáximo de tokens a gerar. 0 pré-aquece o cache sem gerar. Máximo varia por modelo
systemstring ou array de TextBlockParamNãoPrompt de sistema. Não existe role "system" em messages
metadataobjectNão{ user_id } — identificador opaco para detecção de abuso
stop_sequencesarray de stringNãoStrings que param a geração; produzem stop_reason: "stop_sequence"
streambooleanNãoStreaming via SSE
temperaturenumberNão0.0–1.0, default 1.0
top_pnumberNãoNucleus sampling (uso avançado)
top_knumberNãoAmostragem entre os top-K tokens (uso avançado)
toolsarray de ToolUnionNãoDefinições de ferramentas (function calling / server tools)
tool_choiceToolChoiceNãoauto · any · tool (específica) · none
thinkingThinkingConfigParamNãoadaptive (recomendado para Opus 4.8) · enabled (com budget_tokens) · disabled
service_tier"auto" ou "standard_only"NãoSeleção de tier de capacidade
containerstringNãoReuso de container entre requisições (code execution)
context_managementobjectNãoCompactação / edição de contexto server-side (beta)
output_format / output_configobjectNãoSaída estruturada (JSON schema) e nível de effort
mcp_serversarrayNãoServidores MCP remotos (MCP connector, beta)
inference_geostringNão"global" (default) ou "us" — residência de inferência (veja a seção 11.6)
+
Atenção (prefill): Claude Opus 4.8 e Sonnet 4.6 não suportam pré-preencher (prefill) a última mensagem assistant. Enviar um turno assistant final retorna 400 invalid_request_error. Use saída estruturada (output_config.format), instruções no system prompt ou structured outputs.
+ +

3.2. Objeto de resposta (Message)

+
+ + + + + + + + + + + + + +
CampoTipoDescrição
idstringIdentificador único da mensagem (ex. msg_013Zva...)
type"message"Sempre "message"
role"assistant"Sempre "assistant"
contentarray de ContentBlockBlocos gerados: text, thinking, redacted_thinking, tool_use, server_tool_use, web_search_tool_result, web_fetch_tool_result, code_execution_tool_result, container_upload, entre outros
modelstringModelo que atendeu a requisição
stop_reasonenumMotivo do término (tabela abaixo)
stop_sequencestring ou nullA stop_sequence que disparou o término, se houver
usageUsageContagem de tokens / billing (seção 3.3)
stop_detailsobjectDetalhes de recusa: category ("cyber"/"bio"; no Fable 5 também "reasoning_extraction" — bloqueio por engenharia reversa/duplicação de outputs sob os ToS, desde 09/06/2026), explanation, type: "refusal"
containerobject{ id, expires_at } quando a ferramenta de code execution é usada
+

Valores de stop_reason:

+
+ + + + + + + + + +
ValorSignificado
"end_turn"Ponto de parada natural
"max_tokens"Atingiu max_tokens ou o máximo do modelo
"stop_sequence"Gerou uma das stop_sequences
"tool_use"O modelo invocou uma ou mais ferramentas
"pause_turn"Turno longo pausado; reenvie a resposta para continuar
"refusal"Classificador de streaming interveio por política
+
Nota: em modo não-streaming, stop_reason é sempre não-nulo. Em streaming, é null no evento message_start e não-nulo nos demais.
+ +

3.3. Objeto Usage

+
+ + + + + + + + + + + +
CampoTipoDescrição
input_tokensnumberTokens de entrada (excluindo tokens de cache)
output_tokensnumberTokens de saída gerados
cache_creation_input_tokensnumberTokens usados para criar entrada de cache
cache_read_input_tokensnumberTokens lidos do cache
cache_creationobjectDetalhe: ephemeral_5m_input_tokens e ephemeral_1h_input_tokens
server_tool_useobjectContagem de chamadas server-side: web_search_requests, web_fetch_requests
service_tierenum"standard" · "priority" · "batch"
inference_geostringGeografia onde a inferência rodou
+
Dica: total de tokens de entrada = input_tokens + cache_creation_input_tokens + cache_read_input_tokens.
+ +

3.4. Exemplo completo

+
+
+ + +
+
+
curl https://api.anthropic.com/v1/messages \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{"role": "user", "content": "Olá, Claude"}]
+  }'
+
+
+
import anthropic
+client = anthropic.Anthropic()
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+print(message.content[0].text)
+print(message.usage)  # Usage(input_tokens=..., output_tokens=...)
+
+
+
Resposta JSON (200) +
{
+  "id": "msg_013Zva2CMHLNnXjNJJKqJ2EF",
+  "type": "message",
+  "role": "assistant",
+  "content": [{"type": "text", "text": "Olá! Sou o Claude."}],
+  "model": "claude-opus-4-8",
+  "stop_reason": "end_turn",
+  "stop_sequence": null,
+  "usage": {
+    "input_tokens": 2095,
+    "output_tokens": 503,
+    "cache_creation_input_tokens": 0,
+    "cache_read_input_tokens": 0,
+    "service_tier": "standard"
+  }
+}
+
+
+ + + + +
+

4. POST /v1/messages/count_tokens

+

Conta o número de tokens de uma Message — incluindo tools, imagens e documentos — sem criar a mensagem. Útil para validar custos e limites antes de enviar. Aceita os mesmos parâmetros relevantes da Messages API: model, messages, system, tools, tool_choice, thinking, mcp_servers (mas não max_tokens).

+ +

A resposta é um objeto simples com input_tokens (number). O limite de tamanho de requisição é o mesmo da Token Counting API (32 MB).

+
+
+ + +
+
+
curl https://api.anthropic.com/v1/messages/count_tokens \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "model": "claude-opus-4-8",
+    "messages": [{"role": "user", "content": "Olá, mundo"}]
+  }'
+# -> {"input_tokens": 10}
+
+
+
count = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    messages=[{"role": "user", "content": "Olá, mundo"}],
+)
+print(count.input_tokens)  # 10
+
+
+
+ + + + +
+

5. Message Batches API

+

Processa múltiplas requisições da Messages API de uma vez, de forma assíncrona, com desconto de 50% sobre o preço padrão. Um lote começa a processar imediatamente e pode levar até 24 horas. Resultados ficam disponíveis por 29 dias. Para o lado conceitual do processamento em lote (quando usar, trade-offs, custo), veja a Parte A — Batch Processing; aqui detalhamos os endpoints REST e o ciclo de vida do objeto MessageBatch.

+ + +

5.1. Criar um lote

+

O corpo é um array requests; cada item tem um custom_id (único por lote, usado para casar resultados) e params (os mesmos parâmetros da Messages API).

+
+
+ + +
+
+
curl https://api.anthropic.com/v1/messages/batches \
+  --header "x-api-key: $ANTHROPIC_API_KEY" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "content-type: application/json" \
+  --data '{
+    "requests": [
+      {
+        "custom_id": "req-1",
+        "params": {
+          "model": "claude-opus-4-8",
+          "max_tokens": 1024,
+          "messages": [{"role": "user", "content": "Olá, mundo"}]
+        }
+      }
+    ]
+  }'
+
+
+
batch = client.messages.batches.create(
+    requests=[
+        {
+            "custom_id": "req-1",
+            "params": {
+                "model": "claude-opus-4-8",
+                "max_tokens": 1024,
+                "messages": [{"role": "user", "content": "Olá, mundo"}],
+            },
+        },
+    ]
+)
+print(batch.id, batch.processing_status)
+
+
+ +

5.2. Objeto MessageBatch e ciclo de vida

+
+ + + + + + + + + + + + + +
CampoTipoDescrição
idstringEx. msgbatch_013Zva...
type"message_batch"Sempre "message_batch"
processing_statusenum"in_progress" · "canceling" · "ended"
request_countsobjectprocessing, succeeded, errored, canceled, expired
created_atstring (RFC 3339)Criação
ended_atstringQuando todas as requisições terminaram (só após ended)
expires_atstringExpiração (24h após criação)
archived_atstringQuando os resultados ficaram indisponíveis
cancel_initiated_atstringInício do cancelamento, se houve
results_urlstringURL do arquivo .jsonl (só após ended)
+
Nota: os contadores em request_counts permanecem zerados (exceto processing) até o lote inteiro terminar. Um lote precisa estar ended antes de ser deletado — cancele primeiro se ainda estiver em progresso. A exclusão retorna { "id": "...", "type": "message_batch_deleted" }.
+ +

5.3. Resultados em JSONL

+

O endpoint /results faz stream de um arquivo .jsonl: cada linha é um MessageBatchIndividualResponse com custom_id e result. Os resultados não são garantidos na ordem das requisições — use custom_id para casar. O result.type assume: "succeeded" (com message), "errored" (com error), "canceled" ou "expired".

+
Linha JSONL de resultado (succeeded) +
{
+  "custom_id": "req-1",
+  "result": {
+    "type": "succeeded",
+    "message": {
+      "id": "msg_abc123",
+      "type": "message",
+      "role": "assistant",
+      "content": [{"type": "text", "text": "Olá!"}],
+      "stop_reason": "end_turn",
+      "usage": {"input_tokens": 11, "output_tokens": 4}
+    }
+  }
+}
+
+
+
+ +
+
+
# Após .processing_status == "ended"
+result_stream = client.messages.batches.results("msgbatch_abc123")
+for entry in result_stream:
+    if entry.result.type == "succeeded":
+        print(entry.custom_id, entry.result.message.content)
+    elif entry.result.type == "errored":
+        print(entry.custom_id, "erro:", entry.result.error)
+
+
+
+ + + + +
+

6. Models API

+

Determina quais modelos estão disponíveis para a sua conta. Modelos mais recentes aparecem primeiro. Dois endpoints: GET /v1/models (lista paginada) e GET /v1/models/{model_id} (recupera um).

+
Nota de fronteira: a tabela geral de modelos, capacidades e preços da API direta vive na Parte A — Modelos, e a referência detalhada da Models API em Parte A — Models API. Esta seção documenta o esquema do endpoint do ponto de vista REST/SDK, sem reproduzir a tabela de modelos. Os IDs específicos de plataforma (Bedrock/Vertex/Foundry, que diferem da API direta) são registrados na seção 9.
+ + +

6.1. Listar modelos & paginação

+

Query params: before_id / after_id (cursores) e limit (default 20, de 1 a 1000). A resposta traz data[], has_more, first_id e last_id.

+

Cada ModelInfo traz: id, type: "model", display_name, created_at (RFC 3339), max_input_tokens, max_tokens e um objeto capabilities que reporta suporte a batch, citations, code_execution, context_management, effort (níveis low/medium/high/max/xhigh), image_input, pdf_input, structured_outputs e thinking (tipos adaptive/enabled).

+
+
+ + +
+
+
curl https://api.anthropic.com/v1/models \
+  --header "anthropic-version: 2023-06-01" \
+  --header "x-api-key: $ANTHROPIC_API_KEY"
+
+
+
for model in client.models.list(limit=20):
+    print(model.id, model.display_name, model.max_input_tokens)
+
+info = client.models.retrieve("claude-opus-4-8")
+print(info.created_at, info.capabilities)
+
+
+
Resposta JSON (200) — recortada +
{
+  "data": [
+    {
+      "id": "claude-opus-4-8",
+      "type": "model",
+      "display_name": "Claude Opus 4.8",
+      "created_at": "2025-11-01T00:00:00Z",
+      "capabilities": {
+        "batch": {"supported": true},
+        "thinking": {"supported": true, "types": {"adaptive": {"supported": true}, "enabled": {"supported": true}}},
+        "effort": {"supported": true, "low": {"supported": true}, "medium": {"supported": true}, "high": {"supported": true}, "max": {"supported": true}, "xhigh": {"supported": true}}
+      }
+    }
+  ],
+  "has_more": true,
+  "first_id": "...",
+  "last_id": "..."
+}
+
+
+ + + + +
+

7. Files API (lado REST)

+

A Files API (beta — header anthropic-beta: files-api-2025-04-14) permite enviar arquivos uma vez e referenciá-los por file_id em múltiplas requisições, em vez de reenviar bytes. Os recursos são escopados por workspace. Endpoints sob /v1/files: upload, listar, recuperar metadados, baixar e deletar. O limite de tamanho de requisição da Files API é 500 MB.

+ +
Nota: a profundidade conceitual da Files API (tipos de documento, citações, vínculo com blocos document) é coberta na Parte B. Aqui registramos o lado REST/SDK. No SDK Python, o upload aceita PathLike, tupla (filename, content, content_type) ou BinaryIO, via client.beta.files.upload(...).
+
+
+ +
+
+
from pathlib import Path
+from anthropic import Anthropic
+
+client = Anthropic()
+
+# Upload (beta)
+f = client.beta.files.upload(file=Path("/caminho/relatorio.pdf"))
+
+# Referência por file_id na Messages API
+resp = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text", "text": "Resuma este documento."},
+            {"type": "document", "source": {"type": "file", "file_id": f.id}},
+        ],
+    }],
+    betas=["files-api-2025-04-14"],
+)
+
+
+
+ + + + +
+

8. Erros & rate limits

+ + +

8.1. Códigos HTTP e tipos de erro

+
+ + + + + + + + + + + + + +
Statuserror.typeSignificado
400invalid_request_errorFormato/conteúdo inválido (também outros 4XX não listados)
401authentication_errorProblema com a chave da API (ou credenciais AWS no Claude Platform on AWS)
402billing_errorProblema de billing/pagamento
403permission_errorChave sem permissão para o recurso
404not_found_errorRecurso não encontrado
413request_too_largeExcede o tamanho máximo de bytes
429rate_limit_errorAtingiu um rate limit
500api_errorErro interno inesperado
504timeout_errorTimeout durante o processamento (use streaming)
529overloaded_errorAPI temporariamente sobrecarregada
+

Limites de tamanho de requisição: Messages 32 MB · Token Counting 32 MB · Batch 256 MB · Files 500 MB. Exceder retorna 413 (na API direta, devolvido pelo Cloudflare antes de chegar aos servidores).

+ +

8.2. Formato do erro & request ID

+

Erros são sempre JSON com um objeto error de topo (type + message) e um request_id. Toda resposta inclui o header request-id (ex. req_018Ee...) — inclua-o em tickets de suporte. Nos SDKs, leia message._request_id.

+
{
+  "type": "error",
+  "error": {
+    "type": "not_found_error",
+    "message": "The requested resource could not be found."
+  },
+  "request_id": "req_011CSHoEeqs5C35K2UUqR7Fy"
+}
+
Nota (Claude Platform on AWS): respostas trazem dois IDs — o AWS (x-amzn-requestid, primário, indexado no CloudTrail) e o Anthropic (request-id, secundário). Use o AWS para CloudTrail e o Anthropic para o suporte da Anthropic.
+ +

8.3. Rate limit headers & retry/backoff

+

A API direta retorna headers de rate limit que permitem reagir antes do 429:

+
+ + + + + + + +
HeaderSignificado
anthropic-ratelimit-requests-limit / -remaining / -resetLimite, restante e reset de requisições por minuto
anthropic-ratelimit-input-tokens-limit / -remaining / -resetTokens de entrada por minuto
anthropic-ratelimit-output-tokens-limit / -remaining / -resetTokens de saída por minuto
retry-afterSegundos a esperar antes de tentar novamente (em 429)
+
Atenção: erros 529 podem ocorrer sob alta carga global. Um aumento abrupto de uso pode gerar 429 por limites de aceleração — aumente o tráfego gradualmente. Implemente retry com backoff exponencial (os SDKs já fazem 2 tentativas por padrão em conexão, 408, 409, 429 e ≥500). Em streaming SSE, um erro pode ocorrer após o 200, fora do mecanismo padrão.
+
Nota: Microsoft Foundry não inclui os headers de rate limit da Anthropic — gerencie via ferramentas do Azure. Veja a Rate Limits API para ler programaticamente os limites configurados.
+ +
+ + + + +
+

9. Plataformas: Bedrock, Vertex AI, Foundry & Claude Platform on AWS

+

Os SDKs oficiais suportam quatro plataformas além da API de primeira parte. Todas usam o mesmo formato da Messages API; o que muda é a base URL, a autenticação e os IDs de modelo.

+
+ + + + + + + +
PlataformaQuem opera o stackBase URLAuthClient SDK (Python)
Claude in Amazon BedrockAWSbedrock-mantle.{region}.api.awsIAM/SigV4 (ou bearer token)AnthropicBedrockMantle
Claude on Vertex AIGoogle Cloud (parceiro){location}-aiplatform.googleapis.comCredenciais GCP (ADC)AnthropicVertex
Claude in Microsoft FoundryAnthropic (billing via Azure){resource}.services.ai.azure.com/anthropicAPI key ou Entra IDAnthropicFoundry
Claude Platform on AWSAnthropic (billing via AWS Marketplace)aws-external-anthropic.{region}.api.awsIAM/SigV4 ou API keyAnthropicAWS Beta
+ + +

9.1. Amazon Bedrock

+

Claude in Amazon Bedrock roda em infraestrutura gerenciada pela AWS com zero operator access da Anthropic, servindo a Messages API em /anthropic/v1/messages. IDs de modelo carregam o prefixo anthropic. — ex. anthropic.claude-opus-4-8 e anthropic.claude-haiku-4-5 (ambos abertos a todos os clientes Bedrock).

+

Autenticação: três caminhos — service role do Bedrock (recomendado), IAM assumed roles (sessão máx. 12h) e bearer tokens (12h, menos preferido). Instalação: pip install -U "anthropic[bedrock]" (Python) ou npm install @anthropic-ai/bedrock-sdk.

+
+
+ + +
+
+
from anthropic import AnthropicBedrockMantle
+
+client = AnthropicBedrockMantle(aws_region="us-east-1")
+
+message = client.messages.create(
+    model="anthropic.claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+print(message.content[0].text)
+
+
+
curl https://bedrock-mantle.us-east-1.api.aws/anthropic/v1/messages \
+  --aws-sigv4 "aws:amz:us-east-1:bedrock-mantle" \
+  --user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \
+  -H "x-amz-security-token: $AWS_SESSION_TOKEN" \
+  -H "content-type: application/json" \
+  -H "anthropic-version: 2023-06-01" \
+  -d '{
+    "model": "anthropic.claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{"role": "user", "content": "Olá, Claude"}]
+  }'
+
+
+
Nota: Bedrock oferece endpoints Global (roteamento dinâmico, sem prêmio) e Regional (data residency, prêmio de 10%). Cota padrão: 2 milhões de input TPM (até 4 milhões sem aprovação adicional da Anthropic). Recursos não suportados no Bedrock incluem: Files API, server-side tools (code execution, web search/fetch, advisor), Agent Skills, MCP connector, Batches, Models, Admin/Compliance e Managed Agents. A integração legada (InvokeModel/Converse) usa o client AnthropicBedrock e tem formato de request/response próprio; este guia foca a integração atual (Messages API) — para o mapeamento de shapes da legada, consulte a página oficial. + claude-in-amazon-bedrock · legada: claude-on-amazon-bedrock-legacy
+ +

9.2. Google Vertex AI

+

A API Vertex é quase idêntica à Messages API, com duas diferenças no formato: (1) model não vai no corpo — é parte da URL do endpoint GCP; (2) anthropic_version vai no corpo (não no header) e deve valer vertex-2023-10-16. IDs de modelo: claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5@20251001 (datado). Instalação: pip install -U google-cloud-aiplatform "anthropic[vertex]".

+
+
+ + +
+
+
from anthropic import AnthropicVertex
+
+# Antes: gcloud auth application-default login
+client = AnthropicVertex(project_id="MY_PROJECT_ID", region="global")
+
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=100,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+print(message)
+
+
+
MODEL_ID=claude-opus-4-8
+LOCATION=global
+PROJECT_ID=MY_PROJECT_ID
+
+curl -X POST \
+  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
+  -H "Content-Type: application/json" \
+  "https://$LOCATION-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/anthropic/models/${MODEL_ID}:streamRawPredict" \
+  -d '{
+    "anthropic_version": "vertex-2023-10-16",
+    "messages": [{"role": "user", "content": "Olá, Claude"}],
+    "max_tokens": 100
+  }'
+
+
+
Nota: Vertex oferece endpoints global, multi-region e regional (estes últimos com prêmio de 10%). Payload limitado a 30 MB. Claude Opus 4.8 e Sonnet 4.6 têm janela de 1M tokens no Vertex. Recursos não suportados são semelhantes aos do Bedrock (sem Files, code execution/web fetch/advisor, Agent Skills, MCP connector, Batches, Models, Admin/Compliance, Managed Agents).
+ +

9.3. Microsoft Foundry

+

Em Foundry, os modelos rodam na infraestrutura da Anthropic; é uma integração comercial para billing/acesso via Azure. Hierarquia: resource (segurança/billing) contém deployments (instâncias do modelo). O nome do deployment é o valor passado em model. Base URL: https://{resource}.services.ai.azure.com/anthropic/v1/*. Auth: API key (header api-key ou x-api-key) ou Entra ID (Authorization: Bearer). Suportado pelos SDKs C#, Java, PHP, Python e TypeScript (Go e Ruby não têm suporte nativo).

+
+
+ + +
+
+
import os
+from anthropic import AnthropicFoundry
+
+client = AnthropicFoundry(
+    api_key=os.environ.get("ANTHROPIC_FOUNDRY_API_KEY"),
+    resource="example-resource",  # nome do resource
+)
+
+message = client.messages.create(
+    model="claude-opus-4-8",   # nome do deployment
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá!"}],
+)
+print(message.content)
+
+
+
curl https://{resource}.services.ai.azure.com/anthropic/v1/messages \
+  -H "content-type: application/json" \
+  -H "api-key: YOUR_AZURE_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -d '{
+    "model": "claude-opus-4-8",
+    "max_tokens": 1024,
+    "messages": [{"role": "user", "content": "Olá!"}]
+  }'
+
+
+
Nota: Claude Opus 4.8 e Sonnet 4.6 têm janela de 1M tokens no Foundry. Recursos não suportados: Admin API, Compliance API, Models API e Message Batches API. Para suporte, forneça request-id e apim-request-id. Não há headers de rate limit da Anthropic — use o monitoramento do Azure.
+ +

9.4. Claude Platform on AWS

+

Dá a experiência completa da plataforma Anthropic (Messages API, Agent Skills, code execution, features beta) operada pela Anthropic, acessada via conta AWS com billing pelo AWS Marketplace. Diferente do Bedrock (onde a AWS opera o stack), aqui a AWS provê apenas a camada de auth (SigV4/API key), controle IAM e billing.

+

Setup obrigatório (uma vez por conta AWS): habilitar outbound web identity federation com aws iam enable-outbound-web-identity-federation — sem isso toda requisição retorna "Outbound web identity federation is disabled for your account". É preciso um workspace ID (formato wrkspc_..., vinculado a uma região AWS) e definir ANTHROPIC_AWS_WORKSPACE_ID + AWS_REGION. Instalação: pip install -U "anthropic[aws]".

+
+
+ +
+
+
from anthropic import AnthropicAWS
+
+# Lê ANTHROPIC_AWS_WORKSPACE_ID e resolve credenciais via cadeia padrão AWS (SigV4)
+client = AnthropicAWS(aws_region="us-west-2")
+
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+print(message.content[0].text)
+
+
+
Atenção: precedência de credenciais do client AnthropicAWS: (1) api_key → x-api-key; (2) aws_access_key+aws_secret_access_key → SigV4; (3) aws_profile → SigV4; (4) ANTHROPIC_AWS_API_KEY → x-api-key; (5) cadeia padrão de credenciais AWS → SigV4. A região é obrigatória (sem fallback). As chaves de API são geradas no AWS Console (não no Claude Console). Tokens de curto prazo (12h) podem ser gerados pelas bibliotecas token-generator da AWS.
+
Nota: escolha Bedrock (não Claude Platform on AWS) se precisar de FedRAMP High, IL4/IL5, HIPAA-ready ou que a AWS seja o único processador de dados. Claude Platform on AWS suporta AWS PrivateLink e o parâmetro inference_geo.
+
+ + + + +
+

10. Claude Managed Agents

+

Os Claude Managed Agents são um harness de agente pré-construído e configurável que roda em infraestrutura gerenciada — ideal para tarefas longas e trabalho assíncrono. Em vez de construir seu próprio loop de agente, execução de ferramentas e runtime, você obtém um ambiente onde o Claude lê arquivos, roda comandos, navega na web e executa código com segurança, com prompt caching e compactação embutidos.

+ +
Atenção (beta): Managed Agents está em Beta. Todas as requisições exigem o header anthropic-beta: managed-agents-2026-04-01 (o SDK define automaticamente). Por ser stateful (sessões longas com histórico e estado server-side), não é elegível a ZDR nem a BAA HIPAA. Dreams exige adicionalmente dreaming-2026-04-21. Rate limits: 300 req/min em endpoints de criação, 600 req/min em leitura.
+
Novidades de 09/06/2026: (1) scheduled deployments — sessões executadas em agenda cron sem scheduler próprio (doc: managed-agents/scheduled-deployments); (2) vaults agora suportam credenciais por variável de ambiente, injetadas com segurança no sandbox (para CLIs/SDKs/serviços que autenticam via env var); (3) os eventos de webhook session.thread_* ganharam o campo session_thread_id, identificando a thread multi-agente que disparou o evento.
+ +

10.1. Conceitos centrais

+
+ + + + + + + +
ConceitoDescrição
AgentModelo + system prompt + tools + servidores MCP + skills. Criado uma vez e referenciado por ID; é versionado
EnvironmentOnde as sessões rodam: container cloud gerenciado pela Anthropic ou self_hosted (sua infra)
SessionInstância de um agente em um environment, executando uma tarefa e gerando outputs; mantém histórico
EventsMensagens trocadas entre sua aplicação e o agente (turnos de usuário, resultados de tools, status)
+ +

10.2. Quickstart: agente → environment → sessão → eventos

+

O fluxo é: criar um agente (com o toolset agent_toolset_20260401 que habilita bash, operações de arquivo, web search etc.), criar um environment, iniciar uma sessão e então enviar eventos user.message, recebendo respostas via SSE.

+
+
+ + +
+
+
from anthropic import Anthropic
+
+client = Anthropic()  # define o beta header automaticamente
+
+# 1) Agente
+agent = client.beta.agents.create(
+    name="Coding Assistant",
+    model="claude-opus-4-8",
+    system="Você é um assistente de código. Escreva código limpo e documentado.",
+    tools=[{"type": "agent_toolset_20260401"}],
+)
+
+# 2) Environment (container cloud)
+env = client.beta.environments.create(
+    name="quickstart-env",
+    config={"type": "cloud", "networking": {"type": "unrestricted"}},
+)
+
+# 3) Sessão
+session = client.beta.sessions.create(
+    agent=agent.id,
+    environment_id=env.id,
+    title="Sessão quickstart",
+)
+print(agent.id, env.id, session.id)
+
+
+
# 1) Criar agente
+curl https://api.anthropic.com/v1/agents \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: managed-agents-2026-04-01" \
+  -H "content-type: application/json" \
+  -d '{
+    "name": "Coding Assistant",
+    "model": "claude-opus-4-8",
+    "system": "Você é um assistente de código.",
+    "tools": [{"type": "agent_toolset_20260401"}]
+  }'
+
+# 3) Iniciar sessão (após criar environment)
+curl https://api.anthropic.com/v1/sessions \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: managed-agents-2026-04-01" \
+  -H "content-type: application/json" \
+  -d '{"agent": "'"$AGENT_ID"'", "environment_id": "'"$ENVIRONMENT_ID"'"}'
+
+
+ +

10.3. Environments & containers

+

Um environment é criado uma vez e referenciado por ID a cada sessão; várias sessões compartilham o environment, mas cada uma recebe um container isolado. Containers cloud vêm com Ubuntu 22.04, x86_64, até 8 GB de RAM e 10 GB de disco, e rede desabilitada por padrão (habilite via networking na config). Vêm pré-instalados Python 3.12+, Node.js 20+, Go, Rust, Java 21+, Ruby, PHP, C/C++, clientes SQLite/PostgreSQL/Redis e utilitários (git, curl, jq, ripgrep etc.).

+ + +

10.4. Self-hosted sandboxes & modelo de segurança

+

Os self-hosted sandboxes mantêm a orquestração na Anthropic mas movem a execução de tools para infra que você controla — o código, filesystem e egress de rede do agente nunca saem do seu ambiente. Um environment worker (processo seu) consome itens da fila de trabalho do environment self_hosted, baixa as skills do agente, roda tool calls localmente e devolve resultados. Filesystem: /workspace (trabalho/skills) e /mnt/session/outputs (outputs finais).

+ +
Cuidado (modelo de responsabilidade compartilhada): ao self-hospedar, você é responsável pela qualidade/hardening da imagem do container, controles de egress de rede, armazenamento e rotação do ANTHROPIC_ENVIRONMENT_KEY (a chave que autoriza o polling da fila — guarde em secret manager, nunca em env files ou imagens), isolamento de workloads não confiáveis e retenção/redação dos logs e conteúdo de sessão. A Anthropic não inspeciona sua imagem, não consegue revogar uma chave vazada antes de você detectá-la e não isola tools dentro do seu container.
+ +

10.5. Eventos & streaming

+

A comunicação é baseada em eventos ({domain}.{action}). Você envia eventos de usuário; recebe eventos de agente, sessão e span.

+
+ + + + + + + +
DireçãoEventos (exemplos)
User (envia)user.message · user.interrupt · user.custom_tool_result · user.tool_confirmation · user.define_outcome · user.tool_result (self-hosted)
Agent (recebe)agent.message · agent.thinking · agent.tool_use · agent.tool_result · agent.mcp_tool_use · agent.custom_tool_use · agent.thread_context_compacted
Session (recebe)session.status_running · session.status_idle (com stop_reason) · session.status_rescheduled · session.status_terminated · session.updated · session.error
Span (recebe)span.model_request_start · span.model_request_end (com model_usage) · span.outcome_evaluation_*
+ + +

10.6. Tools, skills, permission policies, memory, vaults, outcomes

+
+ + + + + + + + + + + + + +
RecursoO que faz
Tools (agent_toolset_20260401)Toolset pré-construído: bash, operações de arquivo, web search/fetch; mais mcp_toolset e custom tools
SkillsPacotes de capacidade carregados no container (baixados para /workspace/skills/<nome>/)
Permission policiesalways_allow (executa sem confirmação) ou always_ask (pausa e aguarda aprovação via user.tool_confirmation). Custom tools não são governadas por políticas
Memory storesColeção de documentos texto escopada por workspace, montada como diretório na sessão; cada alteração cria uma memory version imutável (audit trail). Requer o agent toolset
Vaults & credentialsRegistram credenciais de terceiros uma vez e referenciam por ID na criação da sessão (per-user). Workspace-scoped
Define outcomesDefine o "pronto" e uma rubrica; o harness provisiona um grader em janela de contexto separada que avalia e devolve gaps para o agente iterar
Dreams Research PreviewJob assíncrono que lê uma memory store + transcrições e produz uma nova store reorganizada (dedup, atualização, novos insights); a store de entrada nunca é modificada
GitHubMonta repositório no container e conecta ao GitHub MCP para clonar, ler e abrir PRs (repos são cacheados entre sessões)
Multi-agentUm coordenador delega a outros agentes em session threads isoladas; compartilham container, filesystem e vault, mas têm contexto/tools próprios. Padrões: paralelização, especialização, escalonamento
WebhooksNotificam mudanças de estado sem polling; entregam type+id (busque o objeto via GET). Assinados com header X-Webhook-Signature e segredo whsec_...; valide com o helper unwrap() do SDK
+ +
Nota de fronteira: a Parte C também cobre Managed Agents do ângulo de ferramentas/skills/MCP. Aqui o foco é a superfície REST/governança (endpoints /v1/agents, /v1/sessions, /v1/environments, eventos, segurança self-hosted, retenção). Coordene com a Parte C para evitar duplicação de conteúdo conceitual de tools.
+
+ + + + +
+

11. Governança & Admin

+

O plano de governança gerencia membros, workspaces, chaves, limites, custos, retenção e residência de dados. A maior parte usa a Admin API, que exige uma chave especial sk-ant-admin... (distinta das chaves padrão) provisionável apenas por membros com role admin.

+ +

11.1. Admin API

+

Permite gerenciar programaticamente os recursos da organização: membros e roles, convites, workspaces e seus membros, e chaves de API. Indisponível para contas individuais (configure uma organização). Endpoints sob /v1/organizations/*, autenticados com x-api-key: $ANTHROPIC_ADMIN_KEY.

+ +

Roles de organização:

+
+ + + + + + + + +
RolePermissões
userUsar o Workbench
claude_code_userWorkbench + Claude Code
developerWorkbench + gerenciar chaves de API
billingWorkbench + gerenciar billing
adminTudo acima + gerenciar usuários
+
+
+ +
+
+
# Listar membros da organização
+curl "https://api.anthropic.com/v1/organizations/users?limit=10" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
+
+# Info da organização
+curl "https://api.anthropic.com/v1/organizations/me" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
+
+
+
Atenção: novas chaves de API só podem ser criadas no Claude Console (não via Admin API). Admins de organização não podem ser removidos via API. Convites expiram em 21 dias. No Claude Platform on AWS, apenas os endpoints de workspace (/v1/organizations/workspaces) estão disponíveis.
+ +

11.2. Workspaces

+

Workspaces organizam o uso da API dentro de uma organização — separam projetos/ambientes/times mantendo billing centralizado. IDs usam o prefixo wrkspc_. Máximo de 100 workspaces por organização (arquivados não contam). O Default Workspace não pode ser renomeado/arquivado/deletado e não tem ID (aparece como null em relatórios).

+ +

Chaves de API são escopadas a um único workspace. Recursos escopados por workspace incluem Files, Message Batches e Skills; o prompt cache é isolado por workspace na API direta, Claude Platform on AWS e Foundry (por organização no Bedrock/Vertex). Roles de workspace: Workspace User, Limited Developer, Developer, Admin e Billing (herdada). Limites de workspace podem ser menores (não maiores) que os da organização.

+ +

11.3. Autenticação: API keys vs Workload Identity Federation

+

Há dois métodos de autenticação, com o mesmo acesso aos endpoints:

+
+ + + + + +
MétodoCredencialMelhor para
API keySegredo longo sk-ant-api... no header x-api-keyDev local, protótipos, scripts, servidores single-tenant
Workload Identity Federation (WIF)Token bearer de curta duração trocado do JWT do seu IdPProdução em nuvem (AWS, GCP, Azure), CI/CD, Kubernetes — elimina segredos estáticos
+ + +

11.4. Workload Identity Federation (WIF)

+

WIF permite que cargas de trabalho autentiquem com tokens OIDC de curta duração emitidos por um IdP que você já opera (AWS IAM, Google Cloud, ou qualquer emissor OIDC como GitHub Actions, Kubernetes, SPIFFE, Microsoft Entra ID, Okta), em vez de chaves estáticas sk-ant-.... O workload troca seu JWT em POST /v1/oauth/token (grant jwt-bearer da RFC 7523) por um token de acesso sk-ant-oat01-... de curta duração, que o SDK renova automaticamente.

+ +

Três recursos no Console expressam "tokens assinados pelo emissor X, com claims Y, podem agir como service account Z":

+
+ + + + + + +
RecursoPrefixoPapel
Service accountsvac_...Identidade não-humana que o token federado representa; ativa-se ao ser adicionada a um workspace
Federation issuerfdis_...Registra o IdP (URL do iss + fonte JWKS: discovery/explicit_url/inline)
Federation rulefdrl_...Ponte: match (subject_prefix/audience/claims/CEL) → target (service account) → authorization (scope, default workspace:developer; token_lifetime_seconds 60–86400, default 3600)
+

O corpo da troca de token (POST /v1/oauth/token) exige: grant_type (urn:ietf:params:oauth:grant-type:jwt-bearer), assertion (o JWT), federation_rule_id, organization_id, service_account_id e workspace_id (condicional). A resposta segue OAuth 2.0 (access_token, token_type, expires_in, scope).

+
+
+ + +
+
+
from anthropic import Anthropic, WorkloadIdentityCredentials, IdentityTokenFile
+
+client = Anthropic(
+    credentials=WorkloadIdentityCredentials(
+        identity_token_provider=IdentityTokenFile("/var/run/secrets/anthropic.com/token"),
+        federation_rule_id="fdrl_...",
+        organization_id="00000000-0000-0000-0000-000000000000",
+        service_account_id="svac_...",
+        workspace_id="wrkspc_...",
+    ),
+)
+
+message = client.messages.create(
+    model="claude-sonnet-4-6",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+print(message.content[0].text)
+
+
+
# 1) Trocar JWT do IdP por token de acesso Anthropic
+RESPONSE=$(curl -sS https://api.anthropic.com/v1/oauth/token \
+  -H "content-type: application/json" \
+  --data '{
+    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
+    "assertion": "'"$JWT"'",
+    "federation_rule_id": "fdrl_...",
+    "organization_id": "00000000-0000-0000-0000-000000000000",
+    "service_account_id": "svac_...",
+    "workspace_id": "wrkspc_..."
+  }')
+ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r .access_token)
+
+# 2) Chamar a API com Authorization: Bearer
+curl https://api.anthropic.com/v1/messages \
+  -H "authorization: Bearer $ACCESS_TOKEN" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "content-type: application/json" \
+  --data '{"model":"claude-sonnet-4-6","max_tokens":1024,"messages":[{"role":"user","content":"Olá"}]}'
+
+
+

Provedores de identidade suportados (guias dedicados): AWS · Google Cloud · Microsoft Azure · GitHub Actions · Kubernetes · SPIFFE · Okta.

+
Atenção (precedência): ANTHROPIC_API_KEY fica acima dos tiers de federação na cadeia de precedência — uma chave esquecida no ambiente silenciosamente sobrescreve o WIF. Ao migrar, confirme que ANTHROPIC_API_KEY está removida em todo lugar (env do container, secrets de CI, perfis de shell). Use ant auth status para ver qual fonte venceu. O token mintado vive o menor entre o token_lifetime_seconds da regra e o dobro da vida restante do JWT (piso de 60s); o SDK renova em expiração-120s (advisory) e expiração-30s (mandatória).
+ +

11.5. Rate Limits API

+

Lê programaticamente os limites configurados para a organização e workspaces (mesma informação da página Limits do Console). Parte da Admin API (chave sk-ant-admin...). Endpoint org: GET /v1/organizations/rate_limits; workspace: GET /v1/organizations/workspaces/{id}/rate_limits (só retorna overrides; ausências são herdadas). É somente leitura — para alterar, use a aba Limits do Console.

+ +

Cada entrada é um grupo de rate limit com group_type (model_group, batch, token_count, files, skills, web_search) e uma lista limits de pares {type, value} — requests_per_minute, input_tokens_per_minute, output_tokens_per_minute, enqueued_batch_requests etc. Filtre por ?model= (apenas no endpoint org) ou ?group_type=.

+ +

11.6. Usage & Cost API

+

Acesso programático granular a uso e custo históricos. Parte da Admin API. Dois endpoints: GET /v1/organizations/usage_report/messages (uso — tokens por modelo/workspace/service tier; buckets 1m/1h/1d) e GET /v1/organizations/cost_report (custo em USD, granularidade diária). Dados aparecem em ~5 minutos; polling recomendado: 1×/min.

+ +
+
+ +
+
+
# Uso diário por modelo (últimos 7 dias)
+curl "https://api.anthropic.com/v1/organizations/usage_report/messages?\
+starting_at=2026-05-01T00:00:00Z&\
+ending_at=2026-05-08T00:00:00Z&\
+group_by[]=model&bucket_width=1d" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
+
+# Custo por workspace (mensal)
+curl "https://api.anthropic.com/v1/organizations/cost_report?\
+starting_at=2026-05-01T00:00:00Z&ending_at=2026-05-31T00:00:00Z&\
+group_by[]=workspace_id&group_by[]=description" \
+  --header "anthropic-version: 2023-06-01" \
+  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
+
+
+
Nota: filtros/grupos incluem api_key_ids[], workspace_ids[], models[], service_tiers[], context_window[], inference_geo (valores global/us/not_available) e speed (beta, exige fast-mode-2026-02-01). Custos de Priority Tier e de code execution não aparecem no endpoint de custo (use o de uso). Para custos por usuário do Claude Code, use a Claude Code Analytics API. Integrações prontas: CloudZero, Datadog, Grafana Cloud, Honeycomb, Vantage.
+ +

11.7. Retenção de dados (ZDR & HIPAA)

+

A Anthropic oferece dois arranjos de tratamento de dados para a Claude API: Zero Data Retention (ZDR) — dados do cliente não são armazenados em repouso após a resposta, exceto onde exigido por lei ou para combater abuso — e HIPAA readiness — para PHI, com BAA assinado e organização HIPAA-enabled.

+ +

ZDR cobre as APIs de Mensagens e Token Counting (e Claude Code com chaves Commercial/Enterprise). Não cobre: Console/Workbench, Managed Agents (stateful), produtos de consumo, Teams/Enterprise (exceto Claude Code via Enterprise com ZDR) e integrações de terceiros. HIPAA readiness é imposta no nível da organização: requisições com features não-elegíveis retornam 400.

+

Elegibilidade de features (recorte):

+
+ + + + + + + + + + + +
FeatureZDRHIPAA
Messages API / Token countingSimSim
Prompt caching / Extended & adaptive thinking / Citations / 1M contextSimSim
Structured outputsSim (qualificado)Sim (sem PHI no schema)
Context management (compaction/editing)SimNão
Web fetch / Advisor / Computer use / Tool searchSimNão
Batch processingNãoNão
Code execution / Programmatic tool callingNãoNão
Files API / Agent skills / MCP connector / Managed Agents / MCP tunnelsNãoNão
+
Atenção: CORS não é suportado para organizações com ZDR — use um backend proxy e nunca exponha chaves no JavaScript do navegador. Mesmo com ZDR/HIPAA, dados podem ser retidos por até 2 anos se sinalizados por violação de política. Bedrock/Vertex têm o provedor de nuvem como processador (consulte suas próprias políticas); Claude Platform on AWS segue a política da API direta (ZDR sob demanda; HIPAA indisponível).
+ +

11.8. Residência de dados

+

Dois controles independentes: Inference geo (onde a inferência roda, por requisição, via inference_geo) e Workspace geo (onde dados são armazenados em repouso, fixado na criação do workspace — atualmente só "us").

+ +

Valores de inference_geo: "global" (default) e "us" (só infra dos EUA). A resposta reporta onde rodou em usage.inference_geo. Suportado em Claude Opus 4.8, Sonnet 4.6 e posteriores (modelos anteriores retornam 400). Configurável por workspace via allowed_inference_geos e default_inference_geo (campo data_residency na Admin API).

+
Nota (pricing): inferência US-only (inference_geo: "us") custa 1,1× a tarifa padrão em todas as categorias de token (e drena 1,1 token por token no burndown de Priority Tier). Roteamento global usa preço padrão. Disponível na API direta e Claude Platform on AWS; suportado também na Batch API (por requisição). Em Bedrock/Vertex/Foundry, a região é determinada pela URL/inference profile (parâmetro não se aplica).
+ +

11.9. Compliance API

+

Acesso programático à atividade, chats, arquivos, projetos e usuários da organização para auditoria e governança. Habilitada sob demanda: organizações Claude Enterprise têm acesso completo; organizações Claude Console têm acesso apenas ao Activity Feed. Endpoints sob /v1/compliance/*, autenticados por x-api-key.

+ +

Dois tipos de chave: uma Compliance Access Key (sk-ant-api01-..., criada no claude.ai) alcança todos os endpoints; uma Admin API key (sk-ant-admin01-...) alcança apenas o Activity Feed. Scopes: read:compliance_activities (feed), read:compliance_user_data (chats/arquivos/projetos/usuários), read:compliance_org_data (organizações/roles/grupos) e delete:compliance_user_data (deletes). Limite: 600 req/min por organização-pai. O Activity Feed retém 6 anos e novos eventos são consultáveis em ~1 min.

+
+
+ +
+
+
# Evento de atividade mais recente
+curl "https://api.anthropic.com/v1/compliance/activities?limit=1" \
+  --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY"
+
+
+
Nota: o Activity Feed registra quem fez o quê e quando (autenticação, criação de chat/arquivo, ações administrativas) — não captura texto de prompt nem respostas. Para corpos de mensagem e conteúdo de arquivo, use os endpoints de conteúdo com uma Compliance Access Key (read:compliance_user_data), que servem apenas dados do claude.ai. Deletes são imediatos e irreversíveis. Padrões de consumo: window polling (com created_at.gte/.lt) ou cursor-driven (persistindo first_id/before_id); correlacione com SIEM por actor.user_id/email_address/ip_address/created_at.
+
+ + + + + + + + +
+

Parte E — SDK Python (anthropic): referência exaustiva

+

Cobertura completa e fiel do SDK oficial anthropic para Python, extraída de + platform.claude.com/docs/en/api/sdks/python, + do api.md do repositório oficial e da referência da API. Aprofunda o que a + Parte D (D1 · SDKs) resume: instalação e extras, clientes síncrono/assíncrono e todas as + opções de construtor, mensagens, streaming, ferramentas, batches, contagem de tokens, arquivos, modelos, + paginação automática, hierarquia de erros, retries/timeouts, respostas cruas, sistema de tipos, logging, + requisições não documentadas, cliente HTTP customizado, namespace beta e os cinco clientes de plataforma. + Todos os exemplos usam os modelos atuais (claude-opus-4-8, claude-sonnet-4-6, + claude-haiku-4-5).

+
+ +
+

E1. Instalação, requisitos e extras

+

O SDK anthropic dá acesso conveniente à API REST da Anthropic a partir de Python, com suporte a + operações síncronas e assíncronas, streaming e integrações com Amazon Bedrock, Vertex AI, Microsoft Foundry e + Claude Platform on AWS. Requer Python 3.9 ou superior.

+
# Instalação base
+pip install anthropic
+
+# Extras por integração de plataforma
+pip install "anthropic[bedrock]"   # Amazon Bedrock
+pip install "anthropic[vertex]"    # Google Vertex AI
+pip install "anthropic[aws]"       # Claude Platform on AWS
+# Microsoft Foundry já vem incluso no pacote base
+
+# Backend assíncrono alternativo (melhor concorrência)
+pip install "anthropic[aiohttp]"
+
+ + + + + + + +
ExtraHabilita
anthropic[bedrock]Clientes AnthropicBedrockMantle / AnthropicBedrock
anthropic[vertex]Cliente AnthropicVertex
anthropic[aws]Cliente AnthropicAWS (beta)
anthropic[aiohttp]Backend HTTP DefaultAioHttpClient (assíncrono)
+

E1.1 Versão instalada em tempo de execução

+

Se um recurso novo não aparece, confirme a versão efetivamente carregada no ambiente Python:

+
import anthropic
+print(anthropic.__version__)
+
Dica: use python-dotenv + para carregar ANTHROPIC_API_KEY="..." de um arquivo .env e manter a chave fora do controle de versão.
+

O pacote segue SemVer, mas mudanças que afetam apenas tipos estáticos, internos públicos não + documentados, ou que não impactam a maioria dos usuários, podem sair como minor.

+ +
+ +
+

E2. Inicializando o cliente (síncrono e assíncrono)

+

O cliente síncrono é Anthropic; o assíncrono é AsyncAnthropic + (mesma interface, com await). Ambos leem a chave de ANTHROPIC_API_KEY por padrão.

+
+
+ + +
+
+
import os
+from anthropic import Anthropic
+
+client = Anthropic(
+    api_key=os.environ.get("ANTHROPIC_API_KEY"),  # padrão; pode ser omitido
+)
+
+message = client.messages.create(
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+    model="claude-opus-4-8",
+)
+print(message.content)
+
+
+
import os, asyncio
+from anthropic import AsyncAnthropic
+
+client = AsyncAnthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
+
+async def main() -> None:
+    message = await client.messages.create(
+        max_tokens=1024,
+        messages=[{"role": "user", "content": "Olá, Claude"}],
+        model="claude-opus-4-8",
+    )
+    print(message.content)
+
+asyncio.run(main())
+
+
+ +

E2.1 Opções do construtor

+
+ + + + + + + + + + + +
OpçãoTipoPadrão / EnvDescrição
api_keystrANTHROPIC_API_KEYChave da API (header x-api-key).
auth_tokenstr—Token Bearer (ex.: Workload Identity Federation) como alternativa à API key.
base_urlstrANTHROPIC_BASE_URLSobrescreve a URL base (ex.: gateway/proxy).
timeoutfloat · httpx.Timeout600 s (10 min)Timeout global; aceita granularidade por fase.
max_retriesint2Retentativas automáticas com backoff exponencial.
default_headersdict—Headers padrão em todas as requisições.
default_querydict—Query params padrão em todas as requisições.
http_clientDefaultHttpxClient · DefaultAioHttpClienthttpxCliente HTTP customizado (proxies, transporte, backend).
+ +

E2.2 Backend aiohttp (melhor concorrência assíncrona)

+
import os, asyncio
+from anthropic import AsyncAnthropic, DefaultAioHttpClient
+
+async def main() -> None:
+    async with AsyncAnthropic(
+        api_key=os.environ.get("ANTHROPIC_API_KEY"),
+        http_client=DefaultAioHttpClient(),
+    ) as client:
+        message = await client.messages.create(
+            max_tokens=1024,
+            messages=[{"role": "user", "content": "Olá, Claude"}],
+            model="claude-opus-4-8",
+        )
+        print(message.content)
+
+asyncio.run(main())
+ +

E2.3 Gerenciando recursos HTTP

+

Por padrão, as conexões são fechadas quando o cliente é coletado pelo GC. Para controle explícito, use + .close() ou um context manager:

+
from anthropic import Anthropic
+
+with Anthropic() as client:
+    message = client.messages.create(
+        max_tokens=1024,
+        messages=[{"role": "user", "content": "Olá, Claude"}],
+        model="claude-opus-4-8",
+    )
+# cliente HTTP fechado automaticamente ao sair do bloco
+ +
+ +
+

E3. Mensagens e usage

+

O método central é client.messages.create(...) → retorna um objeto Message (modelo Pydantic). + O texto fica em message.content (lista de blocos); o consumo de tokens, em message.usage.

+
message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Explique a teoria das cordas em 1 parágrafo."}],
+)
+print(message.content[0].text)
+print(message.usage)   # Usage(input_tokens=25, output_tokens=13, ...)
+print(message.stop_reason)
+print(message._request_id)  # id da requisição (ver E13)
+
Tipos: os parâmetros aninhados são TypedDict (ex.: MessageParam, + ContentBlockParam); as respostas são modelos Pydantic (Message, TextBlock, + ToolUseBlock, ThinkingBlock, Usage). Veja a Parte D (D3) para o schema REST completo de parâmetros.
+ +
+ +
+

E4. Streaming (duas abordagens)

+

O SDK oferece duas formas de streaming via SSE — escolha conforme a necessidade:

+
+ + + + + +
AbordagemO que retornaQuando usar
messages.create(..., stream=True)Iterável de eventos brutos (não monta o objeto final). Menos memória.Quando você só quer os deltas e cuida da acumulação.
messages.stream(...) (context manager)Helper com .text_stream, acumulação e .get_final_message().Quando quer o texto incremental E o objeto Message final pronto.
+ +

E4.1 Iterável de eventos (stream=True)

+
+
+ + +
+
+
stream = client.messages.create(
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+    model="claude-opus-4-8",
+    stream=True,
+)
+for event in stream:
+    print(event.type)   # message_start, content_block_delta, ...
+
+
+
stream = await client.messages.create(
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+    model="claude-opus-4-8",
+    stream=True,
+)
+async for event in stream:
+    print(event.type)
+
+
+ +

E4.2 Helper com acumulação (messages.stream)

+
import asyncio
+from anthropic import AsyncAnthropic
+
+client = AsyncAnthropic()
+
+async def main() -> None:
+    async with client.messages.stream(
+        max_tokens=1024,
+        messages=[{"role": "user", "content": "Diga olá!"}],
+        model="claude-opus-4-8",
+    ) as stream:
+        async for text in stream.text_stream:    # apenas os deltas de texto
+            print(text, end="", flush=True)
+        print()
+        message = await stream.get_final_message()  # objeto Message acumulado
+        print(message.to_json())
+
+asyncio.run(main())
+

O stream() retorna um MessageStreamManager; o objeto de stream expõe também eventos + específicos do SDK além de .text_stream. Veja a Parte A (A5) para os tipos de evento SSE.

+ +
+ +
+

E5. Ferramentas como funções Python (@beta_tool + tool_runner)

+

Além de definir ferramentas manualmente (ver Parte C), o SDK gera o schema da + ferramenta a partir da assinatura e do docstring de uma função Python via o decorador @beta_tool, e + executa o laço de tool use automaticamente com client.beta.messages.tool_runner(...).

+
import json
+from anthropic import Anthropic, beta_tool
+
+client = Anthropic()
+
+@beta_tool
+def get_weather(location: str) -> str:
+    """Obtém o clima de um local.
+
+    Args:
+        location: cidade e estado, ex.: San Francisco, CA
+    Returns:
+        String JSON com local, temperatura e condição.
+    """
+    return json.dumps({"location": location, "temperature": "68°F", "condition": "Sunny"})
+
+# tool_runner cuida automaticamente das chamadas de ferramenta
+runner = client.beta.messages.tool_runner(
+    max_tokens=1024,
+    model="claude-opus-4-8",
+    tools=[get_weather],
+    messages=[{"role": "user", "content": "Como está o tempo em SF?"}],
+)
+for message in runner:
+    print(message)
+

A cada iteração é feita uma requisição à API; se o Claude quiser chamar uma ferramenta dada, ela é executada + automaticamente e o resultado volta ao modelo na próxima iteração.

+ +
+ +
+

E6. Message Batches no SDK (client.messages.batches)

+

Conceito e limites na Parte A (A12) e o lado REST na Parte D (D5). + No SDK, cada requisição tem um custom_id e os mesmos params da Messages API.

+
batch = client.messages.batches.create(
+    requests=[
+        {"custom_id": "req-1", "params": {
+            "model": "claude-opus-4-8", "max_tokens": 1024,
+            "messages": [{"role": "user", "content": "Olá, mundo"}]}},
+        {"custom_id": "req-2", "params": {
+            "model": "claude-opus-4-8", "max_tokens": 1024,
+            "messages": [{"role": "user", "content": "Oi de novo, amigo"}]}},
+    ]
+)
+
+# Quando batch.processing_status == "ended", itere os resultados (stream JSONL):
+for entry in client.messages.batches.results(batch.id):
+    if entry.result.type == "succeeded":
+        print(entry.custom_id, entry.result.message.content)
+
+ + + + + + + + + +
MétodoCaminho RESTRetorno
batches.create(requests=[...])POST /v1/messages/batchesMessageBatch
batches.retrieve(id)GET /v1/messages/batches/{id}MessageBatch
batches.list(**params)GET /v1/messages/batchesSyncPage[MessageBatch]
batches.cancel(id)POST /v1/messages/batches/{id}/cancelMessageBatch
batches.delete(id)DELETE /v1/messages/batches/{id}DeletedMessageBatch
batches.results(id)GET /v1/messages/batches/{id}/resultsJSONLDecoder[MessageBatchIndividualResponse]
+ +
+ +
+

E7. Contagem de tokens (count_tokens e usage)

+

Veja o consumo real de qualquer resposta em message.usage, ou estime antes de enviar com + messages.count_tokens(...):

+
# Uso real, após a resposta
+message = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
+                                 messages=[{"role": "user", "content": "Olá"}])
+print(message.usage)            # Usage(input_tokens=25, output_tokens=13)
+
+# Estimativa antes do envio
+count = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    messages=[{"role": "user", "content": "Hello, world"}],
+)
+print(count.input_tokens)       # 10  (retorna MessageTokensCount)
+ +
+ +
+

E8. Upload de arquivos (client.beta.files)

+

Parâmetros que correspondem a uploads aceitam várias formas: um objeto PathLike (ex.: + pathlib.Path), uma tupla (filename, content, content_type), ou um objeto file-like + BinaryIO. No cliente assíncrono, PathLike é lido de forma assíncrona automaticamente.

+
from pathlib import Path
+from anthropic import Anthropic
+
+client = Anthropic()
+
+# Por caminho
+f = client.beta.files.upload(file=Path("/caminho/relatorio.pdf"))
+
+# Por bytes (tupla)
+client.beta.files.upload(file=("nota.txt", b"meus bytes", "text/plain"))
+
+# Referenciando o arquivo numa mensagem (header beta obrigatório)
+resp = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": [
+        {"type": "text", "text": "Resuma este documento."},
+        {"type": "document", "source": {"type": "file", "file_id": f.id}},
+    ]}],
+    betas=["files-api-2025-04-14"],
+)
+
+ + + + + + + + +
MétodoCaminho RESTRetorno
beta.files.upload(file=...)POST /v1/filesFileMetadata
beta.files.list(**params)GET /v1/filesSyncPage[FileMetadata]
beta.files.retrieve_metadata(file_id)GET /v1/files/{id}FileMetadata
beta.files.download(file_id)GET /v1/files/{id}/contentBinaryAPIResponse
beta.files.delete(file_id)DELETE /v1/files/{id}DeletedFile
+

Profundidade de visão/PDF/documentos na Parte B (Files, PDF, Vision).

+ +
+ +
+

E9. Models API no SDK (client.models)

+
# Listar modelos disponíveis (paginado — ver E10)
+for m in client.models.list(limit=20):
+    print(m.id, m.display_name)
+
+# Recuperar um modelo específico e suas capacidades
+info = client.models.retrieve("claude-opus-4-8")
+print(info.max_input_tokens, info.max_output_tokens)
+print(info.capabilities)   # ModelCapabilities: thinking, effort, context_management, ...
+
+ + + + + +
MétodoCaminhoRetorno
models.list(**params)GET /v1/modelsSyncPage[ModelInfo]
models.retrieve(model_id)GET /v1/models/{model_id}ModelInfo
+

Tipos: ModelInfo, ModelCapabilities, CapabilitySupport, + ThinkingCapability, EffortCapability, ContextManagementCapability. + Tabela canônica de modelos na Parte A (A3).

+ +
+ +
+

E10. Paginação automática

+

Métodos list são paginados. A forma idiomática é iterar diretamente — o SDK busca as páginas + seguintes conforme necessário (SyncPage / AsyncPage):

+
+
+ + +
+
+
all_batches = []
+for batch in client.messages.batches.list(limit=20):  # busca páginas automaticamente
+    all_batches.append(batch)
+
+
+
all_batches = []
+async for batch in client.messages.batches.list(limit=20):
+    all_batches.append(batch)
+
+
+

Para controle granular de páginas:

+
first_page = client.messages.batches.list(limit=20)
+if first_page.has_next_page():
+    print(first_page.next_page_info())
+    next_page = first_page.get_next_page()
+    print(len(next_page.data))
+
+# Ou trabalhe diretamente com os dados da página
+print(first_page.last_id)
+for batch in first_page.data:
+    print(batch.id)
+ +
+ +
+

E11. Tratamento de erros e hierarquia de exceções

+

Quando o SDK não consegue conectar, ou a API retorna 4xx/5xx, uma subclasse de APIError é levantada.

+
import anthropic
+from anthropic import Anthropic
+
+client = Anthropic()
+try:
+    message = client.messages.create(
+        max_tokens=1024,
+        messages=[{"role": "user", "content": "Olá, Claude"}],
+        model="claude-opus-4-8",
+    )
+except anthropic.APIConnectionError as e:
+    print("Servidor inacessível")
+    print(e.__cause__)              # exceção subjacente (httpx)
+except anthropic.RateLimitError as e:
+    print("429 recebido; aplicar backoff.")
+except anthropic.APIStatusError as e:
+    print("Outro status fora de 2xx:", e.status_code)
+    print(e.response)
+
+ + + + + + + + + + + + +
Status HTTPExceção
400BadRequestError
401AuthenticationError
403PermissionDeniedError
404NotFoundError
409ConflictError
422UnprocessableEntityError
429RateLimitError
≥ 500InternalServerError
N/A (rede)APIConnectionError (e APITimeoutError)
+

Todas herdam de APIError; APIStatusError agrupa as que têm status_code e + response. Ver Parte D (D8) para o formato de erro REST e request-id.

+ +
+ +
+

E12. Retries, timeouts e requisições longas

+

E12.1 Retries

+

Por padrão, certos erros são retentados 2 vezes com backoff exponencial curto: + erros de conexão, 408, 409, 429 e ≥ 500.

+
from anthropic import Anthropic
+
+# Padrão para todas as requisições
+client = Anthropic(max_retries=0)   # padrão é 2
+
+# Por requisição
+client.with_options(max_retries=5).messages.create(
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+    model="claude-opus-4-8",
+)
+

E12.2 Timeouts

+

Por padrão, as requisições expiram após 10 minutos. Aceita float ou + httpx.Timeout; em timeout, lança APITimeoutError (e a requisição é retentada).

+
import httpx
+from anthropic import Anthropic
+
+client = Anthropic(timeout=20.0)  # 20 s (padrão = 10 min)
+
+# Granular por fase
+client = Anthropic(timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0))
+
+# Por requisição
+client.with_options(timeout=5.0).messages.create(
+    max_tokens=1024, model="claude-opus-4-8",
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+
Requisições longas: evite max_tokens alto sem streaming — + conexões ociosas podem cair. O SDK lança ValueError se uma requisição não-streaming for + estimada em mais de ~10 min; passar stream=True ou ajustar timeout desativa esse erro. + O SDK ativa TCP keep-alive para reduzir quedas por ociosidade (sobrescrevível via http_client).
+ +
+ +
+

E13. Resposta crua, streaming de corpo e Request ID

+

E13.1 Request ID

+

Todo objeto de resposta expõe ._request_id (do header request-id) — útil para logar + falhas e reportar à Anthropic. É a única propriedade _ pública.

+
message = client.messages.create(max_tokens=1024, model="claude-opus-4-8",
+    messages=[{"role": "user", "content": "Olá, Claude"}])
+print(message._request_id)  # ex.: req_018EeWyXxfu5pfWkrYcMdjWG
+

E13.2 with_raw_response (headers + corpo já lido)

+
response = client.messages.with_raw_response.create(
+    max_tokens=1024, model="claude-opus-4-8",
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+)
+print(response.headers.get("request-id"))
+message = response.parse()   # objeto que messages.create() retornaria
+print(message.content)
+

E13.3 with_streaming_response (corpo sob demanda)

+

Diferente de with_raw_response (que lê o corpo inteiro de imediato), + with_streaming_response exige context manager e só lê ao chamar .read(), .text(), + .json(), .iter_bytes(), .iter_text(), .iter_lines() ou .parse().

+
with client.messages.with_streaming_response.create(
+    max_tokens=1024, model="claude-opus-4-8",
+    messages=[{"role": "user", "content": "Olá, Claude"}],
+) as response:
+    print(response.headers.get("request-id"))
+    for line in response.iter_lines():
+        print(line)
+ +
+ +
+

E14. Sistema de tipos (request/response)

+
    +
  • Requisições: parâmetros aninhados são TypedDict — autocompletar e checagem no editor.
  • +
  • Respostas: modelos Pydantic, com .to_json() e .to_dict().
  • +
+
message = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá"}])
+json_str = message.to_json()   # string JSON
+data = message.to_dict()       # dict
+
+# Distinguir campo null vs ausente
+if message.some_field is None:
+    if "some_field" not in message.model_fields_set:
+        print("campo ausente na resposta")
+    else:
+        print("campo veio como null")
+
+# Propriedades não documentadas
+extra = message.model_extra     # dict com campos extras
+
VS Code: defina python.analysis.typeCheckingMode como + basic para ver erros de tipo cedo.
+ +
+ +
+

E15. Logging, requisições não documentadas e cliente HTTP custom

+

E15.1 Logging

+

O SDK usa o módulo logging padrão. Habilite com a variável de ambiente:

+
export ANTHROPIC_LOG=debug   # ou info
+

E15.2 Endpoints/params não documentados

+
# Endpoint não documentado (respeita retries/timeout do cliente)
+import httpx
+response = client.post("/foo", cast_to=httpx.Response, body={"my_param": True})
+print(response.json())
+
+# Param/header/query extra (sobrescrevem os documentados de mesmo nome!)
+client.messages.create(
+    model="claude-opus-4-8", max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá"}],
+    extra_headers={"X-Custom": "1"},
+    extra_query={"debug": "true"},
+    extra_body={"experimental": {"flag": True}},
+)
+
Segurança: extra_headers/extra_query/extra_body + sobrescrevem parâmetros documentados de mesmo nome — use apenas com dados confiáveis.
+

E15.3 Cliente HTTP customizado (proxies, transporte)

+
import httpx
+from anthropic import Anthropic, DefaultHttpxClient
+
+client = Anthropic(
+    base_url="http://meu.servidor.example.com:8083",  # ou env ANTHROPIC_BASE_URL
+    http_client=DefaultHttpxClient(
+        proxy="http://meu.proxy.example.com",
+        transport=httpx.HTTPTransport(local_address="0.0.0.0"),
+    ),
+)
+# Por requisição:
+client.with_options(http_client=DefaultHttpxClient())
+
Use DefaultHttpxClient / DefaultAsyncHttpxClient + (e não httpx.Client cru) para preservar timeouts e limites de conexão padrão do SDK.
+

E15.4 Header de versão

+

O SDK envia automaticamente anthropic-version: 2023-06-01. Sobrescrever via + default_headers ou extra_headers pode causar comportamento indefinido — evite salvo necessidade real.

+ +
+ +
+

E16. Namespace beta

+

Recursos beta ficam sob client.beta.*. Para habilitar uma feature beta, inclua o + beta header apropriado + no campo betas ao criar a mensagem.

+
resp = client.beta.messages.create(
+    model="claude-opus-4-8", max_tokens=1024,
+    messages=[{"role": "user", "content": "..."}],
+    betas=["files-api-2025-04-14"],   # ex.: Files API
+)
+
+ + + + + + + + + + + +
Namespace betaPrincipais métodos
client.beta.messages · .batchescreate, count_tokens, tool_runner; batches create/retrieve/list/cancel/delete/results
client.beta.modelslist, retrieve
client.beta.filesupload, list, retrieve_metadata, download, delete
client.beta.agents · .versionscreate/retrieve/update/list/archive (Managed Agents — ver Parte D)
client.beta.sessions · .events/.resources/.threadscreate/retrieve/update/list/delete/archive; eventos list/send/stream
client.beta.vaults · .credentialscreate/retrieve/update/list/delete/archive; mcp_oauth_validate
client.beta.memory_stores · .memoriescreate/retrieve/update/list/delete
client.beta.skills · client.beta.user_profiles · client.beta.environmentsCRUD de skills, perfis de usuário e ambientes
+

Tipos beta espelham os estáveis com prefixo Beta (ex.: BetaMessage, BetaUsage, + BetaModelInfo, FileMetadata).

+ +
+ +
+

E17. Clientes de plataforma (Bedrock, Vertex, Foundry, AWS)

+

Os cinco clientes vêm no pacote base anthropic (alguns exigem extras). Detalhes de cada plataforma + na Parte D (D9).

+
+ + + + + + + + +
ProvedorClasse (import de anthropic)Extra
Bedrock (novo)AnthropicBedrockMantleanthropic[bedrock]
Bedrock (InvokeModel legado)AnthropicBedrockanthropic[bedrock]
Vertex AIAnthropicVertexanthropic[vertex]
Microsoft FoundryAnthropicFoundry—
Claude Platform on AWS BetaAnthropicAWSanthropic[aws]
+
# Exemplos de inicialização
+from anthropic import AnthropicBedrockMantle, AnthropicVertex, AnthropicAWS
+
+bedrock = AnthropicBedrockMantle()           # novo padrão p/ Bedrock
+vertex  = AnthropicVertex(region="us-east5", project_id="meu-projeto")
+aws     = AnthropicAWS(workspace_id="...")   # ou env ANTHROPIC_AWS_WORKSPACE_ID (beta)
+
+msg = bedrock.messages.create(
+    model="anthropic.claude-opus-4-8",       # IDs com prefixo de plataforma — ver Parte D
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Olá"}],
+)
+
Recomendação: use AnthropicBedrockMantle em projetos novos; + AnthropicBedrock permanece para apps existentes que usam a API InvokeModel do Bedrock.
+ +
+ + + + +
+

Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk): referência exaustiva

+

Cobertura completa e fiel do SDK oficial @anthropic-ai/sdk, extraída de + platform.claude.com/docs/en/api/sdks/typescript + e do repositório oficial. Espelha a Parte E (SDK Python) para o ecossistema + JS/TS: instalação e runtimes suportados, cliente e todas as opções, mensagens e tipos, streaming + (iterável e por event handlers), helpers de ferramentas (Zod/JSON + ToolError), + helpers de MCP, batches, contagem de tokens, upload de arquivos (toFile), modelos e paginação, + hierarquia de erros, retries/timeouts (incluindo a fórmula dinâmica), respostas cruas, logging, + requisições não documentadas, fetch/proxy customizado, namespace beta, pacotes de plataforma + e o aviso de uso no navegador. Todos os exemplos usam os modelos atuais + (claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5).

+
+ +
+

F1. Instalação e runtimes suportados

+
npm install @anthropic-ai/sdk
+# ou: pnpm add @anthropic-ai/sdk · yarn add @anthropic-ai/sdk · bun add @anthropic-ai/sdk
+

Requer TypeScript ≥ 4.9. Runtimes oficialmente suportados:

+
+ + + + + + + + + + + + +
RuntimeSuporte
Node.js20 LTS+ (versões não-EOL)
Denov1.28.0+
Bun1.0+
Cloudflare WorkersSim
Vercel Edge RuntimeSim
Nitrov2.6+
Jest28+ com ambiente "node" ("jsdom" não suportado)
Navegador (browser)Desabilitado por padrão — habilite com dangerouslyAllowBrowser: true (ver F18)
React NativeNão suportado
+
SemVer: o pacote segue SemVer, mas mudanças que afetam apenas tipos + estáticos, internos públicos não documentados, ou de impacto mínimo, podem sair como minor.
+ +
+ +
+

F2. Inicializando o cliente e opções

+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic({
+  apiKey: process.env["ANTHROPIC_API_KEY"], // padrão; pode ser omitido
+});
+
+const message = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Olá, Claude" }],
+});
+console.log(message.content);
+

F2.1 Opções do construtor

+
+ + + + + + + + + + + + + + + +
OpçãoTipoPadrão / EnvDescrição
apiKeystringANTHROPIC_API_KEYChave da API (header x-api-key).
authTokenstringANTHROPIC_AUTH_TOKENToken Bearer (ex.: WIF) como alternativa à API key.
baseURLstringhttps://api.anthropic.com · ANTHROPIC_BASE_URLSobrescreve a URL base.
timeoutnumber (ms)600000 (10 min; dinâmico p/ max_tokens alto — ver F12)Timeout da requisição.
maxRetriesnumber2Retentativas automáticas com backoff.
defaultHeadersobject—Headers padrão em todas as requisições.
defaultQueryobject—Query params padrão.
fetchOptionsRequestInit—Opções repassadas ao fetch (proxy, agent — ver F15).
fetchfunçãoglobalThis.fetchImplementação de fetch customizada.
logLevelstring'warn' · ANTHROPIC_LOGdebug | info | warn | error | off.
loggerLoggerglobalThis.consoleLogger custom (pino, winston, bunyan…).
dangerouslyAllowBrowserbooleanfalseHabilita execução no navegador (ver F18).
+ +
+ +
+

F3. Mensagens, tipos e usage

+

A biblioteca inclui definições TypeScript para todos os params de requisição e campos de resposta — + importáveis via o namespace Anthropic.*. Documentação de cada método/param aparece no hover do editor.

+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const params: Anthropic.MessageCreateParams = {
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Olá, Claude" }],
+};
+const message: Anthropic.Message = await client.messages.create(params);
+
+console.log(message.content[0]);   // ContentBlock (ex.: TextBlock)
+console.log(message.usage);        // { input_tokens: 25, output_tokens: 13 }
+console.log(message.stop_reason);  // "end_turn" | "max_tokens" | "tool_use" | ...
+console.log(message._request_id);  // ver F13
+ +
+ +
+

F4. Streaming (iterável e por event handlers)

+

Duas abordagens, como no Python: create({stream:true}) retorna um async iterable de eventos + (menos memória); messages.stream(...) adiciona event handlers e acumulação.

+

F4.1 Iterável de eventos (stream: true)

+
const stream = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Olá, Claude" }],
+  stream: true,
+});
+for await (const event of stream) {
+  console.log(event.type);   // message_start, content_block_delta, ...
+}
+// Para cancelar: break no loop, ou stream.controller.abort()
+

F4.2 Helper com event handlers (messages.stream)

+
const stream = client.messages
+  .stream({
+    model: "claude-opus-4-8",
+    max_tokens: 1024,
+    messages: [{ role: "user", content: "Diga olá!" }],
+  })
+  .on("text", (text) => process.stdout.write(text))      // delta de texto
+  .on("streamEvent", (event) => { /* evento bruto SSE */ })
+  .on("contentBlock", (block) => { /* bloco completo */ })
+  .on("message", (msg) => { /* mensagem parcial acumulada */ })
+  .on("finalMessage", (msg) => { /* mensagem final */ });
+
+const message = await stream.finalMessage();   // Promise<Message>
+console.log(message);
+
Handlers disponíveis: text, streamEvent, + contentBlock, message, finalMessage. O objeto de stream também é + async iterable (for await … of stream). Tipos de evento SSE na Parte A (A5).
+ +
+ +
+

F5. Helpers de ferramentas (Zod / JSON Schema + ToolError)

+

O SDK JS facilita criar e executar ferramentas com esquemas Zod ou JSON Schema, executadas + via client.beta.messages.toolRunner() — que passa os inputs do modelo à função certa e devolve o + resultado ao modelo automaticamente.

+
import Anthropic from "@anthropic-ai/sdk";
+import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
+import { z } from "zod";
+
+const anthropic = new Anthropic();
+
+const weatherTool = betaZodTool({
+  name: "get_weather",
+  description: "Obtém o clima atual de um local",
+  inputSchema: z.object({ location: z.string() }),
+  run: (input) => `O tempo em ${input.location} está nublado, 16°C`,
+});
+
+const finalMessage = await anthropic.beta.messages.toolRunner({
+  model: "claude-opus-4-8",
+  max_tokens: 1000,
+  messages: [{ role: "user", content: "Como está o tempo em São Paulo?" }],
+  tools: [weatherTool],
+});
+console.log(finalMessage.content);
+

F5.1 Erros de ferramenta (ToolError)

+

Para reportar um erro ao modelo, lance ToolError de dentro do run — diferente de um + Error comum, ele aceita content blocks (texto, imagem) na resposta de erro. Um Error + comum é convertido num bloco de texto.

+
import { ToolError } from "@anthropic-ai/sdk/lib/tools/BetaRunnableTool";
+
+const screenshotTool = betaZodTool({
+  name: "take_screenshot",
+  inputSchema: z.object({ url: z.string() }),
+  run: async (input) => {
+    if (!isValidUrl(input.url)) throw new ToolError(`URL inválida: ${input.url}`);
+    const result = await takeScreenshot(input.url);
+    if (result.error) {
+      throw new ToolError([
+        { type: "text", text: `Falha ao carregar: ${result.error}` },
+        { type: "image", source: { type: "base64", data: result.screenshot, media_type: "image/png" } },
+      ]);
+    }
+    return { type: "image", source: { type: "base64", data: result.screenshot, media_type: "image/png" } };
+  },
+});
+

Também é possível definir ferramentas manualmente via input_schema (JSON Schema) em + messages.create({tools:[...]}) — ver Parte C.

+ +
+ +
+

F6. Helpers de MCP (Model Context Protocol)

+

O SDK JS converte tipos MCP para tipos da Claude API, reduzindo boilerplate ao usar ferramentas, + prompts e recursos de servidores MCP locais. (Para servidores MCP remotos por URL + com suporte só a ferramentas, prefira o parâmetro mcp_servers — ver Parte C (MCP).)

+
import Anthropic from "@anthropic-ai/sdk";
+import { mcpTools, mcpMessages, mcpResourceToContent, mcpResourceToFile }
+  from "@anthropic-ai/sdk/helpers/beta/mcp";
+import { Client } from "@modelcontextprotocol/sdk/client/index.js";
+import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
+
+const anthropic = new Anthropic();
+const transport = new StdioClientTransport({ command: "mcp-server", args: [] });
+const mcpClient = new Client({ name: "my-client", version: "1.0.0" });
+await mcpClient.connect(transport);
+
+// Prompts MCP → mensagens
+const { messages } = await mcpClient.getPrompt({ name: "my-prompt" });
+await anthropic.beta.messages.create({
+  model: "claude-opus-4-8", max_tokens: 1024, messages: mcpMessages(messages),
+});
+
+// Ferramentas MCP com toolRunner
+const { tools } = await mcpClient.listTools();
+await anthropic.beta.messages.toolRunner({
+  model: "claude-opus-4-8", max_tokens: 1024,
+  messages: [{ role: "user", content: "Use as ferramentas disponíveis" }],
+  tools: mcpTools(tools, mcpClient),
+});
+
+// Recurso MCP como conteúdo / como arquivo
+const resource = await mcpClient.readResource({ uri: "file:///doc.txt" });
+mcpResourceToContent(resource);
+await anthropic.beta.files.upload({ file: mcpResourceToFile(resource) });
+
Erros: as funções de conversão lançam UnsupportedMCPValueError + se um valor MCP não for suportado (tipo de conteúdo/MIME inválido, recurso não-http/https).
+ +
+ +
+

F7. Message Batches (client.messages.batches)

+
const batch = await client.messages.batches.create({
+  requests: [
+    { custom_id: "req-1", params: {
+        model: "claude-opus-4-8", max_tokens: 1024,
+        messages: [{ role: "user", content: "Olá, mundo" }] } },
+    { custom_id: "req-2", params: {
+        model: "claude-opus-4-8", max_tokens: 1024,
+        messages: [{ role: "user", content: "Oi de novo, amigo" }] } },
+  ],
+});
+
+// Quando batch.processing_status === "ended":
+const results = await client.messages.batches.results(batch.id);
+for await (const entry of results) {
+  if (entry.result.type === "succeeded") console.log(entry.result.message.content);
+}
+

Conceito e limites na Parte A (A12); schema REST na Parte D (D5).

+ +
+ +
+

F8. Contagem de tokens (countTokens)

+
const count = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  messages: [{ role: "user", content: "Hello, world" }],
+});
+console.log(count.input_tokens);
+
+// Uso real após a resposta:
+const message = await client.messages.create(/* ... */);
+console.log(message.usage); // { input_tokens: 25, output_tokens: 13 }
+ +
+ +
+

F9. Upload de arquivos (toFile e variantes)

+

Parâmetros de upload aceitam: um File (ou objeto equivalente), uma Response do + fetch, um fs.ReadStream, ou o retorno do helper toFile. + Defina o content-type explicitamente — a Files API não o infere.

+
import fs from "fs";
+import Anthropic, { toFile } from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+// fs.ReadStream
+await client.beta.files.upload({
+  file: await toFile(fs.createReadStream("/caminho/data.json"), undefined, { type: "application/json" }),
+});
+// Web File API
+await client.beta.files.upload({ file: new File(["meus bytes"], "file.txt", { type: "text/plain" }) });
+// Response do fetch
+await client.beta.files.upload({ file: await fetch("https://site/arquivo") });
+// Buffer / Uint8Array
+await client.beta.files.upload({ file: await toFile(Buffer.from("meus bytes"), "file", { type: "text/plain" }) });
+

Profundidade de visão/PDF/documentos na Parte B; endpoints REST na Parte D (D7).

+ +
+ +
+

F10. Models API e paginação automática

+
// Recuperar
+const model = await client.models.retrieve("claude-opus-4-8");
+
+// Listar com auto-paginação (busca páginas conforme necessário)
+for await (const m of client.models.list({ limit: 20 })) console.log(m.id);
+
+// Uma página por vez + navegação manual
+let page = await client.messages.batches.list({ limit: 20 });
+for (const item of page.data) console.log(item);
+while (page.hasNextPage()) { page = await page.getNextPage(); }
+
+// Iterar páginas
+for await (const p of client.models.list().iterPages()) console.log(p.data);
+

Tabela canônica de modelos na Parte A (A3).

+ +
+ +
+

F11. Tratamento de erros

+
const message = await client.messages
+  .create({ model: "claude-opus-4-8", max_tokens: 1024,
+            messages: [{ role: "user", content: "Olá, Claude" }] })
+  .catch((err) => {
+    if (err instanceof Anthropic.APIError) {
+      console.log(err.status);  // 400
+      console.log(err.name);    // BadRequestError
+      console.log(err.headers); // { server: 'nginx', ... }
+    } else { throw err; }
+  });
+
+ + + + + + + + + + + + + +
StatusClasse
400BadRequestError
401AuthenticationError
403PermissionDeniedError
404NotFoundError
409ConflictError
422UnprocessableEntityError
429RateLimitError
≥ 500InternalServerError
redeAPIConnectionError
timeoutAPIConnectionTimeoutError
+

Todas herdam de Anthropic.APIError. Formato de erro REST na Parte D (D8).

+ +
+ +
+

F12. Retries e timeouts (incl. fórmula dinâmica)

+

F12.1 Retries

+

Padrão: 2 retentativas com backoff (conexão, 408, 409, 429, ≥500).

+
const client = new Anthropic({ maxRetries: 0 });   // padrão é 2
+// por requisição:
+await client.messages.create({ /* ... */ }, { maxRetries: 5 });
+

F12.2 Timeouts

+

Padrão: 10 minutos. Porém, se max_tokens for grande e você não estiver + usando streaming, o timeout default é calculado dinamicamente (até ~60 min):

+
// fórmula do default dinâmico (não-streaming, max_tokens grande):
+const minimum = 10 * 60;
+const calculated = (60 * 60 * maxTokens) / 128_000;
+const timeoutMs = (calculated < minimum ? minimum : calculated) * 1000;
+
+const client = new Anthropic({ timeout: 20 * 1000 }); // 20 s (override do default)
+await client.messages.create({ /* ... */ }, { timeout: 5 * 1000 }); // por requisição
+

Em timeout lança APIConnectionTimeoutError (e a requisição é retentada). Para requisições longas, + prefira streaming; passar stream:true ou timeout desativa o erro de "requisição > 10 min".

+ +
+ +
+

F13. Request ID e resposta crua (asResponse / withResponse)

+
// Request ID (header request-id) — para logar/correlacionar com o suporte
+const message = await client.messages.create({ /* ... */ });
+console.log(message._request_id); // req_018Ee...
+
+// .asResponse(): retorna o Response cru assim que os headers chegam (não consome o corpo)
+const response = await client.messages.create({ /* ... */ }).asResponse();
+console.log(response.headers.get("request-id"));
+
+// .withResponse(): consome o corpo e devolve { data, response }
+const { data, response: raw } = await client.messages.create({ /* ... */ }).withResponse();
+console.log(raw.headers.get("request-id"), data.content);
+ +
+ +
+

F14. Logging

+

Configure por variável de ambiente ANTHROPIC_LOG ou pela opção logLevel (que sobrescreve + a env). Níveis: debug ▸ info ▸ warn (padrão) ▸ error ▸ off. + No nível debug, todas as requisições/respostas HTTP são logadas (alguns headers de auth são redigidos).

+
// via opção
+const client = new Anthropic({ logLevel: "debug" });
+
+// logger custom (pino, winston, bunyan, consola, signale, @std/log)
+import pino from "pino";
+const logger = pino();
+new Anthropic({ logger: logger.child({ name: "Anthropic" }), logLevel: "debug" });
+
ANTHROPIC_LOG=debug node script.js
+ +
+ +
+

F15. Requisições não documentadas, fetch e proxies

+

F15.1 Endpoints/params não documentados

+
// endpoint não documentado (respeita retries/opções do cliente)
+await client.post("/some/path", { body: { some_prop: "foo" }, query: { arg: "bar" } });
+
+// param extra: use @ts-expect-error (não validado em runtime; enviado as-is)
+client.messages.create({
+  model: "claude-opus-4-8", max_tokens: 1024, messages: [/* ... */],
+  // @ts-expect-error baz ainda não é público
+  baz: "opção não documentada",
+});
+

F15.2 fetch customizado e fetchOptions

+
import Anthropic from "@anthropic-ai/sdk";
+import myFetch from "my-fetch";
+
+const client = new Anthropic({
+  fetch: myFetch,                 // ou globalThis.fetch = myFetch
+  fetchOptions: { /* RequestInit */ },
+});
+

F15.3 Proxies por runtime

+
+
+ + + +
+
+
import Anthropic from "@anthropic-ai/sdk";
+import * as undici from "undici";
+
+const proxyAgent = new undici.ProxyAgent("http://localhost:8888");
+const client = new Anthropic({ fetchOptions: { dispatcher: proxyAgent } });
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic({ fetchOptions: { proxy: "http://localhost:8888" } });
+
+
+
import Anthropic from "npm:@anthropic-ai/sdk";
+
+const httpClient = Deno.createHttpClient({ proxy: { url: "http://localhost:8888" } });
+const client = new Anthropic({ fetchOptions: { client: httpClient } });
+
+
+ +
+ +
+

F16. Namespace beta

+
const response = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: [
+    { type: "text", text: "Resuma este documento." },
+    { type: "document", source: { type: "file", file_id: "file_abc123" } },
+  ]}],
+  betas: ["files-api-2025-04-14"],   // habilita a feature beta via header
+});
+

Ative cada feature beta incluindo o beta header em betas: [...]. Espelha o namespace beta do Python (E16).

+ +
+ +
+

F17. Pacotes de plataforma (npm separados)

+

Diferente do Python (clientes no pacote base), no JS cada plataforma é um pacote npm separado:

+
+ + + + + + + +
PlataformaPacote npmCliente
Amazon Bedrock@anthropic-ai/bedrock-sdkAnthropicBedrockMantle (novo) · AnthropicBedrock (path bedrock-runtime/InvokeModel legado)
Google Vertex AI@anthropic-ai/vertex-sdkAnthropicVertex
Microsoft Foundry@anthropic-ai/foundry-sdkAnthropicFoundry
Claude Platform on AWS Beta@anthropic-ai/aws-sdkAnthropicAws (workspaceId ou ANTHROPIC_AWS_WORKSPACE_ID)
+
import AnthropicBedrock from "@anthropic-ai/bedrock-sdk";
+import AnthropicVertex from "@anthropic-ai/vertex-sdk";
+
+const bedrock = new AnthropicBedrock({ awsRegion: "us-east-1" });
+const vertex  = new AnthropicVertex({ projectId: "meu-projeto", region: "us-east5" });
+
+const msg = await bedrock.messages.create({
+  model: "anthropic.claude-opus-4-8",  // IDs com prefixo de plataforma — ver Parte D
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Olá" }],
+});
+

Detalhes por plataforma (IDs, auth) na Parte D (D9).

+ +
+ +
+

F18. Uso no navegador (dangerouslyAllowBrowser)

+
Perigo: habilitar dangerouslyAllowBrowser: true expõe sua + chave secreta no código client-side. Qualquer usuário com acesso ao navegador pode inspecionar e extrair as + credenciais. Use apenas em cenários controlados: ferramentas internas com usuários confiáveis, + ou desenvolvimento/depuração com credenciais efêmeras e rotacionadas — nunca com a chave de produção.
+
const client = new Anthropic({ apiKey: "...", dangerouslyAllowBrowser: true });
+

Padrão recomendado: faça as chamadas a partir de um backend e exponha apenas um endpoint seu ao navegador.

+ +
+
+

Apêndice

+

Notebooks do cookbook oficial, glossário consolidado e histórico deste guia.

+
+
+

Cookbook — notebooks & exemplos oficiais

+

Exemplos executáveis mantidos pela Anthropic. Use sempre os modelos atuais + (claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5) ao rodar.

+ +
+
+

Glossário

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TermoDefinição
Divulgação progressivaEstratégia das Skills de carregar metadados sempre, instruções ao acionar e recursos sob demanda.
Managed AgentHarness gerenciado (Agent, Environment, Session, Events) para tarefas longas/assíncronas.
MCP tunnelsForma outbound-only de expor servidores MCP de rede privada ao Claude, via cloudflared + proxy.
SigV4Assinatura de requisição AWS usada por Bedrock e Claude Platform on AWS.
SKILL.mdArquivo com frontmatter YAML (name, description) que define uma Agent Skill; carregado por divulgação progressiva.
WIF (Workload Identity Federation)Autenticação por token OIDC de curta duração via POST /v1/oauth/token (grant jwt-bearer).
ZDR (Zero Data Retention)Arranjo em que dados não são armazenados em repouso após a resposta da API.
@anthropic-ai/sdkPacote npm oficial do SDK JavaScript/TypeScript da Anthropic.
@beta_toolDecorador que gera o schema da ferramenta a partir da assinatura/docstring de uma função Python.
_request_idID da requisição (header request-id); única propriedade _ pública.
adaptive thinkingModo de raciocínio em que o modelo decide quando/quanto pensar; recomendado para Opus 4.8 (thinking: {type:"adaptive"}).
agent_toolset_20260401Toolset pré-construído de Managed Agents: bash, operações de arquivo, web search/fetch.
allowed_callersArray que define quem chama a ferramenta: "direct" (modelo) e/ou "code_execution_20260120" (sandbox).
Anthropic / AsyncAnthropicClasses de cliente síncrono e assíncrono do SDK Python.
anthropic-betaHeader que habilita features beta (ex. managed-agents-2026-04-01, files-api-2025-04-14).
anthropic-versionCabeçalho obrigatório de versão da API; valor atual: 2023-06-01.
ANTHROPIC_ENVIRONMENT_KEYChave que autoriza o worker self-hosted a consumir a fila de trabalho do environment.
ANTHROPIC_LOGVariável de ambiente para logging (debug | info).
AnthropicBedrockMantleCliente recomendado para Amazon Bedrock em projetos novos.
APIConnectionTimeoutErrorExceção lançada quando uma requisição expira (timeout) no SDK JS.
asResponse() / withResponse()Acessam o Response cru do fetch (headers); withResponse devolve { data, response }.
betasLista de beta headers passada em client.beta.messages.create para habilitar features beta.
betaZodToolHelper que define uma ferramenta a partir de um schema Zod, com função run() executada pelo toolRunner.
budget_tokensOrçamento fixo de tokens de pensamento no modo manual (thinking.type: "enabled").
cache_controlMarca breakpoint de prompt caching ({"type":"ephemeral"}, opcional "ttl":"1h").
cache_creation_input_tokensTokens escritos no cache; se ele e cache_read_input_tokens são 0, não houve cache.
cache_miss_reasonMotivo do cache miss, retornado com a beta cache-diagnosis-2026-04-07.
cache_read_input_tokensTokens lidos do cache (cobrados a 0,1× do input base).
citationsHabilita citações verificáveis ({"enabled": true}) em document/search_result.
clear_thinking_20251015Edit que remove blocos de pensamento antigos do contexto.
clear_tool_uses_20250919Edit que remove resultados de ferramenta antigos do contexto.
compact_20260112Edit que resume o histórico antigo (compaction) em vez de removê-lo.
containerParâmetro da Messages API usado para referenciar Skills (skill_id/type/version) e reusar contêineres de code execution.
context windowJanela de contexto: total de tokens referenciáveis (Opus 4.8 / Sonnet 4.6: 1M; Haiku 4.5: 200k).
context_managementControla edição/compactação de contexto via edits (betas context-management-2025-06-27 / compact-2026-01-12).
count_tokensEndpoint /v1/messages/count_tokens que estima input_tokens antes do envio.
custom_idIdentificador único (1–64 chars) de cada request num Message Batch.
dangerouslyAllowBrowserHabilita o SDK no navegador (expõe a chave — usar só em cenários controlados).
DefaultHttpxClient / DefaultAioHttpClientClientes HTTP do SDK (httpx padrão; aiohttp para concorrência assíncrona).
defer_loadingPropriedade que exclui a ferramenta do prompt inicial, carregando-a sob demanda via tool search; preserva o prompt cache.
displayComo o pensamento volta na resposta: summarized ou omitted (padrão no Opus 4.8).
documentBloco de conteúdo para PDF/texto/conteúdo customizado; suporta citations e cache_control.
eager_input_streamingHabilita fine-grained tool streaming (sem buffering/validação de JSON) em ferramentas de usuário.
effortEm output_config.effort: controla o gasto de tokens (low, medium, high, xhigh [só Opus 4.8], max). Padrão = high.
fetchOptionsRequestInit repassado ao fetch (proxy/agent/dispatcher por runtime).
file_idIdentificador de arquivo da Files API (beta files-api-2025-04-14) referenciável por source.type: "file".
imageBloco de conteúdo de imagem com source base64/url/file.
inference_geoControle de residência de inferência por requisição: global (default) ou us.
input_examplesExemplos de input válidos para guiar o Claude; não disponível em ferramentas server-side.
iterPages()Itera páginas inteiras (JS); hasNextPage()/getNextPage() para navegação manual.
max_retriesRetentativas automáticas (padrão 2) para erros de conexão/408/409/429/≥500.
max_tokensMáximo de tokens a gerar numa resposta; limitado pelo teto do modelo (Opus 4.8 / Sonnet 4.6: 128k; Haiku 4.5: 64k). Na Batch API, Opus 4.8/4.7/4.6 e Sonnet 4.6 chegam a 300k com o header beta output-300k-2026-03-24.
maxRetries (JS)Opção do cliente/requisição; padrão 2.
MCP connectorRecurso que conecta a Messages API a servidores MCP remotos sem cliente MCP separado (beta mcp-client-2025-11-20).
mcp_toolsetEntrada no array tools que configura quais ferramentas de um servidor MCP habilitar.
mcpTools / mcpMessagesHelpers que convertem tipos MCP (ferramentas/prompts/recursos) para tipos da Claude API.
messages.stream()Context manager de streaming com .text_stream e get_final_message() (acumula o Message final).
messages.stream().on(...)Streaming com event handlers (text, streamEvent, contentBlock, message, finalMessage) + finalMessage().
ModelInfoMetadados de modelo na Models API: id, display_name, created_at, max_input_tokens, capabilities.
output_config.formatJSON outputs (structured outputs): força a resposta a seguir um JSON Schema.
pause_turnMotivo de parada que indica que um turno de ferramenta server-side foi pausado; reenvie a conversa para continuar.
processing_statusEstado de um Message Batch: in_progress → ended.
redacted_thinkingBloco de pensamento criptografado por segurança; reenvie sem modificar.
search_resultBloco de resultado de busca para RAG com citações nativas (source/title/content).
search_result_locationLocalização de citação que aponta para search_result_index e blocos.
server_tool_useBloco que aparece quando uma ferramenta server-side roda; id prefixado por srvtoolu_. Não exige tool_result.
service_tierTier de capacidade: standard, priority ou batch.
signatureCampo opaco com o pensamento completo criptografado, usado para verificar/reconstruir blocos reenviados.
sk-ant-admin...Chave da Admin API (gerencia membros, workspaces, chaves).
snapshot fixoCada model ID mapeia para pesos imutáveis; a partir da 4.6 os IDs são sem data, mas ainda assim pinned (não evergreen).
speed: "fast"Fast mode (beta): saída até 2,5× mais rápida em Opus 4.8 a 6× o preço; header fast-mode-2026-02-01.
stop_reasonMotivo do término da geração: end_turn, max_tokens, stop_sequence, tool_use, pause_turn, refusal, model_context_window_exceeded.
strictPropriedade que força (grammar-constrained sampling) os inputs da ferramenta a casarem com o JSON Schema.
strict: trueStrict tool use: valida os inputs de uma ferramenta contra seu input_schema via sampling guiado por gramática.
svac_ / fdis_ / fdrl_Prefixos de service account, federation issuer e federation rule (WIF).
SyncPage / AsyncPageObjetos de página com auto-paginação (has_next_page, get_next_page, .data, .last_id).
systemPrompt de sistema — instruções/persona enviadas como campo de topo, não como turno de messages.
task_budgetTeto de tokens para a tarefa inteira (várias requisições); beta task-budgets-2026-03-13.
thinkingConfiguração de raciocínio estendido: adaptive (modelo decide), enabled (manual com budget_tokens) ou disabled.
toFileHelper do SDK JS para criar uploads a partir de ReadStream/Buffer/Uint8Array com content-type explícito.
tool_choiceControla a escolha de ferramentas: auto, any, tool ou none.
tool_resultBloco na mensagem do usuário que devolve o resultado de uma ferramenta client-side, casado por tool_use_id. Pode ter is_error: true.
tool_runnerclient.beta.messages.tool_runner — executa o laço de tool use automaticamente.
tool_useBloco de conteúdo na resposta do assistente que representa a requisição do Claude para chamar uma ferramenta (com id, name, input). Acompanha stop_reason: "tool_use".
ToolErrorErro lançável de dentro de uma tool que aceita content blocks (texto/imagem) na resposta de erro.
toolRunnerclient.beta.messages.toolRunner — executa o laço de tool use automaticamente (JS).
UsageObjeto de contagem de tokens: input/output, cache_creation/read, server_tool_use, service_tier, inference_geo.
whsec_Segredo de assinatura de webhook de Managed Agents (header X-Webhook-Signature).
with_options()Retorna um cliente com overrides por requisição (max_retries, timeout, http_client...).
with_raw_responseAcessa headers/corpo crus; .parse() devolve o objeto tipado.
with_streaming_responseLê o corpo sob demanda via context manager (.iter_lines, .read, .json...).
wrkspc_Prefixo de ID de workspace.
x-api-keyCabeçalho de autenticação com a chave do Claude Console.
+
+
+

Histórico deste guia

+
    +
  • 2026-05-24 — Versão completa, produzida por um time de 4 agentes Claude Opus 4.7 + em paralelo (orquestração + revisão Claude). Parte A (Fundamentos, Modelos, Mensagens, streaming, + stop_reason, structured outputs, effort, contexto, embeddings, batch), Parte B (adaptive/extended + thinking, prompt caching, cache diagnostics, context editing, compaction, visão, PDF, Files, citations), + Parte C (tool use e todas as ferramentas, Agent Skills, MCP) e Parte D (SDKs, referência REST completa, + Message Batches, Models/Files API, Managed Agents, governança/WIF/compliance, Bedrock/Vertex/Foundry). + Apêndice com cookbook, glossário e este histórico.
  • +
  • 2026-05-24 (Parte E + setup) — Adicionada a Parte E — SDK Python + (anthropic), referência exaustiva extraída da página oficial do SDK Python e do + api.md do repositório (clientes sync/async e opções de construtor, streaming, @beta_tool/ + tool_runner, batches, paginação, hierarquia de erros, retries/timeouts, respostas cruas, tipos, + logging, namespace beta e clientes de plataforma). Incluído o bloco Setup em 4 passos e o cookbook + expandido a partir do repositório claude-cookbooks.
  • +
  • 2026-05-24 (Parte F + foco Python/JS) — Adicionada a Parte F — SDK + JavaScript/TypeScript (@anthropic-ai/sdk), referência exaustiva paralela à do Python + (runtimes suportados, opções do cliente, streaming por event handlers, helpers de ferramentas Zod/JSON + + ToolError, helpers de MCP, batches, toFile, paginação, erros, fórmula dinâmica de + timeout, asResponse/withResponse, logging, proxies por runtime, namespace beta, + pacotes de plataforma e dangerouslyAllowBrowser). A tabela de SDKs foi focada em + Python e JavaScript/TypeScript (as demais linguagens oficiais são citadas apenas como referência).
  • +
  • 2026-05-24 (política de modelos) — Restrito aos modelos gerais atuais: + claude-opus-4-7 e claude-sonnet-4-6 (geração 4.6+: o ID puro, sem data, + é o snapshot fixo — não é ponteiro evergreen) e + claude-haiku-4-5 (geração pré-4.6: alias do snapshot datado claude-haiku-4-5-20251001). + Todas as tabelas oficiais que citavam gerações anteriores foram reescritas.
  • +
  • 2026-05-24 (verificação de versionamento) — Corrigida a linha de snapshot da tabela + de modelos: o Opus 4.7 não usa um snapshot datado ...-20251101 (essa data + pertence ao Opus 4.5 legado); na geração 4.6+ o ID dateless é o próprio snapshot canônico. Confirmado em + models/overview e models/model-ids-and-versions.
  • +
  • 2026-06-03 (migração Opus 4.8) — A linha Opus do guia migrou de + claude-opus-4-7 para claude-opus-4-8 (recomendado atual; o 4.7 passou a + Legacy). Specs centrais confirmadas idênticas em models/overview: + 1M de contexto, 128k de saída, adaptive thinking (sem extended), $5/$25 por MTok; no 4.8 o + effort assume high por padrão em todas as superfícies. Créditos de produção e + notas datadas de 2026-05-24 preservados como registro histórico.
  • +
  • 2026-06-10 (varredura de atualização) — Verificação contra a documentação oficial. + Adicionado callout no catálogo de modelos: Claude Fable 5 (claude-fable-5, + GA em 2026-06-09 — $10/$50 por MTok, 1M de contexto, 128k de saída, adaptive thinking sempre ativo, + tokenizer do Opus 4.7, stop_reason "refusal" + fallbacks beta, retenção + obrigatória de 30 dias, cache mínimo de 512 tokens) e Claude Mythos 5 em + disponibilidade limitada; Opus 4.8 segue ativo e recomendado (o guia permanece centrado + nele). Registradas as aposentadorias de Sonnet 4 / Opus 4 (2026-06-15) e Opus 4.1 (2026-08-05) e o campo + usage.output_tokens_details.thinking_tokens (desde 2026-05-27). Corrigido o code execution: + GA sem header beta desde 2026-02-17 (o header legado code-execution-2025-08-25 + segue aceito por compatibilidade) e code_execution_20260120 disponível em + Opus 4.5+ e Sonnet 4.5+ (não Haiku 4.5), conforme a página oficial da ferramenta. + Marcadores de verificação atualizados para 2026-06-10.
  • +
  • 2026-06-11 (delta sweep) — Re-verificação contra os release notes oficiais da API. + Incorporado: stop_details.category ganha o valor "reasoning_extraction" no + Fable 5 (09/06 — bloqueio por engenharia reversa/duplicação de outputs sob os ToS); advisor tool aceita + tools[].max_tokens (02/06); a não-cobrança de refusals sem output gerado é política de toda a + Claude API desde 02/06 (não exclusiva do Fable 5); Managed Agents ganhou scheduled deployments, credenciais + de variável de ambiente em vaults e o campo session_thread_id nos eventos + session.thread_* (09/06).
  • +
  • 2026-06-16 (micro-sweep de versões) — SDKs Anthropic subiram para + 0.109.2 (Python) / 0.104.2 (TS), ambos em 15/06: removem os modelos + aposentados da API e dos SDKs (limpeza da retirada de 15/06). A 0.109.1 (09/06) já + havia adicionado a refusal category frontier_llm. Sem endpoint, parâmetro ou modelo + novo — apenas manutenção.
  • +
  • 2026-06-19 (micro-sweep de versões) — SDKs Anthropic subiram para + 0.111.0 (Python) / 0.105.0 (TS). A 0.110.0 (18/06) adicionou + o suporte tipado ao tool code_execution_20260120 — a capacidade já era + GA e está documentada na §4.5 — além de corrigir o merge de headers x-stainless-helper + e o tipo de evento de stream no Bedrock; a TS 0.105.0 também passou a parsear o JSON + parcial de tool input de forma lazy. A 0.111.0 (18/06) apenas marca requests de + fallback de recusa com fallback-refusal-middleware. Sem endpoint, parâmetro ou modelo + novo — apenas manutenção.
  • +
  • 2026-06-25 (varredura de freshness) — SDK anthropic em + 0.112.0 (Python, 24/06). Correção factual: a saída máxima do + Sonnet 4.6 é 128k (não 64k) na Messages API — alinhado a + models/overview; também documentado o teto de 300k na Batch API via header + output-300k-2026-03-24. O Claude Fable 5 segue GA (09/06) porém + indisponível no momento (confirmar status atual). Sem endpoint, parâmetro ou + modelo novo.
  • +
+

Fontes primárias: platform.claude.com/docs + (export llms-full.txt) e github.com/anthropics/anthropic-cookbook. + Verificado em 2026-06-25 — para fatos perecíveis (modelos, datas, preços, limites, headers beta), + consulte sempre a fonte oficial.

+
+
+
+ +
+
+
+
Guia Claude API Anthropic · PT-BR
+

+ Referência técnica construída a partir da documentação oficial pública em + 2026-06-11 (versões de SDK reconferidas em 2026-06-19). Para informações sempre atualizadas, consulte + platform.claude.com/docs. + Para fatos perecíveis (modelos, datas, preços, limites), a documentação oficial é a fonte autoritativa. +

+
+
+
Crédito de produção
+
Produzido por um time de 4 agentes Claude Opus 4.7
+
em paralelo · orquestração + revisão Claude · 2026-05-24
+
+ anthropic + PT-BR + SOTA +
+
+
+
Navegação rápida
+ + + + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_contexto_compactacao_estrategias.html b/references/agents_tools_best_guides/guia_contexto_compactacao_estrategias.html new file mode 100644 index 0000000..52c410f --- /dev/null +++ b/references/agents_tools_best_guides/guia_contexto_compactacao_estrategias.html @@ -0,0 +1,1630 @@ + + + + + + + + + Guia SOTA de Contexto e Compactação para Orquestrações de IA + + + + +
+
+

Guia independente de contexto SOTA

+

Contexto e compactação em orquestrações de IA

+

Uma estratégia prática para definir um teto operacional X, dividir o input em fatias com políticas diferentes, compactar sem quebrar protocolo, persistir snapshots cumulativos e provar que o contexto está sob controle.

+
+ +
+ +
+ + +
+
+
+

0. Orientação

+

Use este guia como um mapa de decisão, não como uma tabela imutável. Os números são pontos de partida; a verdade final vem de domínio, latência, custo, risco, testes e telemetria.

+
    +
  • Para agentes de IA: procure data-fact, blocos keyfacts e o glossário final.
  • +
  • As seções de estratégia são universais; exemplos numéricos e riscos comuns são apenas guias de calibração.
  • +
  • A meta é qualidade sob restrição, não usar a maior janela disponível por reflexo.
  • +
  • Compactação reduz o payload da próxima chamada; originais completos continuam em ledger/storage para replay, auditoria e retrieval.
  • +
+
+ Evidência + Em orquestrações sérias, confiança vem de comportamento validado, não de jogar todo o histórico no prompt. O contexto deve ser montado, medido e auditado como qualquer outro recurso crítico. +
+
+ +
+

1. Modelo mental: teto X e fatias

+

Pense no contexto como um envelope orçado. O envelope tem teto X; dentro dele, cada fatia tem função, prioridade, política de compactação e telemetria própria.

+

O erro mais comum é tratar contexto como uma lista linear de mensagens. Para uma orquestração real, o prompt de entrada é uma montagem de camadas: instruções e skills, histórico conversacional, tool results, RAG, memórias, planos, scratchpad e reservas de saída.

+ +
+
+
balanced
+ +
+
+
tool_heavy
+ +
+
+
long_horizon
+ +
+
+ +
+ Invariante + O ledger próprio da aplicação é a fonte de verdade. Payloads de provedor, caches e continuation handles são projeções temporárias, nunca o estado durável da conversa. +
+
+ +
+

2. Definir o teto X

+

Seu teto X não é a janela do modelo. É o limite operacional que você aceita usar depois de reservar saída, tool calls, RAG, margem de segurança, custo e latência.

+
hard_input_budget = min(
+  teto_produto_ou_tier,
+  janela_modelo_segura,
+  teto_de_custo_e_latencia
+) - reserve_output - safety_margin
+
+W_steady = hard_input_budget * utilization_target
+soft = hard_input_budget * 0.70..0.75
+compact = hard_input_budget * 0.80..0.85
+hard = hard_input_budget * 0.90..0.92
+emergency = hard_input_budget * 0.95
+

Projetos diferentes podem escolher fatores diferentes. Uma sessão clínica de alto risco, uma geração de relatório com RAG pesado e uma conversa de ajuda rápida não deveriam disputar a mesma proporção de contexto.

+

reserve_output e safety_margin são reservas subtraídas antes do input: não são fatias compactáveis. A compactação opera sobre as fatias de input e só é bem-sucedida quando volta para W_steady com margem suficiente para continuar.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Componentes que devem ser subtraídos antes de confiar em X
ComponentePergunta de decisãoBoa prática
reserva_saidaQual é o pior caso de resposta final ou raciocínio pago?Reserve explicitamente; não confie em default do SDK.
reserva_toolsQuantos resultados de function podem voltar antes da próxima resposta?Reserve por chamada e compacte resultados grandes como digest mais ponteiro.
reserva_ragQuantos chunks e citações entram no pior caso?Use cap por lane e reduza top-k antes de truncar invariantes.
SLO/custoQuanto contexto ainda respeita TTFT, resposta completa e custo?Use telemetria real para reduzir teto quando o modelo permite mais do que o produto aguenta.
+ +
+ Pegadinha + Contar turnos engana. Uma única resposta de ferramenta, um PDF ou uma matriz de evidência pode consumir mais tokens que dezenas de mensagens curtas. +
+ +
+ Exemplos com janela total de 258k tokens +
+

Os números abaixo são exemplos de calibração, não contratos universais. O teto máximo varia por modelo, provedor, tier, latência, custo, tipo de sessão e data da documentação oficial.

+ + + + + + + + + + + + + + + + + + + + + + + + +
Exemplos para uma janela física de 258k
PerfilCálculoW steadyUso típico
Sessão única longa258k - 16k saída - 10k margem = 232k input hard.~60% do input hard = 139k. Compactar em ~80% = 186k e voltar para <=139k.Kernel/skills 32k, diálogo recente 60k, resumo cumulativo 18k, execução/RAG 18k, recall/assets 11k.
Multi-sessão / orquestração com ramosMesmo input hard de 232k, mas o parent deve ficar mais leve porque child ledgers e sessões antigas são retrieval-backed.~50% a 56% do input hard = 116k a 130k. Burst de evidência pode ir além, mas deve voltar ao steady.Kernel/skills 34k, sessão ativa 35k, memória/resumo 12k, execução/RAG 22k, recall/evidence 13k; ramos internos ficam em ledgers próprios.
+
+
+
+ +
+

3. Subdividir X em estratégias diferentes

+

A subdivisão de X evita que uma parte barulhenta do input destrua uma parte crítica. Cada fatia precisa saber o que aceita, quando cede e como prova que cedeu corretamente.

+

Uma forma prática é separar A_kernel estável, A_dialogue volátil, B_execution para tools/RAG/assets/provedor/child packets, e Recall para evidências recuperadas sob demanda. RAG, assets e tools também precisam de sub-budgets para uma lane não esmagar as outras.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Matriz independente de projeto para orçamento por fatias
FatiaConteúdo típicoRazão inicialPolítica de compactaçãoRisco principal
system_injectedSystem prompt, guardrails, skills ativas, contrato de segurança, estilo de resposta.10% a 20%Cede por remoção inteira de skill obsoleta ou reload controlado; não por corte parcial.Mutar skill ou instrução crítica sem perceber.
conversation_pairsPares user/assistant, decisões, preferências, estado visível ao usuário.33% a 60%Preservar recentes, resumir antigos com epoch/span e invariantes.Resumo inventar ou apagar restrição de negócio.
tools_ragFunction results, chamadas MCP, chunks RAG, citações, evidências temporárias.22% a 55%TTL, digest, truncamento explícito, ponteiro para artefato bruto durável e sub-budgets por lane.Tool result gigante expulsar prompt ou histórico.
recall_evidencePares compactados recuperados, anexos históricos relevantes, offsets, refs e trechos seguros.5% a 15%Buscar sob demanda, deduplicar contra o payload atual e limitar por escopo.Reintroduzir contexto duplicado, fora de escopo ou com metadata bruta de provedor.
memory/scratchpadResumos sintéticos, planos ativos, notas de continuidade, scratchpad seguro.0% a 15%Sintético, versionado, pequeno, recuperável sob demanda.Confundir resumo com fonte de verdade.
+ +
+ Perfis de partida +
+
    +
  • balanced: quando a conversa, tools e prompt têm peso parecido.
  • +
  • tool_heavy: quando functions ou MCPs devolvem muito contexto e precisam de budget maior.
  • +
  • rag_heavy: quando qualidade depende de fontes e citações.
  • +
  • long_horizon: quando uma sessão longa precisa preservar continuidade conversacional.
  • +
  • high_stakes: quando instruções, segurança e invariantes precisam de piso maior.
  • +
+
+
+ +
+ Invariante + O bloco de sistema não é só texto antigo no topo. Ele carrega contrato operacional. Se precisar economizar tokens, prefira diminuir RAG, resumir histórico antigo ou evictar uma skill inteira com rastreabilidade. +
+ +
+ Mapa para as zonas canônicas. Estas fatias mapeiam às + zonas canônicas do contrato de + estado: system_injected → authority_context; + conversation_pairs → conversation_context; tools_rag + desdobra-se em turn_working_context (loop aberto do turno) e + evidence_context (RAG/web/fontes); recall_evidence → + recall_context. Em fluxos agentic, duas fatias merecem orçamento próprio: +
+ + + + + + + + + + + + + + + + + + + + + +
Fatias adicionais para fluxos agentic
FatiaConteúdo típicoRazão inicialPolítica de compactaçãoRisco principal
turn_workingPrompt atual, arquivos inline do turno, tool calls abertas e seus results, carriers exigidos pelo loop.12% a 30% (volátil)TTL curtíssimo; prioriza fechar o tool loop; expira ao produzir a resposta final.Planilha/PDF do turno expulsar histórico ou L2 ativo quando não tem fatia própria.
hot_followupReturn packet de agent-as-tool, L3 pequeno ou evidência hot que precisa sobreviver a 1 follow-up.0% a 8% (TTL 1 turno)TTL default 1 turno; depois digest/ref/reload. Renderizado em role=user tagueado, não no system.Virar memória permanente, poluir autoridade ou carregar injeção de fonte externa.
+
+ Onde o hot_followup entra no wire. Depois que o loop fecha, o dado + transitório não volta como tool_result (não há tool call aberta) + nem no system (quebraria o cache do prefixo e misturaria dado com autoridade). Ele + entra como bloco tagueado no próximo turno role=user, com ttl_turns=1, + source_item_ids e trust_tier — detalhe completo no + invariante de colocação. +
+
+ +
+

4. Topologia de sessão

+

Uma sessão única longa e uma orquestração multi-sessão não são o mesmo problema. Elas divergem em teto, persistência de skills, resumo, handoff e tolerância a esquecimento.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Estratégia por topologia de sessão
ModoQuando usarPolítica de skills antigasCompactação dominanteRisco de projeto
single_sessionAtendimento focado, tarefa curta, fluxo com começo e fim claros.Skills ausentes podem ser evicted; recarregue corpo quando necessário.Preservar últimos turnos, resumir antigos e encerrar com handoff se crescer demais.A sessão ficar longa demais sem mudar de estratégia.
multi_sessionPainéis, especialistas, agentes filhos, workflows longos e paralelos.Skills ausentes viram stale/reload_required; corpo não fica persistido.Context packets, summaries, ledger e reidratação sob demanda.Misturar estado de agente filho com transcript público.
hybrid_defaultProduto precisa de continuidade, mas cria janelas episódicas para tarefas.Persistentes no tronco; episódicas nos ramos.Resumo do tronco, handoff curto para ramos, retorno tipado.Subsessão virar fonte de verdade sem merge auditável.
hybrid_adhocConsulta pontual, análise lateral, ferramenta isolada.Evict ao fim do episódio; guarde só referência segura se necessário.Pouca ou nenhuma; descarte e resuma saída final.Carregar contexto demais para uma tarefa lateral.
+ +
+ Pegadinha + Se o modo leve tem teto maior que o modo pesado, a nomenclatura virou armadilha operacional. A topologia precisa bater com custo e risco esperados. +
+
+ +
+

5. Escada de compactação

+

Compactação boa não corta do começo nem economiza só cosmeticamente. Ela avança por estágios e deve recuperar folga suficiente para continuar a sessão.

+ +
+ Compactação e prompt cache: cada degrau abaixo tem impacto diferente no prefix-cache. + Como cache depende de prefixo estável ou objeto explícito de cache (OpenAI: exact prefix match; Anthropic: prefix hash por breakpoint via cache_control, até 4 breakpoints; Gemini generateContent: cachedContent explícito; Gemini Interactions: implicit prefix caching default em Gemini 2.5+ (inclui séries 3.x; não causalmente acoplado a previous_interaction_id, mas ambos beneficiam prefixo estável)), qualquer operação que modifique conteúdo antes do breakpoint atual invalida o cache; operações que cortam pela cauda ou movem o breakpoint atomically preservam. + Resumo: + hygiene preserva cache só quando atua fora da projeção cacheada ou na cauda pós-breakpoint; qualquer dedupe/normalização em conteúdo <= breakpoint invalida o prefixo; + trim_old_pairs preserva cache apenas quando remove cauda pós-breakpoint; se remove pares antigos dentro do prefixo cacheado, cria novo prefixo e paga nova cache write no próximo turno; + summarize_old invalida o prefixo quando substitui material <= breakpoint; pode preservar cache se o resumo for novo bloco pós-breakpoint e o prefixo anterior permanecer byte-idêntico; + snapshot (§6) é o degrau canônico desta estratégia desenhado para mover o breakpoint atomically: commit do snapshot reposiciona o início do prefixo cacheável, então o turno seguinte paga uma cache write e os subsequentes leem. +

+ Implementação: trate cache_breakpoint_id/projection_version como parte do contrato de projeção; qualquer compaction que altere itens <= cache_breakpoint_id deve emitir novo projection_version e esperar uma cache write antes do próximo cache read. + Para detalhes de hit rate + prompt_cache_key (OpenAI) + cache_control (Anthropic) + cachedContent (Gemini generateContent) por provider, veja + §8b — Zonas canônicas do guia de Estado (callout "Cache-hit em projeção manual"). + derived mapeamento operação→cache é inferência consistente; o ganho exato depende do provider + tamanho do prefix. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Escada operacional de compactação
EstágioGatilho típicoO que fazO que não pode quebrar
hygieneUso subindo, sem pressão crítica.Dedup, remover ruído, reduzir citações repetidas.Nada de alterar pares tool-call/tool-result.
trim_old_pairsHistórico conversacional excede sua fatia.Mantém recentes e remove pares antigos não críticos.Invariantes, decisões, preferências e estado de erro.
summarize_oldContinuidade importa, mas pares antigos não cabem.Cria resumo sintético com span, data e limites.Não inventar fato nem apagar red-line.
compress_toolsTools/RAG domina o envelope.Digest, top-k menor, truncamento marcado, artifact pointer.Paridade tool_call/tool_result e citações usadas.
emergency_truncatePróximo request falharia por tamanho.Tenta janela/tier maior ou semantic handoff com digest portátil e assets reanexáveis antes de reduzir ao mínimo.Não prosseguir fingindo que contexto foi preservado.
critical_safety_onlyRisco de segurança, privacidade ou protocolo.Reduz ao mínimo e pede reinício ou reidratação.Fail-closed, com mensagem honesta.
+ +
+ Invariante + Antes de economizar token, preserve protocolo: pares tool-call/tool-result, janelas com tool call aberta, reasoning/thinking selado, assinaturas nativas e invariantes de segurança. +
+ +
+ Gate de sucesso + A primeira compactação precisa voltar a W_steady com margem. Um piso como 15% de recuperação pode ser útil como diagnóstico, mas o contrato correto é liberar espaço suficiente para a conversa continuar sem recompactar a cada turno. +
+ +
+ Degraus finos para fluxos agentic. Com skills e subagentes, a escada ganha + degraus que não aparecem na tabela base. Dois princípios robustos governam a ordem: + (1) descartar o transitório/expirado de baixo valor antes de tocar em continuidade + e (2) tratar autoridade por último. Encaixe natural nos estágios: +
    +
  1. junto do hygiene: remover L3 expirado e hot_followup vencido;
  2. +
  3. trim_old_pairs + summarize_old: compactar pares antigos não-críticos;
  4. +
  5. compress_tools: digest de tool/RAG/evidence antigos e reduzir arquivos inline a páginas/chunks relevantes;
  6. +
  7. filtrar o catálogo L1 (omitir/filtrar, sem resumir instrução crítica);
  8. +
  9. evictar L2 não-pinned como unidade e marcar stale/reload_required — nunca resumo parcial de L2 ativo;
  10. +
  11. emergency_truncate / trocar tier-modelo; por fim critical_safety_only / fail-closed.
  12. +
+ A ordem relativa entre reduzir tools (passo 3) e compactar conversa (passo 2) é + parametrizável por topologia: perfis tool_heavy podem reduzir evidência + antes dos pares; sessões de continuidade longa preservam mais tools e compactam conversa + primeiro. O ciclo de vida de L2/L3 está em Agent Skills. +
+
+ +
+

6. Snapshots cumulativos e ledger original

+

Compactar é criar uma visão menor para a próxima chamada. O original completo continua no ledger/storage; a compactação vira um snapshot cumulativo, versionado e auditável.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Campos mínimos de um snapshot de compactação
CampoFinalidadeRegra
policy_version / trigger_stageExplica por que compactou e qual política decidiu.Imutável por evento; admin muda apenas versões futuras.
preserved_ids, removed_ids, summary_id, recall_refsPermite replay e reidratação sem duplicar texto bruto.Guardar IDs/refs; o texto original fica no ledger canônico.
budget_before, budget_after, reclaimed_tokensProva se a compactação realmente liberou contexto.Medir por fatia e contra hard_input_budget.
sealed_carrier_counts, fail_reasonAudita proteção de estado de provedor e motivo de abortar.Sem PHI, prompts crus, signatures ou raw reasoning.
+ +
+ Sem duplicar bruto + Um snapshot não deve copiar o transcript inteiro a cada evento. Ele referencia mensagens, pares, anexos, tool results e carriers persistidos; replay reconstrói a visão a partir do ledger original mais eventos de compactação. +
+
+ +
+

7. Skills antigas já disclosed

+

Depois que uma skill foi carregada, o sistema não precisa reinjetar seu corpo bruto para sempre. Ele precisa saber se ela está ativa, stale, precisa de reload ou foi evictada.

+

Uma boa estratégia separa materialização de skill de referência de skill. A materialização traz o corpo completo antes de uma decisão que depende dele. A referência compacta mantém nome, versão, escopo, hash e status.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Estados recomendados para skills
EstadoSignificadoUso no promptQuando muda
activeA skill está válida para a janela atual.Referência compacta em <active_skills> ou equivalente.Versão, escopo, política ou agente mudam.
staleA skill já existiu, mas a janela atual não prova que ainda é válida.Marcar reload_required, não assumir corpo.Recarregada do catálogo ou removida.
evictedA skill saiu do episódio e não deve influenciar decisões.Não usar, exceto para explicar que precisa recarregar.Nova intenção solicita a skill novamente.
+ +
    +
  • Nunca persistir corpo bruto da skill em estado público ou metadata pública.
  • +
  • Persistir no máximo name, version, scope, body_hash_ref e reload_required.
  • +
  • Evictar skill inteira; nunca cortar metade do corpo por pressão de token.
  • +
  • Em sessão persistente, preferir stale/reload_required; em episódio curto, preferir evicted.
  • +
  • Skills de segurança sempre têm prioridade explícita e caminho de auditoria.
  • +
+ +
+ Regra prática + Descarregue skills por pressão de A1_hot, recência/frequência, idle_turns, min_residency e swap_margin. Um piso como 15 pares recentes pode ser guardrail de coerência conversacional, mas não deve ser o gatilho principal para evictar skill. +
+ +
+ Risco alto + Reintroduzir automaticamente o corpo inteiro de uma skill antiga pode inflar o prompt, reativar instrução obsoleta e mascarar drift de versão. Referência compacta e reload explícito são mais controláveis. +
+
+ +
+

8. Tool results, functions e RAG

+

Resultados de ferramentas e RAG são voláteis. O bruto fica no store certo; o prompt recebe o menor digest verificável que ainda permite decidir.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Política para resultados de functions e RAG
ItemPrompt recebeStore durável recebeCompactação
Tool result pequenoBruto curto, com tool id e status.Registro completo e auditável.TTL por turnos; remover se não referenciado.
Tool result grandeResumo estruturado, campos decisivos, ponteiro seguro.Bruto integral, checksum e provenance.Truncar com marcador explícito e comprimento original.
RAGChunks top-k, citações, confiança, lane e escopo.Manifesto de retrieval e artefatos.Reduzir top-k, comprimir citações repetidas, preservar fontes usadas.
SubagenteConclusão, evidência, limites e próximos passos.Log completo do agente se permitido.Context packet com escopo e confidence, não transcript inteiro.
+ +
+ Evidência + Todo pruning ou truncamento de tool result deve deixar evento auditável: id da ferramenta, tokens ou caracteres economizados, motivo, fatia afetada e ponteiro para o bruto quando houver. +
+
+ +
+

9. Anexos e session-scoped retrieval

+

Arquivos enviados pelo usuário são estado de sessão, não texto barato de prompt. O bruto e os derivados ficam persistidos; a janela recebe refs, digestos ou trechos recuperados sob escopo.

+ +
    +
  • Persistir bruto, checksum, metadados, parser state, derivados e refs antes de depender do arquivo em uma resposta.
  • +
  • Usar session_id e owner_user_id como escopo mínimo para anexos de sessão.
  • +
  • Enviar inline apenas arquivos atuais e selecionados; arquivos históricos entram por tool/RAG com top-k e provenance.
  • +
  • Apagar sessão deve enfileirar teardown de índice RAG, row de anexo e storage; itens promovidos a knowledge seguem outra retenção.
  • +
  • Formatos como Excel, CSV, PDF, DOCX, imagem e áudio precisam de contrato end-to-end consistente, não allowlists divergentes por canal.
  • +
+ +
+ Quando um par tinha arquivo + Compactar o par não remove o arquivo. O snapshot preserva attachment_refs, asset://, projection:// ou rag-doc://; o runtime reidrata por tool/RAG quando o modelo precisar. +
+
+ +
+

10. Transcript recall dos pares compactados

+

Pares user/assistant compactados podem continuar consultáveis por uma lane de recall. Ela não substitui o ledger original; ela oferece busca segura sobre o que saiu do payload.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Contrato de transcript recall
DecisãoBoa práticaBloqueio
AtivaçãoExpor a tool/lane só quando existir snapshot com pares removidos do payload atual.Buscar histórico ativo, payload corrente ou conversa inteira por conveniência.
ElegibilidadeIndexar apenas pares fechados, server-owned, não ativos e já removidos da janela atual.Pares atuais, incompletos, com tool window aberta ou com metadata bruta de provedor.
BuscaCombinar embedding, lexical/BM25/text-grep, offsets e deduplicação, preservando palavras e frases.Dimensão de índice diferente da consulta ou fonte sem scope.
OrdemCommitar snapshot e índice/registro de recall antes de remover do payload.Se indexação/registro falhar, abortar compactação e manter payload anterior.
+ +
+ Modelo e dimensão + O guia não fixa modelo nem provedor de embedding. O registry versionado define o perfil interno de busca, com fonte oficial, data, alias interno, dimensão e migração de índice; se o perfil canônico for 3072 dimensões, isso deve constar no registry e nos testes de compatibilidade, nunca como constante do runtime nem como nome de provedor no texto canônico. +
+
+ +
+

11. Chamadas ao modelo e microconversas internas

+

Cada chamada ao modelo precisa de um envelope tipado. Cada conversa interna de agente/tool precisa de um ledger próprio. O parent vê resultado tipado, não o transcript bruto do child.

+ +
    +
  • ModelCallEnvelope: provedor, modelo, versão/alias, esforço/thinking, config, request id, usage, cache, fallback e status.
  • +
  • ReplayState: carriers selados necessários ao protocolo, sem convertê-los em texto comum.
  • +
  • ProviderSwitch: handoff semântico com capacidades perdidas, assets reanexados e protocolo antigo fechado.
  • +
  • ChildRunLedger: eventos internos por micro_context_id, incluindo model/tool/MCP calls, resultados, budget e return packet.
  • +
  • Microconversas podem ficar suspensas em waiting_user_input, waiting_parent_input, waiting_tool ou waiting_child_agent, com contrato de retomada explícito.
  • +
  • Enquanto suspensa, a microconversa não é compactável como diálogo comum; ela só entra por refs e estado tipado.
  • +
  • Parent prompt recebe return_packet, digest e refs; nunca child transcript inteiro por conveniência.
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Estados mínimos para microconversas retomáveis
EstadoO que deve persistirQuando continua
waiting_user_inputPergunta feita ao usuário, contrato do input esperado, refs de contexto, owner, prazo e política de expiração.Quando chegar a resposta do usuário com escopo compatível, a mesma microconversa retoma pelo micro_context_id.
waiting_parent_input / waiting_tool / waiting_child_agentDependência aguardada, call/result ids, budget restante, tentativa atual e estado de replay selado.Quando a dependência resolve, o runtime adiciona novo evento ao ledger e reavalia terminalidade.
completed_definitive / failed / canceledReturn packet final, evidência usada, limites, motivo terminal e refs de replay.Não continua como conversa aberta; apenas reabre por nova tarefa ou revisão explícita.
+ +
+ Continuação até terminal definitivo + Se um agente interno precisou perguntar algo ao usuário, a orquestração deve persistir esse estado pendente e retomar a mesma microconversa quando a resposta chegar. O objetivo é chegar a um return_packet definitivo, uma falha segura ou um cancelamento explícito, sem perder contexto no meio. +
+
+ +
+

12. Privacidade, ZDR e estado de provedor

+

Fluxos protegidos devem reconstruir o payload do provedor a partir do ledger próprio. O provedor recebe uma projeção mínima e descartável.

+ +
    +
  • Definir store=false ou equivalente em todo fluxo protegido.
  • +
  • Rejeitar previous_response_id, conversation_id, sessões de provedor e handles equivalentes como estado durável.
  • +
  • Tratar cache de provedor como dica de performance, nunca como portador da conversa.
  • +
  • Não publicar reasoning, thinking, tool IDs sensíveis, raw transcript ou corpo de skill em payload público.
  • +
  • Logs e traces contam tokens, decisões e spans; não carregam PHI, prompts crus ou dados clínicos sensíveis.
  • +
+ +
+ ZDR e replay + Um resumo ajuda a montar contexto, mas não substitui estado de replay, tool history, signatures nativas ou carriers selados exigidos pelo protocolo do provedor. +
+ +
+ Troca de provedor como handoff, não continuação +
+

Ao trocar de provedor, feche janelas de ferramenta, sele carriers nativos não portáveis, gere um pacote portátil pequeno, reanexe assets permitidos e comece uma nova janela de protocolo. Não tente converter thoughtSignature, encrypted reasoning ou redacted thinking em conversa comum.

+
+
+
+ +
+

13. Observabilidade

+

Se você não mede tokens por fatia e eventos de compactação por turno, você não gerencia contexto; você só espera que caiba.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Métricas mínimas para um ledger de contexto
MétricaPor que importaAção quando sobe
tokens_by_sliceMostra se o problema está em sistema, conversa, RAG ou tool result.Aplicar política da fatia, não truncamento global.
token_budget_utilizationDispara a escada de compactação.Entrar em hygiene, summarize ou emergency conforme threshold.
summary_tokens_savedProva se resumo reduziu custo sem apagar fato.Ajustar cadência, max tokens e preservação de recentes.
overflow_eventsMostra que o envelope foi violado ou quase violado.Abrir incidente de política ou reduzir teto efetivo.
compaction_eventsPermite explicar por que algo saiu do prompt.Auditar perdas e ajustar playbook.
compaction_success_rateMostra se a primeira compactação recupera folga suficiente.Se cair, ajustar W steady, slices, recall e unload de skills.
recall_hit_rateProva se conteúdo removido do payload continua útil quando necessário.Ajustar indexação, chunking, filtros e limites de evidência.
critical_path_overhead_msEvita compactação correta mas lenta demais para o produto.Mover embedding/summarization pesada para job, mantendo commit mínimo síncrono.
orphan_cleanup_countDetecta falha de cascade em anexos, RAG e storage.Bloquear PASS de privacidade até reconciliação zerar.
+ +
+ Evidência + A prova mínima muda por camada: domínio por teste de função, runtime por integração, UI por renderização, provedor por request sanitizado, e produção por logs/traces sem dados sensíveis. +
+
+ +
+

14. Admin parametrizável

+

Watermarks, W steady, ASBM, retrieval caps e políticas de emergência não devem ficar espalhados em constantes. Eles pertencem a um registry parametrizável, com limites seguros e trilha de auditoria.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Knobs mínimos para admin/config registry
GrupoParâmetrosGuardrail
Watermarkssoft, compact, hard, emergency, W_steadyLimites por topologia/tier/modelo; alteração versionada e canary.
Reclaimmin_reclaim_ratio, target_utilization_after, reserve_output_multiplierNão aceitar política que não volte a W_steady em fluxo contínuo.
Skills ASBMA1_target, A1_hard, idle_turns, min_residency, swap_marginSkills kernel e safety não podem ser evictadas por edição admin comum.
Retrievaltop-k por lane, max snippets, max bytes, modos semantic/lexical/BM25/text-grepScope isolation e no-leak tests antes de ativar.
Emergencytier escalation, semantic handoff, reattach assets, fail-closed copyNunca emitir payload inválido para o provedor para evitar bloqueio de UX.
Tierstier_cap, inline_pages, main_output_cap, agent_as_tool_output_cap, summary_output_capeffective_cap = min(tier, janela do modelo, custo/latência, rota); hard de fatia é teto local, não somável.
+ +
+ Defaults por tier (ilustrativos). Como ponto de partida — e + parametrizável, sujeito a recalibração por evals, idioma, densidade de + documento e SLO — uma escada de tiers pode ser: + + + + + + + + + +
Tetos por tier — exemplos iniciais, não axiomas
Tiertier_cap sugeridoPáginas inline/turnoPerfil
Free~128k~10Contexto moderado, 1 skill ativa pequena, loops curtos.
Plus~258k~30Contexto longo, L2 moderado, arquivos úteis no turno.
Pro~512k~40Agentic, L2 robusto, tool loops longos.
Super~1M se o modelo permitir~60Sessões longas, multiagentes, microcontextos.
+ Dois cuidados que mudam com o tempo: (a) effective_context_cap = min(tier, janela do + modelo, custo/latência, política de rota) — o tier não aumenta a janela real do modelo; + (b) ao quebrar o tier em fatias, cada hard de fatia é um teto local + não-simultâneo — a soma dos hards excede o cap de propósito (folga de design). O que + vincula é projeção + reserva de saída + margem ≤ cap efetivo (ver + contrato de budgets). As + páginas inline por tier detalham-se em + File inputs sem provider storage. +
+
+ +
+

15. Playbooks

+

Contexto manual fica sustentável quando o operador sabe o que fazer em cada estágio, sem improvisar em produção.

+ +

Quando a conversa cresce

+
    +
  1. Calcule uso por fatia e confirme se o crescimento é de conversation_pairs.
  2. +
  3. Preserve últimos turnos verbatim e mensagens de alta prioridade.
  4. +
  5. Indexe e registre snapshot antes de remover pares do payload.
  6. +
  7. Resuma pares antigos com span, data, fatos, decisões, incertezas e refs de recall.
  8. +
  9. Registre reclaimed_tokens, target_utilization_after e mantenha bruto no ledger durável.
  10. +
+ +

Quando tool results crescem

+
    +
  1. Separe resultados ainda referenciados de resultados antigos.
  2. +
  3. Converta bruto grande em digest estruturado e ponteiro.
  4. +
  5. Preserve pares tool-call/tool-result e IDs nativos necessários.
  6. +
  7. Reexecute tool ou peça reidratação se o digest não for suficiente.
  8. +
+ +

Quando uma skill antiga aparece

+
    +
  1. Verifique se a topologia é persistente ou episódica.
  2. +
  3. Verifique A1_hot, recência, idle_turns, min_residency e swap_margin.
  4. +
  5. Se persistente, marque stale/reload_required até recarregar o corpo.
  6. +
  7. Se episódica, trate como evicted e não deixe influenciar a decisão.
  8. +
  9. Nunca reaproveite corpo bruto de uma janela antiga sem versionamento e escopo.
  10. +
+ +
+ Risco médio + A pior compactação é a silenciosa. Se o contexto essencial não cabe nem pode ser recuperado, a resposta correta é fail-closed, pedir reidratação ou reiniciar a janela com um pacote explícito. +
+
+ +
+

16. Riscos comuns e pendências típicas

+

O desenho SOTA só vira operação confiável quando seus riscos comuns são testados, metrificados e tratados como backlog explícito.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Riscos independentes de framework
RiscoSintomaMitigação
Corte por recênciaMensagens antigas saem sem validar tool pairs, assets, carriers de provedor ou planos ativos.Usar is_compactable estrutural e validador before/after.
Esquecimento funcionalO original existe no banco, mas o agente não consegue recuperá-lo quando precisa.Commit de snapshot e registro/index de recall antes de remover do payload.
Parâmetros hardcodedThresholds, janelas e caps divergem entre runtime, testes e admin.Registry versionado, bounds seguros, snapshot por run e painel read-only.
Órfãos de dadosApagar sessão remove a UI, mas deixa anexos, chunks ou blobs históricos.Teardown determinístico, reconciliação de órfãos e exceção clara para knowledge promovido.
Microconversa inlinadaTurnos internos do child viram transcript comum do parent.Child ledger próprio e parent-facing return packet bounded.
Formatos divergentesUm canal aceita planilha, outro rejeita, e retrieval não tem parser equivalente.Contrato end-to-end por formato: upload, parser, index, fetch, delete e teste.
+
+ +
+

17. Glossário rápido

+

Use estes termos de forma consistente em specs, prompts, testes e telemetria.

+
+
Teto operacional X
+
Limite de tokens que a orquestração escolhe usar, abaixo da janela física do modelo e depois de reservas.
+ +
system_injected
+
Fatia de instruções, guardrails, identidade operacional, skills ativas e políticas de segurança.
+ +
conversation_pairs
+
Histórico user/assistant selecionado, com pares recentes preservados e antigos resumíveis.
+ +
tools_rag
+
Resultados de functions, MCPs, RAG, citações, evidências e artefatos recuperados.
+ +
Compaction snapshot
+
Evento cumulativo que registra política, ids, refs e métricas de uma compactação sem copiar o transcript bruto.
+ +
Transcript recall
+
Lane de busca segura para pares user/assistant fechados que saíram do payload atual, com escopo, refs e offsets.
+ +
ModelCallEnvelope
+
Envelope tipado de uma chamada ao modelo, incluindo provedor, modelo, config, usage, fallback e replay state selado.
+ +
ChildRunLedger
+
Ledger local de uma microconversa interna; o parent recebe apenas return packet, digest e refs.
+ +
Ledger canônico
+
Estado próprio, durável e auditável da aplicação; fonte de verdade para remontar payload de provedor.
+ +
Context packet
+
Pacote pequeno de continuidade para handoff entre agentes, janelas ou provedores, sem transcript bruto.
+ +
ZDR
+
Postura em que estado de provedor e retenção são minimizados; a aplicação não depende de continuation handles externos.
+ +
stale skill
+
Skill conhecida em sessão persistente, mas que exige reload antes de orientar decisão sensível.
+ +
evicted skill
+
Skill removida de episódio curto; não deve influenciar a próxima decisão sem nova materialização.
+ +
Fail-closed
+
Quando o sistema não consegue preservar contexto/protocolo/segurança, ele para ou pede reidratação em vez de responder como se nada tivesse acontecido.
+ +
turn_working
+
Fatia volátil do loop atual: prompt, arquivos inline do turno, tool calls abertas e carriers exigidos; expira ao fechar o loop e produzir a resposta final.
+ +
hot_followup
+
Dado transitório (return packet de agent-as-tool, L3 pequeno, evidência hot) carregado por ~1 turno em role=user tagueado — nunca no system; depois vira digest/ref/reload.
+
+
+
+
+
+ +
+

Arquivo atualizado em 2026-06-10 (integração da proposta de gestão manual de contexto v0.6: fatias turn_working/hot_followup, degraus finos da escada e defaults por tier ilustrativos; o roteamento de modelo summarizer — modelo pequeno/barato, contrato de saída tipado e sucesso por min_reclaim_ratio/target_utilization_after (§14) — é deliberadamente deixado aos guias de modelo por ser perecível). Documento independente e framework-neutral. Claims perecíveis sobre modelos, janelas, SDKs, cache, thinking ou embeddings devem ser confirmados em fontes oficiais antes de virar código canônico.

+
+ + diff --git a/references/agents_tools_best_guides/guia_deepagents.html b/references/agents_tools_best_guides/guia_deepagents.html new file mode 100644 index 0000000..a487b93 --- /dev/null +++ b/references/agents_tools_best_guides/guia_deepagents.html @@ -0,0 +1,2581 @@ + + + + + +Guia Deep Agents — Referência completa (Python) + + + + + + + + +
+
+
Guia Deep Agents Python — Referência completa
+
+ Verificado em 2026-06-25 + deepagents + Python 3.11+ + +
+
+
+ +
+ + +
+ +
+

Guia Deep Agents — Referência completa (Python)

+

+ Documentação técnica exaustiva do Deep Agents, o harness do + LangChain para construir agentes capazes de planejar, delegar para + sub-agents e manter contexto via sistema de arquivos virtual. Cobre + create_deep_agent, as ferramentas built-in, sub-agents + (síncronos e assíncronos), os backends pluggable (StateBackend, FilesystemBackend, + StoreBackend, ContextHubBackend, CompositeBackend e sandboxes), permissões, + skills, memória persistente, profiles, HITL, dcode CLI e o ACP. +

+
+ deepagents 0.6.12 + Python ≥ 3.11 + SOTA · 2026-06-25 +
+
+ +
+

Sobre este guia

+
+ Atualização 2026-06-25 — deepagents 0.6.12 é o último no PyPI (release de 2026-06-25; a 0.6.11 era de 2026-06-18). Desde a 0.6.3: RubricMiddleware (auto-avaliação iterativa do agente, 0.6.5); state_schema aceitável em create_deep_agent (0.6.6); Commands retornados por tools propagam goto/graph e DeepAgentState passou a ser exportado (0.6.7); CodeInterpreterMiddleware experimental (runtime QuickJS) e adoção de DeltaChannel + event streaming v3 (0.6.0). Breaking (0.6.8): removidos os exports públicos SubagentRunStream/AsyncSubagentRunStream/SubagentTransformer (eram internos da API beta stream_events(version="v3")). 0.6.9: formato de resposta de subagente configurável (nova opção pública), além de bugfixes/perf (token counting na summarization middleware, cache de prompts de filesystem e de matchers de glob). 0.6.10: bugfix — passa a comparar o provider em model_matches_spec. 0.6.11: bugfix — roteia os helpers async do BaseSandbox por aexecute. 0.6.12: adicionou BedrockPromptCachingMiddleware (middleware de prompt-caching para Amazon Bedrock). Compatibilidade: exige langchain-core >=1.4,<2, langchain >=1.3.4,<2, langchain-anthropic >=1.4.3,<2, langchain-google-genai >=4.2.2,<5 — compatível com o LangChain/LangGraph mais novos. O modelo default resolve via HarnessProfile/init_chat_model; passe o ID explicitamente (ex.: "anthropic:claude-sonnet-4-6") em vez de depender do default. +
+

+ Este guia é uma conversão fiel da documentação oficial pública + do Deep Agents em + docs.langchain.com/oss/python/deepagents + e da referência de API em + reference.langchain.com/python/deepagents. +

+

+ A Parte A apresenta os conceitos em 24 capítulos. A + Parte B é referência técnica de cada símbolo público: + assinatura, parâmetros em tabela, métodos e exemplos. Tudo em Python — o + Deep Agents também tem porta JS em + deepagentsjs, + não coberta aqui. +

+
+ Como ler: a Parte A ensina a mecânica do harness; a Parte B + é consulta rápida com blocos <details> expansíveis. +
+
+ Verbatim parcial: a documentação pública não publica o texto + completo das constantes de prompt (BASE_AGENT_PROMPT, + TASK_SYSTEM_PROMPT, FILESYSTEM_SYSTEM_PROMPT, + SKILLS_SYSTEM_PROMPT, MEMORY_SYSTEM_PROMPT, + SUMMARIZATION_SYSTEM_PROMPT). Este guia descreve o conteúdo e a + função de cada prompt; para o texto exato, importe da biblioteca: + from deepagents.graph import BASE_AGENT_PROMPT (não é reexportado no topo de deepagents). +
+
+ +
+

Fontes oficiais

+ +
+ +
+

Parte A — Conceitos

+

Vinte e quatro capítulos cobrindo o Deep Agents na ordem de leitura recomendada da documentação oficial.

+
+ +
+

1. Visão geral · os quatro pilares

+

+ O Deep Agents é um harness construído sobre + langchain.agents.create_agent e LangGraph. Sua proposta — segundo o + post de Harrison Chase (2025-07-30) — é elevar agentes "shallow" (chamar tool + em loop) para a categoria deep: capazes de planejar, delegar e manter + contexto em horizontes longos. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
PilarMecânicaImplementação
1. System prompt detalhadoPrompt longo com instruções de uso de tool e exemplos few-shotBASE_AGENT_PROMPT + prompts por feature (TASK_*, FILESYSTEM_*, SKILLS_*, MEMORY_*, SUMMARIZATION_*). Opcional: HarnessProfile.system_prompt_suffix
2. Planning toolTo-do list como "context engineering strategy" para manter o agente no rumoTool write_todos injetada por TodoListMiddleware; status pending / in_progress / completed
3. Sub-agentsDividir tarefas e isolar contextoTool task(...) injetada por SubAgentMiddleware; subagent general-purpose default; tipos SubAgent / CompiledSubAgent / AsyncSubAgent
4. Sistema de arquivos virtualWorkspace compartilhado funcionando como memória de longo prazoTools ls / read_file / write_file / edit_file / glob / grep injetadas por FilesystemMiddleware; BackendProtocol pluggable
+
+ +
+ Nota (docs oficiais, verificado 2026-06-25): a documentação oficial enquadra as quatro capacidades como: (1) Execution environment — tools, filesystem virtual, sandbox opcional e REPL; (2) Context management — skills, memória, sumarização e caching de prompt; (3) Delegation — subagents e planejamento de tarefas; (4) Steering — HITL e interrupts. Mapeamento com os pilares acima: System prompt detalhado ≈ Execution environment + Context management; Planning tool e Sub-agents ≈ Delegation; Sistema de arquivos virtual ≈ Execution environment. +
+
+ +
+

2. Quickstart

+
# pip install -qU deepagents langchain-anthropic
+from deepagents import create_deep_agent
+
+def get_weather(city: str) -> str:
+    """Get weather for a given city."""
+    return f"It's always sunny in {city}!"
+
+agent = create_deep_agent(
+    model="anthropic:claude-sonnet-4-6",
+    tools=[get_weather],
+    system_prompt="You are a helpful assistant",
+)
+
+agent.invoke({"messages": [{"role": "user", "content": "what is the weather in sf"}]})
+

Quickstart canônico — pesquisador com Tavily

+
# pip install deepagents tavily-python
+import os
+from typing import Literal
+from tavily import TavilyClient
+from deepagents import create_deep_agent
+
+tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
+
+def internet_search(
+    query: str,
+    max_results: int = 5,
+    topic: Literal["general", "news", "finance"] = "general",
+    include_raw_content: bool = False,
+):
+    """Run a web search"""
+    return tavily_client.search(
+        query,
+        max_results=max_results,
+        include_raw_content=include_raw_content,
+        topic=topic,
+    )
+
+agent = create_deep_agent(
+    model="anthropic:claude-sonnet-4-6",
+    tools=[internet_search],
+    system_prompt="You are an expert researcher...",
+)
+
+agent.invoke({
+    "messages": [{"role": "user", "content": "Research LangGraph and write a summary"}]
+})
+
+ +
+

3. Instalação

+
pip install deepagents                       # core
+pip install -U "deepagents[quickjs]"          # + Code Interpreter (QuickJS)
+pip install deepagents-acp                    # + integração IDE (ACP)
+pip install deepagents-code                   # + dcode CLI
+
+# Sandboxes (opcionais)
+pip install langchain-modal
+pip install langchain-daytona
+pip install langchain-runloop
+pip install "langsmith[sandbox]"
+
+# uv equivalente
+uv add deepagents tavily-python
+
+ + + + + + + + + +
ItemValor
Versão atualdeepagents == 0.6.12 (2026-06-25)
Python>= 3.11, < 4.0 (3.11 – 3.14)
LicençaMIT
Dependências principaislanggraph, langchain (create_agent + middleware framework)
Extras opcionaisquickjs
+
+
+ +
+

4. create_deep_agent

+
from deepagents import create_deep_agent
+from langchain.messages import SystemMessage
+
+create_deep_agent(
+    model: str | BaseChatModel | None = None,
+    tools: Sequence[BaseTool | Callable | dict[str, Any]] | None = None,
+    *,
+    system_prompt: str | SystemMessage | None = None,
+    middleware: Sequence[AgentMiddleware] = (),
+    subagents: Sequence[SubAgent | CompiledSubAgent | AsyncSubAgent] | None = None,
+    skills: list[str] | None = None,
+    memory: list[str] | None = None,
+    permissions: list[FilesystemPermission] | None = None,
+    backend: BackendProtocol | BackendFactory | None = None,
+    interrupt_on: dict[str, bool | InterruptOnConfig] | None = None,
+    response_format: ResponseFormat | type | dict | None = None,
+    context_schema: type[ContextT] | None = None,
+    checkpointer: Checkpointer | None = None,
+    store: BaseStore | None = None,
+    debug: bool = False,
+    name: str | None = None,
+    cache: BaseCache | None = None,
+) -> CompiledStateGraph
+

Parâmetros

+
+ + + + + + + + + + + + + + + + + + + + + +
ParamTipoDefaultComportamento
modelstr \| BaseChatModel \| NoneNone"provider:model" (via init_chat_model) ou instância. None está depreciado desde 0.5.3.
toolsSequence[BaseTool \| Callable \| dict]NoneAditivo — concatena com built-ins. Funções usam docstring como description.
system_promptstr \| SystemMessage \| NoneNonePreenche o slot USER. Usando SystemMessage, preserva blocos com cache_control.
middlewareSequence[AgentMiddleware]()Inserido entre base stack e tail stack.
subagentsSequence[SubAgent \| CompiledSubAgent \| AsyncSubAgent]NoneDeclarativos, grafo pré-compilado ou remoto/async.
skillslist[str]NonePaths POSIX relativos à raiz do backend. Entradas posteriores sobrepõem skills de mesmo nome.
memorylist[str]NonePaths de AGENTS.md carregados no system prompt em startup.
permissionslist[FilesystemPermission]NoneFirst-match-wins; allow por padrão. Herdadas por subagents, exceto se sobrescritas.
backendBackendProtocol \| BackendFactoryNone → StateBackend()Armazenamento de arquivos; sandboxes adicionam execute.
interrupt_ondict[str, bool \| InterruptOnConfig]NoneHITL; requer checkpointer.
response_formatstructured-output specNoneMesma semântica de create_agent. A saída estruturada fica em result["structured_response"] (ver 7.1).
context_schematype[ContextT]NoneContexto imutável por run.
checkpointerCheckpointerNoneObrigatório para HITL, async, threads duráveis.
storeBaseStoreNoneObrigatório se algum backend usa StoreBackend.
debugboolFalseLogs verbosos.
namestrNoneNome do agente (aparece em traces).
cacheBaseCacheNoneCache por call.
+
+

+ Retorna um CompiledStateGraph do LangGraph — + invoca com .invoke({"messages": [...]}), faz stream com + .stream(...), retoma com Command(resume=...). +

+
+ Política de integração por provedor. O model + aceita uma string "provider:model" (resolvida por + init_chat_model) ou uma instância de chat model já configurada. + Cada provedor tem seu pacote e classe nativos: +
+ + + + + + + + + + + + + + + + + + + +
ProvedorPacote · classeComo usar
OpenAIlangchain-openai · ChatOpenAIPara garantir a Responses API, instancie + ChatOpenAI(model="gpt-5.5", use_responses_api=True) e passe como + model=. A flag real é use_responses_api (não existe + "output_version"). O roteamento também vai para Responses API automaticamente ao usar + built-in tools (web_search, file_search, etc.), o param + reasoning={"effort": ..., "summary": ...} ou + previous_response_id. Uma string + "openai:gpt-5.5" sozinha não força Responses API.
Anthropiclangchain-anthropic · ChatAnthropicFala direto com a Messages API nativa da Anthropic (SDK + anthropic). ChatAnthropic(model="claude-sonnet-4-6"). + Bedrock/Vertex são classes separadas + (ChatBedrockConverse, ChatAnthropicVertex).
Googlelangchain-google-genai · ChatGoogleGenerativeAIDesde a v4.0.0 usa o SDK consolidado google-genai (via + generateContent). Prefixo de string: + google_genai:gemini-3.5-flash. Gotcha: em Gemini 3.0+, se + temperature não for setado, vira 1.0 — prefira + fixá-lo.
+
+
from langchain_openai import ChatOpenAI
+from langchain_anthropic import ChatAnthropic
+from langchain_google_genai import ChatGoogleGenerativeAI
+from deepagents import create_deep_agent
+
+# OpenAI — Responses API garantida via objeto configurado (NÃO use a string solta):
+openai_llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
+# Anthropic — Messages API nativa:
+anthropic_llm = ChatAnthropic(model="claude-sonnet-4-6")
+# Google — SDK google-genai (langchain-google-genai >= 4.0):
+google_llm = ChatGoogleGenerativeAI(model="gemini-3.5-flash", temperature=0.7)
+
+agent = create_deep_agent(model=openai_llm, tools=[...])   # passe a instância em model=
+
+
+ A Gemini Interactions API (endpoint /interactions, + histórico server-side, agentes gerenciados) não tem integração nativa em + langchain-google-genai, LangGraph ou deepagents (maio/2026). O + ChatGoogleGenerativeAI usa generateContent; features exclusivas da + Interactions API (previous_interaction_id, agentes como + Deep Research) só são acessíveis pelo SDK google-genai direto. Não + existe flag use_interactions_api=... na classe LangChain. +
+ +

Ordem do stack de middleware

+

Base stack (sempre presente, exceto excluído):

+
    +
  1. TodoListMiddleware
  2. +
  3. SkillsMiddleware (só se skills= for fornecido)
  4. +
  5. FilesystemMiddleware
  6. +
  7. SubAgentMiddleware (só se houver subagent síncrono — incluindo o general-purpose default)
  8. +
  9. AsyncSubAgentMiddleware (só se houver AsyncSubAgent)
  10. +
  11. SummarizationMiddleware
  12. +
  13. PatchToolCallsMiddleware
  14. +
+

User middleware é inserido aqui.

+

Tail stack:

+
    +
  • HarnessProfile.extra_middleware
  • +
  • _ToolExclusionMiddleware (só se profile tem excluded_tools)
  • +
  • AnthropicPromptCachingMiddleware (no-op em modelos não-Anthropic)
  • +
  • MemoryMiddleware (só se memory=)
  • +
  • HumanInTheLoopMiddleware (só se interrupt_on=)
  • +
+
+ Não existe um símbolo separado async_create_deep_agent. Use o mesmo + create_deep_agent e chame await agent.ainvoke(...), + agent.astream(...) e middleware com hooks async + (abefore_agent, awrap_model_call, + awrap_tool_call, astream). Para sub-agents em + background, use AsyncSubAgent. +
+
+ +
+

5. Ferramentas embutidas

+
+ + + + + + + + + + + + + + + +
ToolMiddlewareAssinaturaComportamento
write_todosTodoListMiddleware(todos: list[Todo])Persiste o plano no estado. Status: pending / in_progress / completed.
lsFilesystemMiddleware(path: str)Lista arquivos com tamanho e modified_at.
read_fileFilesystemMiddleware(file_path: str, offset: int = 0, limit: int = 2000)Lê conteúdo com numeração de linhas; suporta offset/limit. Para arquivos não-texto, retorna content blocks multimodais (ver 5.1).
write_fileFilesystemMiddleware(file_path: str, content: str)Apenas criação — erro se arquivo já existe.
edit_fileFilesystemMiddleware(file_path: str, old_string: str, new_string: str, replace_all: bool = False)Substituição exata; unicidade obrigatória, salvo replace_all=True.
globFilesystemMiddleware(pattern: str, path: str = "/")Pattern match.
grepFilesystemMiddleware(pattern: str, path=None, glob=None)Busca de conteúdo; múltiplos modos de output.
executeFilesystemMiddleware (apenas backends sandbox)(command: str)Retorna output (stdout+stderr), exit code e nota de truncamento.
taskSubAgentMiddleware(subagent_type: str, description: str)Spawn de subagent síncrono; só o sumário volta ao contexto do pai.
compact_conversationSummarizationToolMiddleware()Dispara summarization manual.
start_async_task · check_async_task · update_async_task · cancel_async_task · list_async_tasksAsyncSubAgentMiddlewarevariadosSubagents em background (fire-and-forget) via Agent Protocol.
+
+ +

5.1 read_file multimodal

+

+ Quando read_file lê um arquivo não-texto (imagem, vídeo, áudio + ou documento), o conteúdo retorna como content blocks multimodais — + não como texto. Extensões oficialmente suportadas: +

+
+ + + + + + + + +
TipoExtensões
Imagem.png .jpg .jpeg .gif .webp .heic .heif
Vídeo.mp4 .mpeg .mov .avi .flv .mpg .webm .wmv .3gpp
Áudio.wav .mp3 .aiff .aac .ogg .flac
Documento.pdf .ppt .pptx
+
+
+ A estrutura exata do content block não é detalhada na página do harness — ela + aponta para a documentação de mensagens multimodais do LangChain + (langchain/messages, + seção #multimodal). As tools de FS built-in são ls, + read_file, write_file, edit_file, + glob, grep e execute (este só em + backends sandbox). +
+ +
+ +
+

6. System prompt e ordem de montagem

+

Slots

+

O system prompt resultante é montado por USER → (BASE ou CUSTOM) → SUFFIX, juntando por \n\n.

+
+ + + + + + + + +
SlotFonte
USERArgumento system_prompt= de create_deep_agent
BASEDefault do SDK — constante BASE_AGENT_PROMPT
CUSTOMHarnessProfile.base_system_prompt — substitui BASE
SUFFIXHarnessProfile.system_prompt_suffix — anexado por último
+
+

Camadas adicionadas por middleware (ordem)

+
    +
  1. Custom system_prompt (slot USER)
  2. +
  3. Base prompt do agent (BASE ou CUSTOM)
  4. +
  5. Prompt da to-do list
  6. +
  7. Prompt de memória (se MemoryMiddleware)
  8. +
  9. Prompt de skills (se SkillsMiddleware)
  10. +
  11. Prompt do filesystem virtual
  12. +
  13. Prompt de subagent (TASK_SYSTEM_PROMPT)
  14. +
  15. Prompts de middleware do usuário
  16. +
  17. Prompt de human-in-the-loop (se interrupt_on)
  18. +
+

Conteúdo dos prompts (paráfrase oficial)

+

+ A documentação pública sumariza o conteúdo das constantes — o texto completo + fica na biblioteca. Importe e inspecione: + from deepagents.graph import BASE_AGENT_PROMPT. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ConstanteFunção e seções (paráfrase)
BASE_AGENT_PROMPTAbre identificando o agente como "deep agent" que ajuda usuários a cumprir tarefas com tools. Seções: core behavior (ser conciso e direto, sem filler), professional objectivity (priorizar precisão sobre validação emocional), execução de tarefa em três etapas (entender via leitura/inspeção → agir com precisão → verificar contra o pedido original), persistência (continuar até completar; iterar em vez de repetir tentativas falhas), clarificação (perguntar de domínio antes de implementação) e progress updates (curtos, em intervalos razoáveis).
TASK_SYSTEM_PROMPTOrienta o agente orquestrador no uso da tool task: delegar quando a sub-tarefa é complexa/multistep, independente, ou se beneficia de sandboxing; NÃO delegar quando é trivial, exige raciocínio intermediário ou não traria ganho de latência. Recomenda disparar passos independentes em paralelo. Refere-se aos subagents como "highly competent and efficient."
FILESYSTEM_SYSTEM_PROMPTInstruções sobre as tools de FS. Construído a partir de _FILESYSTEM_SYSTEM_PROMPT_TEMPLATE.format(large_tool_results_prefix='/large_tool_results').
SKILLS_SYSTEM_PROMPTUso de skills. Duas fontes: Deepagents (agent-specific) e Agents (compartilhada). Progressive disclosure: nome+descrição aparecem upfront; read_file com limit=1000 sobre o SKILL.md quando necessário. Slots de template: {skills_locations}, {skills_load_warnings}, {skills_list}.
MEMORY_SYSTEM_PROMPTTem bloco <agent_memory>{agent_memory}</agent_memory> + regras em <memory_guidelines>. Inclui aviso de confiança: o texto dentro de <agent_memory> é dado em disco — pode estar desatualizado/incorreto. Atualizações via edit_file; nunca armazenar credenciais.
SUMMARIZATION_SYSTEM_PROMPTEncoraja o modelo a chamar compact_conversation entre tarefas. A tool fica registrada mesmo sem o prompt, mas o modelo dificilmente descobriria sem menção explícita.
+
+
+ +
+

7. Sub-agents

+

Tipos disponíveis

+
from typing import TypedDict, NotRequired, Sequence
+from langchain.tools import BaseTool
+from langchain.agents.middleware import AgentMiddleware
+
+class SubAgent(TypedDict):
+    name: str                                       # obrigatório
+    description: str                                # obrigatório
+    system_prompt: str                              # obrigatório; NÃO herda do pai
+    tools: NotRequired[Sequence[BaseTool | callable | dict]]  # se set, SUBSTITUI as herdadas
+    model: NotRequired[str | object]                # default = main model
+    middleware: NotRequired[list[AgentMiddleware]]  # NÃO herda
+    interrupt_on: NotRequired[dict[str, bool | dict]]
+    skills: NotRequired[list[str]]                  # isolado do pai
+    permissions: NotRequired[list[object]]          # SUBSTITUI o do pai
+    response_format: NotRequired[object]
+

CompiledSubAgent — embrulhar grafo pronto

+
from deepagents import CompiledSubAgent
+from langchain.agents import create_agent
+
+custom_graph = create_agent(model="openai:gpt-5.5", tools=[...], prompt="...")
+
+custom_subagent = CompiledSubAgent(
+    name="data-analyzer",
+    description="Specialized agent for complex data analysis tasks",
+    runnable=custom_graph,  # precisa ter um state key chamado "messages"
+)
+

AsyncSubAgent — fire-and-forget em background

+
class AsyncSubAgent(TypedDict):
+    name: str
+    description: str
+    graph_id: str                       # ID no Agent Protocol server
+    url: NotRequired[str]               # omitir = in-process ASGI; setar = HTTP remoto
+    headers: NotRequired[dict[str, str]]
+

+ Cinco tools supervisoras aparecem automaticamente: start_async_task, + check_async_task, update_async_task, + cancel_async_task, list_async_tasks. Metadados das + tasks vivem em um canal dedicado async_tasks do estado, que + sobrevive a compactação de histórico. +

+

Subagent general-purpose default

+

+ Sempre adicionado, exceto quando desabilitado explicitamente. Compartilha + system prompt, tools, model e skills do agente principal. Para desligar: +

+
from deepagents import HarnessProfile, GeneralPurposeSubagentProfile, register_harness_profile
+
+register_harness_profile(
+    "<profile-key>",
+    HarnessProfile(
+        general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False),
+    ),
+)
+# E não passe nenhum subagent síncrono em create_deep_agent.
+# NÃO use excluded_middleware={"SubAgentMiddleware"} — isso levanta ValueError.
+

Context quarantine

+

+ Citando a doc: "Subagents isolate this detailed work — the main agent + receives only the final result, not the dozens of tool calls that produced + it.". Chamada: + task(subagent_type="general-purpose", description="Research quantum computing trends"). + Identificar o caller via + runtime.config.get("metadata", {}).get("lc_agent_name"). +

+ +

7.1 Structured output

+

+ Agente principal: passe response_format=Schema + ao create_deep_agent; o resultado tipado fica em + result["structured_response"]. +

+
result = agent.invoke({"messages": [...]})
+findings = result["structured_response"]   # instância do Schema
+

+ Subagent: declare "response_format": Schema no + dict do subagent. Ao terminar, a saída estruturada do subagent volta ao pai + como JSON serializado dentro do ToolMessage da + tool task (não como objeto Python). Requer + deepagents >= 0.5.3. +

+
research_subagent = {
+    "name": "researcher",
+    "description": "Researches topics and returns structured findings",
+    "system_prompt": "Research the given topic thoroughly. Return your findings.",
+    "tools": [web_search],
+    "response_format": ResearchFindings,   # Pydantic / ToolStrategy / ProviderStrategy / raw schema
+}
+agent = create_deep_agent(model="claude-sonnet-4-6", subagents=[research_subagent])
+ +
+ +
+

8. Sistema de arquivos virtual

+

+ Por padrão, o Deep Agent usa o StateBackend — um filesystem em + memória, escopado por thread, persistido pelo checkpointer junto com o + estado. Subagents síncronos compartilham a mesma visão; sandboxes têm + isolamento físico. +

+
from deepagents.backends import StateBackend, FilesystemBackend, LocalShellBackend, StoreBackend, CompositeBackend
+
+# Default (state-backed, per-thread)
+agent = create_deep_agent(model="...", tools=[], backend=StateBackend())
+
+# Disco real (NÃO recomendado para produção)
+agent = create_deep_agent(
+    model="...", tools=[],
+    backend=FilesystemBackend(root_dir="/abs/path/to/workspace", virtual_mode=True),
+)
+
+# Composite (default state + memórias no Store)
+agent = create_deep_agent(
+    model="...", tools=[],
+    backend=CompositeBackend(
+        default=StateBackend(),
+        routes={"/memories/": StoreBackend(namespace=lambda rt: (rt.server_info.assistant_id,))},
+    ),
+    store=InMemoryStore(),
+)
+
+ +
+

9. Catálogo de backends

+
+ + + + + + + + + + + + + + + + +
BackendImportPersistênciaCaso de uso
StateBackenddeepagents.backendsPor thread (estado LangGraph)Scratch pad default. Subagents síncronos compartilham writes.
FilesystemBackenddeepagents.backendsDisco localroot_dir (abs) + virtual_mode=True. Não use em produção.
LocalShellBackenddeepagents.backendsDisco local + shellAdiciona execute via subprocess.run(shell=True). Não para produção. Params: timeout=120, max_output_bytes=100_000, env, inherit_env.
StoreBackenddeepagents.backendsBaseStore (cross-thread)Requer store= no create_deep_agent. namespace=lambda rt: (...,).
ContextHubBackenddeepagents.backendsLangSmith Hub repoWrites commit-otimistas; LANGSMITH_API_KEY. Apenas texto UTF-8 via upload_files().
CompositeBackenddeepagents.backendsRoteado por prefixodefault= + routes={prefix: backend}. Prefixos mais longos vencem. ls/glob/grep agregam.
ModalSandboxlangchain-modal → from langchain_modal import ModalSandboxSandbox+ execute. Teardown: sandbox.terminate().
DaytonaSandboxlangchain-daytona → from langchain_daytona import DaytonaSandboxSandboxTeardown: sandbox.stop().
RunloopSandboxlangchain-runloop → from langchain_runloop import RunloopSandboxSandboxTeardown: devbox.shutdown().
LangSmithSandboxlangsmith[sandbox] → from deepagents.backends import LangSmithSandboxSandboxTeardown: client.delete_sandbox(...).
AgentCoreSandboxlangchain-agentcore-codeinterpreter → from langchain_agentcore_codeinterpreter import AgentCoreSandboxSandbox (AWS Bedrock AgentCore)Recebe um CodeInterpreter de bedrock_agentcore. Teardown: interpreter.stop() em finally (ver 9.1).
E2BBackend proposto, ainda não lançado. Há proposta oficial (GitHub issue #1739) de um pacote langchain-e2b implementando o SandboxBackendProtocol + flag --sandbox e2b; até o lançamento não há pacote/import publicado. O E2B tem SDK próprio (e2b-code-interpreter), mas ainda não como backend Deep Agents.Sandbox (proposto)—
+
+ +

9.1 AgentCoreSandbox (AWS Bedrock AgentCore)

+

+ Diferente dos outros sandboxes, o AgentCoreSandbox não fabrica o + interpretador internamente — você cria um CodeInterpreter do + pacote bedrock_agentcore, faz start()/ + stop() do seu ciclo de vida e passa-o ao backend. +

+
from bedrock_agentcore.tools.code_interpreter_client import CodeInterpreter
+from langchain_agentcore_codeinterpreter import AgentCoreSandbox
+from deepagents import create_deep_agent
+from langchain_anthropic import ChatAnthropic
+
+interpreter = CodeInterpreter(region="us-west-2")
+interpreter.start()
+backend = AgentCoreSandbox(interpreter=interpreter)
+
+try:
+    agent = create_deep_agent(
+        model=ChatAnthropic(model="claude-sonnet-4-6"),
+        backend=backend,
+    )
+    # ... usar o agente ...
+finally:
+    interpreter.stop()   # teardown obrigatório
+ + +

Instanciação two-step para sandboxes

+

Sandbox providers retornam um cliente (longo-vivo) e produzem backends (curto-vivos, 1 por agent/run). Não passe o cliente direto em backend=.

+
from langchain_modal import ModalSandbox
+from deepagents import create_deep_agent
+
+# 1) Cliente do provedor (acquire/release de VMs no pool)
+sandbox = ModalSandbox(workspace="my-org")
+
+# 2) Backend por agent: chame .backend() ou método equivalente do provider
+agent = create_deep_agent(
+    model="google_genai:gemini-3.5-flash",
+    backend=sandbox.backend(),                # ← instância, não factory
+    tools=[...],
+)
+
+try:
+    result = agent.invoke({"messages":[{"role":"user","content":"..."}]})
+finally:
+    sandbox.terminate()        # libera o pool
+

BackendProtocol — backend customizado

+
from deepagents.backends.protocol import (
+    BackendProtocol, LsResult, ReadResult, WriteResult, EditResult,
+    GlobResult, GrepResult, FileInfo, FileData, GrepMatch,
+)
+
+class MyBackend(BackendProtocol):
+    def ls(self, path: str) -> LsResult: ...
+    def read(self, file_path: str, offset: int = 0, limit: int = 2000) -> ReadResult: ...
+    def grep(self, pattern: str, path=None, glob=None) -> GrepResult: ...
+    def glob(self, pattern: str, path: str = "/") -> GlobResult: ...
+    def write(self, file_path: str, content: str) -> WriteResult: ...
+    def edit(self, file_path: str, old_string: str, new_string: str,
+             replace_all: bool = False) -> EditResult: ...
+    # Também: upload_files, download_files, ls_info, glob_info, grep_raw
+    # Todos os métodos possuem contraparte async com prefixo `a`.
+

+ Implementações retornam erros, nunca levantam — os + *Result têm campo error. Para suporte a + execute, implemente também SandboxBackendProtocol. +

+
+ Passar callables-factory a backend= está depreciado desde v0.5.0. + Passe instâncias. BackendContext será removido em v0.7 — use + Runtime diretamente: + lambda rt: (rt.server_info.user.identity,). +
+
+ +
+

10. Permissões

+
from deepagents import create_deep_agent, FilesystemPermission
+
+agent = create_deep_agent(
+    model="google_genai:gemini-3.5-flash",
+    permissions=[
+        FilesystemPermission(operations=["write"], paths=["/policies/**"], mode="deny"),
+        FilesystemPermission(operations=["read", "write"], paths=["/workspace/**"], mode="allow"),
+        FilesystemPermission(operations=["read", "write"], paths=["/**"], mode="deny"),
+    ],
+)
+
+ + + + + + + +
CampoValoresNotas
operationslist["read" \| "write"]—
pathslist[str]Glob: **, {a,b}
mode"allow" \| "deny"Default "allow"
+
+

+ First-match-wins. Sem regra que case ⇒ permitido. Cobre apenas as tools de + FS embutidas; tools customizadas, MCP e execute não são + inspecionados. Subagents herdam — definir permissions no + subagent substitui as regras do pai. Com + CompositeBackend + sandbox default, paths devem permanecer dentro + dos prefixos conhecidos (sob pena de NotImplementedError). + Requer deepagents >= 0.5.2. +

+
+ Validação customizada (alternativa às permissions): como as + FilesystemPermission só cobrem as FS tools built-in, para + políticas mais ricas (quotas, sanitização de conteúdo, auditoria, bloqueio + por padrão de path) crie uma subclasse de FilesystemBackend ou + um wrapper de BackendProtocol que intercepte + write/edit/read e retorne os + *Result com o campo error preenchido (os métodos + retornam erro, nunca levantam). Isso aplica a regra antes de qualquer write + chegar ao armazenamento. +
+
+ +
+

11. Catálogo de middleware

+
+ + + + + + + + + + + + + + + + + + + + + + +
MiddlewareHook(s)PropósitoParams-chave
TodoListMiddlewarebefore_modelInjeta write_todos; trackeia plano—
FilesystemMiddlewarewrap_model_call, wrap_tool_callInjeta FS tools (+ execute em sandbox)backend, system_prompt, custom_tool_descriptions, tool_token_limit_before_evict=20000, human_message_token_limit_before_evict=50000, max_execute_timeout=3600
SubAgentMiddlewareinjeta taskSpawn de subagent síncronobackend, subagents, system_prompt=TASK_SYSTEM_PROMPT, task_description=None
AsyncSubAgentMiddlewareinjeta 5 tools asyncBackground subagents(auto-adicionado se há AsyncSubAgent)
SkillsMiddlewareinjeta promptProgressive disclosure de skillsbackend, sources: Sequence[SkillSource], system_prompt=SKILLS_SYSTEM_PROMPT
MemoryMiddlewareinjeta promptCarregar AGENTS.mdbackend, sources: list[str], add_cache_control=False, system_prompt=MEMORY_SYSTEM_PROMPT
SummarizationMiddlewareauto-compactionTrigger em 85% de max_input_tokens; mantém 10% recentes (fallback 170k / 6 msgs)compute_summarization_defaults(), create_summarization_middleware()
SummarizationToolMiddlewareadiciona compact_conversationSummarization disparada pelo agentesummarization, system_prompt=SUMMARIZATION_SYSTEM_PROMPT
AnthropicPromptCachingMiddlewaremodel wrapCache de prompt no Anthropic; no-op fora(auto no tail stack)
PatchToolCallsMiddlewarebefore_agentRepara tool calls "pendurados" depois de interrupts—
HumanInTheLoopMiddlewaretool wrapPausa em tools de interrupt_on(auto quando interrupt_on=)
CodeInterpreterMiddlewareadiciona evalSandbox QuickJS para TS/JSmemory_limit=64MB, timeout=5.0, max_ptc_calls=256, tool_name="eval", max_result_chars=4000, capture_console=True, ptc=None, skills_backend=None, snapshot_between_turns=True, max_snapshot_bytes=None · instalar com pip install -U "deepagents[quickjs]"
ModelCallLimitMiddlewaremodel wrapLimita LLM calls por run/threadrun_limit, thread_limit
ToolCallLimitMiddlewaretool wrapLimita tool callsrun_limit, thread_limit
ModelRetryMiddlewaremodel wrapBackoff em erros transitóriosmax_retries, backoff_factor
ModelFallbackMiddlewaremodel wrapTroca modelo em falhalista de model ids
ToolRetryMiddlewaretool wrapRetry por toolmax_retries, tools
PIIMiddlewareinput wrapRedact/mask/hash/block PII("email", strategy="redact", apply_to_input=True)
+
+
+ +
+

12. Skills

+

+ Skills são pacotes SKILL.md com frontmatter YAML, descobertos por + progressive disclosure (nome+descrição expostos upfront, conteúdo só + carregado quando o agente decide usar). +

+

Frontmatter

+
---
+name: my-skill
+description: When to use this skill (truncado em 1024 chars)
+license: MIT
+compatibility: requirements
+allowed-tools: fetch_url
+module: index.ts    # apenas para skills de interpreter
+---
+# Instruções a seguir...
+

Carregar

+
from deepagents.backends import StateBackend
+from deepagents.backends.utils import create_file_data
+from langchain_quickjs import CodeInterpreterMiddleware
+from langgraph.checkpoint.memory import MemorySaver
+
+backend = StateBackend()
+
+agent = create_deep_agent(
+    model="openai:gpt-5.5",
+    backend=backend,
+    skills=["/skills/"],
+    checkpointer=MemorySaver(),
+    middleware=[CodeInterpreterMiddleware(skills_backend=backend)],
+)
+
+agent.invoke(
+    {
+        "messages": [{"role": "user", "content": "..."}],
+        "files": {"/skills/my-skill/SKILL.md": create_file_data(skill_content)},
+    },
+    config={"configurable": {"thread_id": "12345"}},
+)
+

+ Precedência de fontes: entradas posteriores em + skills= sobrepõem skills de mesmo nome. + Subagent general-purpose herda skills; subagents + customizados não (passe skills= explícito). + Tamanho máximo do SKILL.md: 10 MB. Skills com module: + são importáveis no interpreter: + const { fn } = await import("@/skills/order-helpers");. +

+
+ +
+

13. Memória — AGENTS.md

+
from deepagents.backends.utils import create_file_data
+from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
+from langgraph.checkpoint.memory import MemorySaver
+from langgraph.store.memory import InMemoryStore
+
+agent = create_deep_agent(
+    model="anthropic:claude-sonnet-4-6",
+    memory=["/memories/AGENTS.md"],
+    backend=CompositeBackend(
+        default=StateBackend(),
+        routes={
+            "/memories/": StoreBackend(namespace=lambda rt: (rt.server_info.assistant_id,)),
+        },
+    ),
+    store=InMemoryStore(),
+    checkpointer=MemorySaver(),
+)
+

Estratégias de escopo (namespaces)

+
+ + + + + + + + +
EscopoNamespace
Por usuário (recomendado)(assistant_id, user_id)
Por assistente(assistant_id,)
Por usuário (global)(user_id,)
Por organização (read-only)(org_id,)
+
+
+ Memória compartilhada e gravável é vetor de prompt injection. Default em + user-scoped; use permissions ou políticas explícitas para + memória read-only. +
+
+ +
+

14. Profiles

+
from deepagents import (
+    HarnessProfile, GeneralPurposeSubagentProfile, register_harness_profile,
+    ProviderProfile, register_provider_profile,
+)
+

HarnessProfile

+
+ + + + + + + + + + + +
CampoPropósito
base_system_promptSubstitui BASE_AGENT_PROMPT (slot CUSTOM)
system_prompt_suffixAnexado depois do BASE/CUSTOM, no main agent E nos subagents
tool_description_overridesdict[tool_name, str]
excluded_toolsRemove tools por nome após injeção. É a forma correta de esconder as FS tools (ex.: {"ls","read_file","write_file","edit_file","glob","grep"}).
excluded_middlewareStrip por classe ou string. Remover FilesystemMiddleware (ou SubAgentMiddleware / a permission middleware interna) por aqui levanta ValueError — use excluded_tools para esconder as FS tools.
extra_middlewareAnexa a todo stack que casar
general_purpose_subagentGeneralPurposeSubagentProfile(enabled=..., system_prompt=...)
+
+

+ Chaves de registro: "openai" (provider-level) ou + "openai:gpt-5.5" (model-level). Model-level faz merge sobre + provider-level. Re-registrar é aditivo. +

+

+ Profiles built-in que vêm com o pacote: _anthropic_opus_4_7, + _anthropic_sonnet_4_6, _anthropic_haiku_4_5, + _openai_codex. +

+

+ Entry-point de plugin: "deepagents.harness_profiles" + em pyproject.toml. Config em arquivo: + HarnessProfileConfig.from_dict(yaml.safe_load(f)) e + register_harness_profile aceita ambos. +

+

ProviderProfile

+

Tem três campos. Só se aplica quando você passa o modelo como string + provider:model (não quando passa uma instância de + init_chat_model já construída).

+
+ + + + + + + +
CampoTipoPropósito
init_kwargsMappingKwargs estáticos passados na construção do modelo.
pre_initCallable[[str], None]Side-effects antes de construir o modelo (ex.: validar credenciais).
init_kwargs_factoryCallable[[], dict[str, Any]]Kwargs derivados em runtime (avaliados a cada construção).
+
+
def _check_creds(model: str) -> None:
+    import os
+    if not os.environ.get("OPENAI_API_KEY"):
+        raise RuntimeError("OPENAI_API_KEY ausente")
+
+register_provider_profile(
+    "openai",
+    ProviderProfile(
+        init_kwargs={"temperature": 0},
+        pre_init=_check_creds,
+        init_kwargs_factory=lambda: {"timeout": int_from_runtime()},
+    ),
+)
+register_provider_profile("openai:gpt-5.5",
+                          ProviderProfile(init_kwargs={"reasoning_effort": "medium"}))
+
+ +
+

15. Human-in-the-loop

+
from langgraph.checkpoint.memory import MemorySaver
+from langgraph.types import Command
+
+agent = create_deep_agent(
+    model="google_genai:gemini-3.5-flash",
+    tools=[remove_file, fetch_file, notify_email],
+    interrupt_on={
+        "remove_file": True,                                # qualquer decisão
+        "fetch_file": False,                                # não interrompe
+        "notify_email": {"allowed_decisions": ["approve", "reject"]},
+    },
+    checkpointer=MemorySaver(),  # obrigatório
+)
+
+config = {"configurable": {"thread_id": "abc"}}
+result = agent.invoke({"messages": [...]}, config=config, version="v2")
+
+if result.interrupts:
+    interrupt_value = result.interrupts[0].value
+    decisions = [{"type": "approve"}]
+    # ou edit:
+    # decisions = [{"type": "edit", "edited_action": {"name": "...", "args": {...}}}]
+    result = agent.invoke(Command(resume={"decisions": decisions}),
+                          config=config, version="v2")
+

+ Decisions permitidas: "approve", + "edit", "reject", "respond". + Requisitos: checkpointer, mesmo thread_id no + resume, version="v2" em cada .invoke(), decisions + em ordem dos action_requests. +

+
+ +
+

16. Sandboxes

+

+ Sandboxes adicionam isolamento físico e habilitam a tool execute. + Cada provider é uma instalação opcional, e cada backend implementa + SandboxBackendProtocol. +

+
from langchain_modal import ModalSandbox  # ou DaytonaSandbox, RunloopSandbox
+
+sandbox = ModalSandbox(...)
+try:
+    agent = create_deep_agent(model="...", tools=[], backend=sandbox)
+    agent.invoke(...)
+finally:
+    sandbox.terminate()  # Daytona: .stop(); Runloop: .shutdown(); LangSmith: client.delete_sandbox(...)
+
+# Execute direto no backend (sem agent):
+result = sandbox.execute("python --version")
+print(result.output)  # "Python 3.11.x\n[Command succeeded with exit code 0]"
+

File transfer

+
sandbox.upload_files([("/src/index.py", b"print('Hello')\n")])
+results = sandbox.download_files(["/output.txt"])
+
+ +
+

17. Code interpreter (QuickJS)

+

+ O CodeInterpreterMiddleware embute QuickJS para executar JS/TS + dentro do mesmo processo do agente, sem precisar de sandbox externo. Adiciona + a tool eval. Instalação: pip install -U "deepagents[quickjs]". +

+
from langchain_quickjs import CodeInterpreterMiddleware
+
+middleware = CodeInterpreterMiddleware(
+    memory_limit=64 * 1024 * 1024,    # 64MB
+    timeout=5.0,
+    max_ptc_calls=256,
+    tool_name="eval",
+    max_result_chars=4000,
+    capture_console=True,
+    snapshot_between_turns=True,
+)
+

Kwargs completos de CodeInterpreterMiddleware: + memory_limit, timeout, max_ptc_calls, + tool_name, max_result_chars, + capture_console, ptc, skills_backend, + snapshot_between_turns e max_snapshot_bytes.

+ +

17.1 Programmatic Tool Calling (PTC)

+

+ Com PTC, o modelo invoca suas tools de dentro do código JS, em vez + de pelo caminho normal de tool calling. Declare a allowlist com + ptc=[...] (lista de nomes de tools liberadas). Dentro do + interpretador QuickJS, as tools ficam disponíveis sob o namespace + tools. em camelCase e devem ser aguardadas com + await (ex.: a tool web_search vira + tools.webSearch(...)). +

+
from deepagents import create_deep_agent
+from langchain_quickjs import CodeInterpreterMiddleware
+
+agent = create_deep_agent(
+    model="openai:gpt-5.5",
+    middleware=[CodeInterpreterMiddleware(ptc=["task"])],   # allowlist PTC
+)
+
// Dentro do código executado no interpretador (camelCase + await)
+const result = await tools.webSearch({ query: "deepagents interpreters" });
+
+ Gotcha de segurança (citação oficial): "PTC calls + currently execute through the interpreter bridge and do not go through the + normal tool calling path. As a result, interrupt_on approval + workflows are not enforced per PTC-invoked tool call." Ou seja, tools + aprovadas via HITL (interrupt_on) não são + interrompidas quando chamadas por PTC — não inclua na allowlist tools que + exijam aprovação humana. +
+ +
+ +
+

18. Context engineering

+

+ Citando a doc oficial: context engineering = configuração de contexto que + maximiza a probabilidade do comportamento desejado. O Deep Agents + implementa as três técnicas long-horizon do paper da Anthropic: +

+
+ + + + + + + +
TécnicaQuando aplicarNo Deep Agents
CompactionContinuidade conversacionalSummarizationMiddleware (auto em 85% / 170k) + SummarizationToolMiddleware (manual via compact_conversation)
Note-taking estruturadoTrabalho iterativo com milestoneswrite_file / edit_file no FS virtual + MemoryMiddleware (AGENTS.md)
Sub-agent architecturesExploração paralela / pesquisa complexaSubAgent / AsyncSubAgent + tool task; subagent devolve sumário de ~1–2k tokens ao lead
+
+

Específicos da summarization

+
    +
  • Trigger: 85% de max_input_tokens. Mantém 10% como recent context.
  • +
  • Fallback (profile do modelo não disponível): trigger em 170 000 tokens, 6 mensagens mantidas.
  • +
  • Dois outputs: sumário estruturado in-context (intent / artifacts / next steps) substitui o histórico; mensagens originais são escritas em disco para recuperação.
  • +
  • Thresholds de offload: inputs > 20k tokens ⇒ tool calls de file-write truncados a pointers de disco em 85% de uso de janela. Resultados > 20k ⇒ offload imediato com path + 10 primeiras linhas.
  • +
  • Diretórios de offload no backend: resultados grandes vão para /large_tool_results/ e o histórico compactado para /conversation_history/. Ambos são escritos no backend de arquivos.
  • +
  • Filtro em stream: if metadata.get("lc_source") == "summarization": continue.
  • +
+
+ Isolamento dos arquivos do sistema: como o harness escreve em + /large_tool_results/ e /conversation_history/, envolva + o FilesystemBackend (ou o backend de projeto) em um + CompositeBackend para que esses diretórios de offload não se + misturem com os arquivos do projeto: +
+
from deepagents.backends import CompositeBackend, StateBackend, FilesystemBackend
+
+backend = CompositeBackend(
+    default=StateBackend(),                          # offload do harness fica aqui
+    routes={"/project/": FilesystemBackend(root_dir="/abs/workspace", virtual_mode=True)},
+)
+ +
+ +
+

19. Streaming

+

+ O Deep Agents delega ao LangGraph. Com o cliente useStream + (React/Vue/Svelte/Angular): +

+
const stream = useStream({
+  apiUrl: "https://your-deployment.langsmith.dev",
+  assistantId: "agent",
+  reconnectOnMount: true,
+  fetchStateHistory: true,
+});
+
+stream.submit(input, {
+  streamSubgraphs: true,
+  config: { recursionLimit: 10000 },  // alto para muitos subagents
+});
+

Em Python, use os modos do LangGraph (updates, messages, custom, etc.) e habilite subgraphs=True + version="v2" para receber eventos com namespace.

+
+ +
+

20. Async

+
    +
  • Não existe async_create_deep_agent. Use o mesmo construtor e await agent.ainvoke(...) / agent.astream(...).
  • +
  • Hooks async em middleware: abefore_agent, awrap_model_call, awrap_tool_call, astream.
  • +
  • Subagents em background: use AsyncSubAgent em subagents=. Exige deployment LangGraph suportando Agent Protocol (langgraph dev --n-jobs-per-worker 10 localmente — um slot para supervisor + concorrentes).
  • +
+
+ Dica para o system prompt: "After launching an async + subagent, ALWAYS return control to the user. Never call check_async_task + immediately after launch." — evita polling parasita. +
+
+ +
+

21. Going to production

+
    +
  • Primitivas: thread, user, assistant.
  • +
  • Deployment: Managed Deep Agents (private preview LangSmith) ou self-hosted via langgraph build.
  • +
  • Invocação: toda call requer thread_id e/ou context.
  • +
  • Multi-tenancy: três camadas — auth de end-user, agent-acting-as-user (OAuth com interrupts), RBAC de team.
  • +
  • Filesystem: nunca use FilesystemBackend / LocalShellBackend em agentes deployed. Use CompositeBackend(default=StateBackend(), routes={"/memories/": StoreBackend(...)}).
  • +
  • Secrets: use auth proxy (proxy_config.rules[].inject_headers) — chaves nunca entram no sandbox.
  • +
  • Guardrails: ModelCallLimitMiddleware, ToolCallLimitMiddleware, ModelRetryMiddleware, ModelFallbackMiddleware, ToolRetryMiddleware, PIIMiddleware.
  • +
+
+ +
+

22. Modelos sugeridos

+

22.1 Trio padrão do projeto

+

+ Modelos default recomendados para os exemplos de código deste guia — um trio + atual por provedor (frontier / equilíbrio / baixo custo). Use o formato de + string provider:model ou a classe nativa do provedor (ver + política de integração no capítulo 4). +

+
+ + + + + + + +
ProvedorFrontierEquilíbrioBaixo custo
OpenAIgpt-5.5gpt-5.4-minigpt-5.4-nano
Googlegemini-3.1-pro-previewgemini-3.5-flashgemini-3.1-flash-lite
Anthropicclaude-opus-4-8claude-sonnet-4-6claude-haiku-4-5
+
+
+ A página oficial deepagents/models + publica uma lista mais ampla de modelos "suggested" (incluindo IDs OpenAI como + gpt-5.4, gpt-4o, o4-mini e variantes + open-weight como GLM-5, Kimi-K2.5); o trio acima é o + default do projeto para os snippets deste guia, não a lista + oficial completa. +
+ +

22.2 Eval suite oficial

+

+ Top eval (DeepAgents eval suite — reprodução oficial): + openrouter:z-ai/glm-5.1 89% · + google_genai:gemini-3.5-flash 82% · + openai:gpt-5.5 80% · + anthropic:claude-opus-4-8 80% · + anthropic:claude-opus-4-6 26% · + openai:gpt-5.4 18%. +

+

+ Citação direta do doc: "Passing these evals is necessary but not + sufficient for strong performance on longer, more complex tasks." +

+

+ Benchmark oficial — IDs preservados; o projeto padroniza nos modelos atuais + do trio acima (22.1). +

+
+ +
+

23. Comparação · Deep Agents vs Claude Agent SDK

+
+ + + + + + + + + +
DimensãoDeep AgentsClaude Agent SDK
Suporte a modelos100+ providersApenas Claude (Anthropic/Bedrock/Vertex/Azure)
ExecuçãoBackends pluggable (in ou out de sandbox)Apenas dentro de sandbox
DeploymentManaged (LangSmith) ou self-hosted (langgraph build)Self-hosted; build o servidor
Multi-tenancyBuilt-in (threads escopados, sandboxes por usuário, RBAC, auth proxy)DIY
LicençaMITMIT (Claude Code em si é proprietário)
+
+
+ +
+

24. dcode — CLI

+

+ O dcode é o "Deep Agents Code", um agente de coding em terminal + construído sobre o SDK. Open-source. +

+

Instalação

+
curl -LsSf https://langch.in/dcode | bash
+# ou
+uv tool install 'deepagents-code[fireworks,nvidia]'
+

Tools built-in

+
+ + + + + + + +
ToolRequer aprovação?
ls, read_file, glob, grep, ask_user, write_todosNão
write_file, edit_file, execute, web_search, fetch_url, taskSim
compact_conversationMisto
+
+

Pular aprovação: dcode -y ou --auto-approve. Toggle in-session: Shift+Tab.

+

Flags principais

+

-a/--agent, -M/--model, --model-params JSON, -r/--resume, -m TEXT, -n TEXT, --max-turns N, --timeout SECONDS, -S/--shell-allow-list, --no-stream, --sandbox {none,langsmith,modal,daytona,runloop,agentcore}, --sandbox-id, --sandbox-setup, --mcp-config, --no-mcp, --acp, --json. Exit code 124 quando turn/time budget é excedido.

+

Slash commands

+

/model, /agents, /auth, /remember, /skill:<name>, /offload, /compact, /tokens, /clear, /threads, /mcp, /reload, /theme, /update, /trace, /editor, /quit.

+

Layout de config

+
    +
  • ~/.deepagents/config.toml — defaults de modelo, profile overrides, themes, MCP trust
  • +
  • ~/.deepagents/.env — chaves API globais
  • +
  • ~/.deepagents/hooks.json — hooks de lifecycle
  • +
  • ~/.deepagents/<agent_name>/ — memória/skills/threads por agente
  • +
  • .deepagents/ (raiz do projeto) — memória + skills específicos do projeto
  • +
  • Prefixo de env DEEPAGENTS_CODE_ escopa credenciais ao dcode
  • +
+

Subagents em dcode

+
.deepagents/agents/{subagent-name}/AGENTS.md           # projeto
+~/.deepagents/{agent}/agents/{subagent-name}/AGENTS.md # usuário
+

+ Frontmatter obrigatório: name, description. + Opcional: model. Corpo = system prompt. Outros campos de + SubAgent não são configuráveis via frontmatter. Async subagents + não são suportados em dcode. +

+
+ +
+

25. ACP — Agent Client Protocol

+

+ Padroniza a comunicação agente ↔ IDE (distinto do MCP). Transport via stdio. +

+
    +
  • Instalação: pip install deepagents-acp (ou uv add deepagents-acp)
  • +
  • Componentes: AgentServerACP, create_deep_agent, run_agent
  • +
  • Clients suportados: Zed (nativo via agent_servers), JetBrains (AI Assistant), VS Code (vscode-acp), Neovim
  • +
  • Dev local: toad acp "python path/to/your_server.py" .
  • +
+
+ +
+

Parte B — Referência de API

+

Referência técnica das classes públicas do deepagents. Cada entrada lista import, assinatura, parâmetros e exemplos. Para o texto completo das constantes de prompt, importe da biblioteca.

+
+ +
+

create_deep_agent

+
from deepagents import create_deep_agent
+

Veja o capítulo 4 para a assinatura completa, tabela de parâmetros e ordem do stack de middleware.

+

Retorno

+

+ CompiledStateGraph[AgentState[ResponseT], ContextT, _InputAgentState, _OutputAgentState[ResponseT]] + do LangGraph — mesma interface de create_agent. +

+
+ +
+

BASE_AGENT_PROMPT

+
from deepagents.graph import BASE_AGENT_PROMPT   # não reexportado no topo de `deepagents`
+# Outras constantes de prompt vivem em seus respectivos módulos de middleware:
+# from deepagents.middleware.subagents import TASK_SYSTEM_PROMPT
+# from deepagents.middleware.filesystem import FILESYSTEM_SYSTEM_PROMPT
+# from deepagents.middleware.skills import SKILLS_SYSTEM_PROMPT
+# from deepagents.middleware.memory import MEMORY_SYSTEM_PROMPT
+# from deepagents.middleware.summarization import SUMMARIZATION_SYSTEM_PROMPT
+

Cada constante é uma string. O capítulo 6 descreve as seções de cada prompt.

+
+ +
+

SubAgent · CompiledSubAgent · AsyncSubAgent

+
from deepagents import SubAgent, CompiledSubAgent, AsyncSubAgent
+
SubAgent (TypedDict) +
+

Campos: name (str), description (str), system_prompt (str). Opcionais: tools, model, middleware, interrupt_on, skills, permissions, response_format. Não herda tools/middleware/permissões do pai — definir substitui.

+
+
CompiledSubAgent +
+
CompiledSubAgent(name: str, description: str, runnable: CompiledStateGraph)
+

O runnable precisa ter um state key messages. Útil para embrulhar grafos pré-compilados com semântica arbitrária.

+
+
AsyncSubAgent (TypedDict) +
+

Campos: name, description, graph_id. Opcionais: url (omitir = in-process; setar = HTTP remoto), headers.

+
+
+ +
+

DeepAgentState e extensões

+
from deepagents.middleware.filesystem import FilesystemState
+from deepagents.middleware.skills import SkillsState
+from deepagents.middleware.memory import MemoryState
+from deepagents.middleware.async_subagents import AsyncSubAgentState
+
+ + + + + + + + + +
ClasseAdiciona ao AgentState
FilesystemStatefiles
SkillsStateskills_metadata
MemoryStatememory_contents
SummarizationStatecheckpoints de summarization
AsyncSubAgentStateasync_tasks
+
+

Composição via herança de TypedDict. O grafo compilado usa AgentState[ResponseT].

+
+ +
+

Ferramentas built-in

+

Veja o capítulo 5 para a tabela completa de tools e seus schemas. Imports das schemas correspondentes (úteis para customização e validation):

+
from deepagents.middleware.filesystem import (
+    LsSchema, ReadFileSchema, WriteFileSchema, EditFileSchema,
+    GlobSchema, GrepSchema, ExecuteSchema,
+)
+from deepagents.middleware.subagents import TaskToolSchema
+from deepagents.middleware.async_subagents import (
+    StartAsyncTaskSchema, CheckAsyncTaskSchema, UpdateAsyncTaskSchema,
+    CancelAsyncTaskSchema, ListAsyncTasksSchema,
+)
+
+ +
+

FilesystemMiddleware

+
from deepagents.middleware.filesystem import FilesystemMiddleware
+
+FilesystemMiddleware(
+    backend: BackendProtocol = StateBackend(),
+    system_prompt: str | None = None,
+    custom_tool_descriptions: dict[str, str] | None = None,
+    tool_token_limit_before_evict: int = 20000,
+    human_message_token_limit_before_evict: int = 50000,
+    max_execute_timeout: int = 3600,
+)
+

Injeta ls, read_file, write_file, edit_file, glob, grep; e execute se o backend é sandbox.

+
+ +
+

SubAgentMiddleware · AsyncSubAgentMiddleware

+
from deepagents.middleware.subagents import SubAgentMiddleware
+
+SubAgentMiddleware(
+    default_model: str | BaseChatModel,
+    default_tools: list = [],
+    subagents: list = [],
+    system_prompt: str | None = None,   # default = TASK_SYSTEM_PROMPT
+    task_description: str | None = None,
+)
+

Exemplo:

+
SubAgentMiddleware(
+    default_model="claude-sonnet-4-6",
+    subagents=[{
+        "name": "weather",
+        "description": "Gets weather in cities.",
+        "system_prompt": "Use get_weather tool...",
+        "tools": [get_weather],
+        "model": "gpt-5.5",
+        "middleware": [],
+    }],
+)
+

+ AsyncSubAgentMiddleware é auto-adicionado quando há AsyncSubAgent em subagents=. Expõe automaticamente as 5 tools de orquestração background. +

+
+ +
+

SkillsMiddleware

+
from deepagents.middleware.skills import SkillsMiddleware, SkillMetadata
+
+SkillsMiddleware(
+    backend: BackendProtocol,
+    sources: Sequence[SkillSource],
+    system_prompt: str = SKILLS_SYSTEM_PROMPT,
+)
+

O system_prompt precisa conter os slots {skills_locations}, {skills_load_warnings}, {skills_list}.

+
+ +
+

MemoryMiddleware

+
from deepagents.middleware.memory import MemoryMiddleware, MemoryState
+
+MemoryMiddleware(
+    backend: BackendProtocol,
+    sources: list[str],
+    add_cache_control: bool = False,
+    system_prompt: str = MEMORY_SYSTEM_PROMPT,
+)
+

O system_prompt precisa conter o slot {agent_memory}.

+
+ +
+

SummarizationToolMiddleware · PatchToolCallsMiddleware · TodoListMiddleware

+
from deepagents.middleware.summarization import (
+    SummarizationToolMiddleware, create_summarization_middleware,
+    create_summarization_tool_middleware, SummarizationEvent, SummarizationDefaults,
+    compute_summarization_defaults,
+)
+from deepagents.middleware.patch_tool_calls import PatchToolCallsMiddleware
+# TodoListMiddleware vem do LangChain (o Deep Agents o reexporta no base stack), não de deepagents:
+from langchain.agents.middleware import TodoListMiddleware
+

+ SummarizationToolMiddleware(summarization, system_prompt=SUMMARIZATION_SYSTEM_PROMPT) + expõe a tool compact_conversation. A versão automática + (create_summarization_middleware) é incluída no base stack — aciona + em 85% do max_input_tokens e mantém 10% recentes. +

+

+ PatchToolCallsMiddleware é colocado no base stack em + before_agent e repara tool calls "pendurados" quando há retoma + após um interrupt. +

+
+ +
+

CodeInterpreterMiddleware (QuickJS)

+
from langchain_quickjs import CodeInterpreterMiddleware
+
+CodeInterpreterMiddleware(
+    memory_limit: int = 64 * 1024 * 1024,
+    timeout: float = 5.0,
+    max_ptc_calls: int = 256,
+    tool_name: str = "eval",
+    max_result_chars: int = 4000,
+    capture_console: bool = True,
+    ptc=None,
+    skills_backend: BackendProtocol | None = None,
+    snapshot_between_turns: bool = True,
+    max_snapshot_bytes: int | None = None,
+)
+

Requer pip install -U "deepagents[quickjs]".

+
+ Snapshots entre turnos: com + snapshot_between_turns=True, o estado do interpretador persiste + de um turno para o seguinte, mas apenas valores serializáveis + são retidos (objetos não serializáveis são descartados). + max_snapshot_bytes limita o tamanho do snapshot. +
+
+ +
+

Model/Tool limits e retries

+
from langchain.agents.middleware import (
+    ModelCallLimitMiddleware, ToolCallLimitMiddleware,
+    ModelRetryMiddleware, ModelFallbackMiddleware, ToolRetryMiddleware,
+    PIIMiddleware,
+)
+

+ Estes são fornecidos pelo LangChain e são as primitivas de produção + recomendadas pelo Deep Agents: cap de calls, retry/backoff, fallback de + modelo e redação de PII. Veja o capítulo 11 para a tabela detalhada. +

+
+ +
+

Backends (referência)

+
from deepagents.backends import (
+    StateBackend, FilesystemBackend, LocalShellBackend,
+    StoreBackend, ContextHubBackend, CompositeBackend,
+)
+# Sandbox providers:
+from langchain_modal import ModalSandbox
+from langchain_daytona import DaytonaSandbox
+from langchain_runloop import RunloopSandbox
+from langchain_agentcore_codeinterpreter import AgentCoreSandbox
+# from deepagents.backends import LangSmithSandbox  # langsmith[sandbox]
+
StateBackend() +

Default. Per-thread. Sem persistência cross-thread sem checkpointer.

+
FilesystemBackend(root_dir, virtual_mode=True) +

Disco local sob root_dir. Em virtual_mode, paths internos ficam isolados.

+
LocalShellBackend(root_dir, timeout=120, max_output_bytes=100_000, env=None, inherit_env=True) +

FS local + execute via subprocess.run(shell=True). Não para produção.

+
StoreBackend(namespace=lambda rt: (...,)) +

Persistente cross-thread em BaseStore. Requer store= no create_deep_agent.

+
ContextHubBackend +

Repo do LangSmith Hub como FS. Writes commit-otimistas. Apenas UTF-8 texto via upload_files(). Requer LANGSMITH_API_KEY.

+
CompositeBackend(default, routes) +
+

default = backend fallback. routes = {prefix: backend}. Prefixos mais longos vencem; ls/glob/grep agregam entre backends.

+
+
+ +
+

BackendProtocol

+
from deepagents.backends.protocol import (
+    BackendProtocol, SandboxBackendProtocol, BACKEND_TYPES, BackendFactory,
+    FileInfo, FileData, GrepMatch,
+    LsResult, ReadResult, WriteResult, EditResult, GlobResult, GrepResult,
+    ExecuteResponse, FileUploadResponse, FileDownloadResponse,
+)
+

Métodos sync (com contraparte async a-prefixada)

+
+ + + + + + + + + + + + +
MétodoRetornoNotas
ls(path)LsResultLista; ls_info devolve FileInfo ricos
read(file_path, offset=0, limit=2000)ReadResultConteúdo + linhas
write(file_path, content)WriteResultApenas criação
edit(file_path, old_string, new_string, replace_all=False)EditResultSubstituição exata
glob(pattern, path="/")GlobResultglob_info devolve FileInfo
grep(pattern, path=None, glob=None)GrepResultgrep_raw devolve matches
upload_files(items: list[tuple[str, bytes]])FileUploadResponseBulk upload
download_files(paths)list[FileDownloadResponse]Bulk download
+
+

+ Para sandboxes, implemente também SandboxBackendProtocol com + execute(command) -> ExecuteResponse. BaseSandbox + provê FS ops em cima. +

+
+ +
+

FilesystemPermission

+
from deepagents import FilesystemPermission
+
+FilesystemPermission(
+    operations: list[Literal["read", "write"]],
+    paths: list[str],         # globs: ** e {a,b}
+    mode: Literal["allow", "deny"] = "allow",
+)
+

Veja o capítulo 10 para semântica completa.

+
+ +
+

HarnessProfile · ProviderProfile

+
from deepagents import (
+    HarnessProfile, HarnessProfileConfig, GeneralPurposeSubagentProfile,
+    register_harness_profile,
+    ProviderProfile, register_provider_profile,
+    get_provider_profile, apply_provider_profile,
+)
+

HarnessProfile

+
HarnessProfile(
+    base_system_prompt: str | None = None,
+    system_prompt_suffix: str | None = None,
+    tool_description_overrides: dict[str, str] | None = None,
+    excluded_tools: set[str] | None = None,
+    excluded_middleware: set[type | str] | None = None,
+    extra_middleware: list[AgentMiddleware] | None = None,
+    general_purpose_subagent: GeneralPurposeSubagentProfile | None = None,
+)
+

register_harness_profile

+
register_harness_profile(key: str, profile: HarnessProfile | HarnessProfileConfig | dict)
+

+ key = "openai" (provider) ou + "openai:gpt-5.5" (model). Re-registro faz merge aditivo. + Profiles built-in: _anthropic_opus_4_7, + _anthropic_sonnet_4_6, _anthropic_haiku_4_5, + _openai_codex. +

+

ProviderProfile

+
ProviderProfile(
+    init_kwargs: Mapping[str, Any] | None = None,
+    pre_init: Callable[[str], None] | None = None,            # side-effects pré-construção
+    init_kwargs_factory: Callable[[], dict[str, Any]] | None = None,  # kwargs derivados em runtime
+)
+
+register_provider_profile("openai", ProviderProfile(init_kwargs={"temperature": 0}))
+register_provider_profile("openai:gpt-5.5",
+                          ProviderProfile(init_kwargs={"reasoning_effort": "medium"}))
+

Aplica-se apenas quando o modelo é passado como string provider:model.

+
+ +
+

Imports recap

+
# Core
+from deepagents import (
+    create_deep_agent,
+    SubAgent, CompiledSubAgent, AsyncSubAgent,
+    FilesystemPermission,
+    HarnessProfile, HarnessProfileConfig, GeneralPurposeSubagentProfile,
+    register_harness_profile,
+    ProviderProfile, register_provider_profile,
+)
+# BASE_AGENT_PROMPT não é reexportado no topo de `deepagents`; vive em deepagents.graph:
+from deepagents.graph import BASE_AGENT_PROMPT
+
+# Backends
+from deepagents.backends import (
+    StateBackend, FilesystemBackend, LocalShellBackend,
+    StoreBackend, ContextHubBackend, CompositeBackend,
+)
+from deepagents.backends.protocol import (
+    BackendProtocol, SandboxBackendProtocol,
+    FileInfo, FileData, GrepMatch,
+    LsResult, ReadResult, WriteResult, EditResult, GlobResult, GrepResult,
+    ExecuteResponse, FileUploadResponse, FileDownloadResponse,
+)
+from deepagents.backends.utils import create_file_data
+
+# Middleware (custom)
+from deepagents.middleware.filesystem import (
+    FilesystemMiddleware, FilesystemState,
+    LsSchema, ReadFileSchema, WriteFileSchema, EditFileSchema,
+    GlobSchema, GrepSchema, ExecuteSchema,
+    FILESYSTEM_SYSTEM_PROMPT,
+)
+from deepagents.middleware.subagents import (
+    SubAgentMiddleware, TaskToolSchema, TASK_SYSTEM_PROMPT,
+)
+from deepagents.middleware.async_subagents import (
+    AsyncSubAgentMiddleware, AsyncSubAgentState,
+    StartAsyncTaskSchema, CheckAsyncTaskSchema, UpdateAsyncTaskSchema,
+    CancelAsyncTaskSchema, ListAsyncTasksSchema,
+)
+from deepagents.middleware.skills import (
+    SkillsMiddleware, SkillMetadata, SkillsState, SKILLS_SYSTEM_PROMPT,
+)
+from deepagents.middleware.memory import (
+    MemoryMiddleware, MemoryState, MEMORY_SYSTEM_PROMPT,
+)
+from deepagents.middleware.summarization import (
+    SummarizationToolMiddleware, create_summarization_middleware,
+    create_summarization_tool_middleware,
+    SummarizationEvent, SummarizationDefaults, compute_summarization_defaults,
+    SUMMARIZATION_SYSTEM_PROMPT,
+)
+from deepagents.middleware.patch_tool_calls import PatchToolCallsMiddleware
+# TodoListMiddleware é do LangChain (reexportado pelo base stack do Deep Agents):
+from langchain.agents.middleware import TodoListMiddleware
+
+# Code interpreter
+from langchain_quickjs import CodeInterpreterMiddleware
+
+# Sandbox providers
+from langchain_modal import ModalSandbox
+from langchain_daytona import DaytonaSandbox
+from langchain_runloop import RunloopSandbox
+
+# LangChain middleware reaproveitado em produção
+from langchain.agents.middleware import (
+    ModelCallLimitMiddleware, ToolCallLimitMiddleware,
+    ModelRetryMiddleware, ModelFallbackMiddleware, ToolRetryMiddleware,
+    PIIMiddleware,
+)
+
+ +
+

Parte C — Receituário oficial

+

Esta parte reúne o material das três pastas oficiais de exemplos do Deep Agents (examples/, deploy/, cookbook/) condensado em receitas reutilizáveis, fact-checks pontuais e a tabela de evaluation completa.

+
+ +
+

26. CLI deepagents & deepagents.toml

+
+ Duas ferramentas distintas — não confundir: + (a) dcode (Deep Agents Code) é o coding agent interativo + instalado por script (detalhado no capítulo 24 — aqui + só referenciado); (b) deepagents / deepagents-cli é + a CLI de deploy (Beta), um pacote PyPI separado que + mira a LangGraph Platform. O deepagents.toml é o config da CLI de + deploy. +
+ +

26.1 CLI de deploy deepagents (Beta)

+
# Instalação (pacote separado do SDK core)
+pip install deepagents-cli          # extras: [anthropic], [openai], [ollama], [all-providers]
+# ou: uv tool install deepagents-cli --with deepagents-cli[openai]
+
+# Comandos de deploy (Beta)
+deepagents init <NAME>    # scaffold de um projeto de deploy
+deepagents dev           # dev server local lendo deepagents.toml
+deepagents deploy        # bundle + deploy para a LangGraph Platform (LangSmith Deployment)
+
+ Os subcomandos documentados são apenas init / dev / + deploy; não há flag --config publicada na + referência da CLI. O deepagents.toml é descoberto por + convenção na raiz do projeto. Não confundir com + ~/.deepagents/config.toml, que é a config global da CLI interativa + dcode (com flags próprias como --model, --agent, + --profile-override). +
+ +

26.2 deepagents.toml — schema real (classe DeployConfig)

+

Seções confirmadas: [agent], [sandbox], [memories], [auth], [frontend]. O formato do model é provider:model e o provider: determina o pacote langchain-* necessário.

+
[agent]
+name = "my-agent"
+model = "anthropic:claude-sonnet-4-6"   # formato provider:model
+
+[sandbox]
+provider = "daytona"                     # mapeia para langchain-daytona
+template = "..."                         # snapshot LangSmith
+scope = "thread"                         # "thread" | "assistant"
+
+[memories]
+backend = "store"                        # "hub" | "store"
+
+[auth]
+provider = "supabase"                    # "supabase" | "clerk" | "anonymous"
+
+[frontend]
+# config opcional de frontend
+ +

26.3 Layout do projeto por convenção

+

O bundle de deploy descobre arquivos por convenção a partir da raiz:

+
deepagents.toml              # config principal (DeployConfig)
+AGENTS.md                    # system prompt do agente
+.env                         # chaves: ANTHROPIC_API_KEY, LANGSMITH_API_KEY, ...
+mcp.json                     # opcional → adiciona langchain-mcp-adapters
+                             #   (apenas HTTP/SSE; stdio é rejeitado no bundle)
+skills/<name>/SKILL.md        # skills (progressive disclosure)
+subagents/<name>/
+    deepagents.toml          # config do subagent
+    AGENTS.md                # system prompt do subagent
+user/AGENTS.md               # memória de usuário
+
+ O deploy mira a LangGraph Platform (LangSmith Deployment). + [sandbox].provider mapeia para o pacote partner correspondente + (daytona → langchain-daytona); o + provider: do model mapeia para o pacote do provedor + (google_genai → langchain-google-genai). +
+ +
+ +
+

27. Arquitetura async-deep-agents

+

O exemplo oficial async-subagent-server demonstra a arquitetura recomendada para subagents que precisam rodar em background assíncrono, sobreviver à reconexão e reportar conclusão por canal lateral.

+ +

Conceitualmente, é um supervisor síncrono que declara um ou mais AsyncSubAgent e os dispara como runs de background em graphs separados (próprios ou remotos), com um notifier opcional para reportar conclusão por canal lateral:

+ +
┌──────────────────────────────────────────────────────────────┐
+│  Graph 1: Supervisor (síncrono, com create_deep_agent)       │
+│    • Pega input do usuário                                   │
+│    • Declara AsyncSubAgent(...) → 5 tools auto-injetadas     │
+│    • start_async_task → launch de run no graph_id alvo       │
+│      (transporte ASGI co-deployed ou HTTP via url)           │
+└──────────────────────────────────────────────────────────────┘
+        │ spawn researcher
+        ▼
+┌──────────────────────────────────────────────────────────────┐
+│  Graph 2: Researcher (próprio deep agent ou react agent)     │
+│    • Roda em thread/run independente                         │
+│    • Quando termina, escreve resultado em Store              │
+│      ou aciona Graph 3 via webhook/notifier                  │
+└──────────────────────────────────────────────────────────────┘
+        │ ou
+        ▼
+┌──────────────────────────────────────────────────────────────┐
+│  Graph 3: Coder (próprio deep agent com sandbox)             │
+│    • Mesma semântica do researcher                           │
+└──────────────────────────────────────────────────────────────┘
+        │ on completion
+        ▼
+┌──────────────────────────────────────────────────────────────┐
+│  Notifier (opcional)                                         │
+│    • Recebe webhook do run terminal                          │
+│    • Chama Slack/email/WS para acordar UI                    │
+└──────────────────────────────────────────────────────────────┘
+ +

27.1 Declaração tipada via AsyncSubAgent

+
+ O subagent async é declarado com o objeto tipado + AsyncSubAgent(...), não com um dict + {"async": True}. Não existem os parâmetros + platform_client= nem on_complete_webhook=: o + AsyncSubAgentMiddleware é uma camada interna adicionada + automaticamente quando há um AsyncSubAgent em + subagents=. Requer deepagents >= 0.5.0. +
+
from deepagents import AsyncSubAgent, create_deep_agent
+
+async_subagents = [
+    AsyncSubAgent(
+        name="researcher",
+        description="Research agent for information gathering and synthesis",
+        graph_id="researcher",
+        # sem url → transporte ASGI (co-deployed no mesmo deployment)
+    ),
+    AsyncSubAgent(
+        name="coder",
+        description="Coding agent for code generation and review",
+        graph_id="coder",
+        url="https://coder-deployment.langsmith.dev",  # opcional → transporte HTTP (remoto)
+        headers={"Authorization": "Bearer ..."},         # opcional
+    ),
+]
+
+supervisor = create_deep_agent(
+    model="google_genai:gemini-3.5-flash",
+    subagents=async_subagents,
+    system_prompt="You orchestrate a research team. Use the researcher liberally.",
+)
+

+ Parâmetros reais de AsyncSubAgent: name (obrig.), + description (obrig.), graph_id (obrig.), + url (opc. — sem ele, transporte ASGI co-deployed; com ele, + HTTP remoto) e headers (opc.). +

+ +

27.2 Tools auto-injetadas e canal de estado

+

+ Cinco tools supervisoras são injetadas automaticamente pelo + AsyncSubAgentMiddleware: + start_async_task, check_async_task, + update_async_task, cancel_async_task e + list_async_tasks. Os metadados das tasks vivem em um canal + dedicado do estado chamado async_tasks, que sobrevive à + compactação de histórico. Localmente, controle a concorrência com + langgraph dev --n-jobs-per-worker 10 (um slot para o supervisor + + os concorrentes). +

+
+ Dica de prompt: "After launching an async subagent, + ALWAYS return control to the user. Never call check_async_task immediately + after launch." — evita polling parasita. O notifier (webhook → Slack/ + e-mail/WS) é construído como deployment separado consumindo os webhooks do + Agent Server; não é um parâmetro do create_deep_agent. +
+ +
+ +
+

28. Integração com MCP (Model Context Protocol)

+

Deep Agents consome servidores MCP através do adapter langchain-mcp-adapters. As ferramentas MCP entram em tools=[...] do create_deep_agent exatamente como qualquer outra BaseTool.

+ +

28.1 Consumir servidores MCP — MultiServerMCPClient

+

+ A classe é MultiServerMCPClient do módulo + langchain_mcp_adapters.client. As tools são carregadas com + await client.get_tools() e passadas a + create_deep_agent(tools=...) como qualquer outra + BaseTool. Cada servidor declara um transport + ("stdio" local ou "http" remoto). +

+
from langchain_mcp_adapters.client import MultiServerMCPClient
+from deepagents import create_deep_agent
+
+client = MultiServerMCPClient(
+    {
+        "math": {
+            "transport": "stdio",
+            "command": "python",
+            "args": ["/path/to/math_server.py"],
+        },
+        "weather": {
+            "transport": "http",
+            "url": "http://localhost:8000/mcp",
+        },
+    }
+)
+
+tools = await client.get_tools()          # carrega todas as tools dos servidores
+agent = create_deep_agent(
+    model="claude-sonnet-4-6",
+    tools=tools,                          # mistura com built-ins via FilesystemMiddleware
+    system_prompt="You help users automate tasks across our stack.",
+)
+await agent.ainvoke({"messages": [{"role": "user", "content": "What is 2 + 2?"}]})
+ +

Recursos, prompts e sessão explícita

+

+ Além das tools, o cliente expõe resources e prompts MCP. + Para controle fino, abra uma sessão por servidor e use as funções standalone + load_mcp_tools, load_mcp_resources e + load_mcp_prompt. +

+
# Atalhos no cliente (assinaturas reais)
+resources = await client.get_resources("server_name", uris=[...])
+prompt    = await client.get_prompt("server_name", "prompt_name", arguments={...})
+
+# Via sessão explícita + funções standalone
+from langchain_mcp_adapters.tools import load_mcp_tools
+from langchain_mcp_adapters.resources import load_mcp_resources
+from langchain_mcp_adapters.prompts import load_mcp_prompt
+
+async with client.session("server_name") as session:
+    tools     = await load_mcp_tools(session)
+    resources = await load_mcp_resources(session, uris=[...])
+    prompt    = await load_mcp_prompt(session, "name", arguments={...})
+
+ Símbolos confirmados no pacote: MultiServerMCPClient, + load_mcp_tools, load_mcp_resources, + load_mcp_prompt, MCPToolCallRequest. O exemplo + oficial usa create_agent, mas as tools entram em + create_deep_agent(tools=...) da mesma forma. +
+ +

28.2 Servir um deep agent como servidor MCP

+
+ Não existe função langchain_to_mcp_server(...) + no langchain_mcp_adapters nem no SDK deepagents para + "transformar um agente em servidor MCP". Expor um deep agent por MCP é um + recurso de deployment, não de biblioteca. +
+

+ Um LangSmith Deployment tradicional pode expor seu agente + via MCP ou A2A "out of the box". Citação oficial: + "A traditional LangSmith Deployment ... can expose your agent via MCP or + A2A." A configuração é feita nos endpoints do deployment + (/langsmith/server-mcp para MCP, + /langsmith/server-a2a para A2A — veja a seção de A2A abaixo). + Não há snippet de SDK porque o transporte é provido pelo Agent Server. +

+ + +

28.3 A2A — Agent-to-Agent Protocol

+

+ Enquanto o MCP conecta o agente a tools, o A2A + expõe o próprio deep agent para que outros agentes o consumam. Um + Agent Server publica o endpoint /a2a/{assistant_id} e um + agent card em + /.well-known/agent-card.json?assistant_id={assistant_id}. + Métodos JSON-RPC suportados: message/send, + message/stream e tasks/get. +

+

+ O A2A vem habilitado por padrão; para desligá-lo, adicione + disable_a2a ao bloco http do + langgraph.json: +

+
{
+  "$schema": "https://langgra.ph/schema.json",
+  "http": {
+    "disable_a2a": true
+  }
+}
+
+ Dependência mínima: langgraph-api >= 0.4.21. + O contextId do A2A mapeia para o thread_id do + LangGraph; esse thread_id viaja no metadata de + nível superior do JSON-RPC (não dentro de + params). Para compatibilidade de text-part, o estado do + agente DEVE conter a chave messages. +
+ +
+ +
+

29. Tabela completa de evaluation

+

Catálogo de capacidades testadas oficialmente. Cada coluna marca o sinal medido em harness; um agent SOTA cobre todas.

+
+ + + + + + + + + + + + + + + + + + +
CapacidadeBuilt-inSubagentSandboxSkillsMemorySinal
Planejamento (write_todos)✓————Plan-update ratio
Pesquisa profunda (multi-source)✓✓——✓Recall@k, fontes citadas
Síntese / draft✓✓———BLEU/Rouge ou rubrics
Code editing (apply diff)✓✓✓——Patch pass-rate
Execução de código—✓✓——Exit code 0, output diff
SQL / NL2SQL—✓—✓✓Execution-match
Multi-step tool use✓✓———Trajectory-eval
HITL (interrupt/resume)✓————Resume-correctness
Skills loading (lazy)———✓—Skill-hit-rate
Async subagent (background)—✓———Completion under SLO
Long context (>100k tokens)✓———✓Needle-in-haystack
Cross-thread memory————✓Recall após restart
Permissões / FS guardrails✓————Bloqueia escrita proibida
+
+ +
+

R1. Receita · Deep research

+

Origem: examples/deep_research. Padrão clássico: 1 supervisor + 3 researchers paralelos + revisor crítico.

+
from deepagents import create_deep_agent
+from langchain_community.tools.tavily_search import TavilySearchResults
+
+search = TavilySearchResults(max_results=8, search_depth="advanced")
+
+research_subagent = {
+    "name": "research-agent",
+    "description": "Pesquisa um sub-tópico em profundidade e devolve relatório com fontes.",
+    "system_prompt": (
+        "Você é um pesquisador. Dado um sub-tópico, faça 5+ buscas, "
+        "leia as fontes, anote URLs e devolva um relatório de 3-5 parágrafos."
+    ),
+    "tools": [search],   # objetos de tool reais (Sequence[BaseTool | callable | dict])
+}
+
+critique_subagent = {
+    "name": "critique-agent",
+    "description": "Revisa o relatório final e aponta lacunas.",
+    "system_prompt": "Você é editor sênior. Aponte fatos não-citados, viés e lacunas.",
+}
+
+agent = create_deep_agent(
+    model="anthropic:claude-opus-4-8",
+    tools=[search],
+    subagents=[research_subagent, critique_subagent],
+    system_prompt=(
+        "Você produz relatórios extensos com citações.\n"
+        "1) Crie um plano com write_todos.\n"
+        "2) Para cada sub-tópico, dispare research-agent.\n"
+        "3) Sintetize um draft, peça critique-agent, revise, entregue."
+    ),
+)
+result = agent.invoke({"messages":[{"role":"user","content":"Mercado de robotaxis em 2026"}]})
+
+ +
+

R2. Receita · Coding agent com sandbox

+

Origem: deploy-coding-agent. Filesystem real em sandbox Modal + execução de testes.

+
from deepagents import create_deep_agent
+from langchain_modal import ModalSandbox
+
+sandbox = ModalSandbox(workspace="my-org")
+
+try:
+    agent = create_deep_agent(
+        model="anthropic:claude-opus-4-8",
+        backend=sandbox.backend(),
+        system_prompt=(
+            "Você é um engenheiro de software. Use o sistema de arquivos para ler/editar "
+            "código e o comando execute para rodar testes. Sempre rode os testes "
+            "depois de qualquer mudança."
+        ),
+        tools=[],   # FS + execute vêm do backend
+    )
+    result = agent.invoke({"messages":[{"role":"user",
+        "content":"Corrija o bug em src/parser.py e adicione um teste em tests/test_parser.py"}]})
+finally:
+    sandbox.terminate()
+
+ +
+

R3. Receita · Content writer com subagent por canal

+

Origem: deploy-content-writer. Um subagent por destino (LinkedIn, Twitter, blog) com prompt e tom específicos.

+
from deepagents import create_deep_agent
+
+linkedin = {
+    "name": "linkedin-writer",
+    "description": "Escreve posts longos para LinkedIn com formato 'hook → body → CTA'.",
+    "system_prompt": "Você é especialista em LinkedIn. Tom profissional, posts de 200-400 palavras.",
+}
+twitter = {
+    "name": "twitter-writer",
+    "description": "Escreve threads de 6-10 tweets, cada um < 280 chars.",
+    "system_prompt": "Você escreve threads. Tweet 1 é o hook. Cada tweet conclui um ponto.",
+}
+blog = {
+    "name": "blog-writer",
+    "description": "Escreve posts de blog 1500-2500 palavras com H2/H3/lista.",
+    "system_prompt": "Você escreve blog posts longos e estruturados com SEO em mente.",
+}
+
+agent = create_deep_agent(
+    model="anthropic:claude-opus-4-8",
+    subagents=[linkedin, twitter, blog],
+    system_prompt=(
+        "Dado um tópico e canais alvo, dispare o subagent apropriado para CADA canal. "
+        "Rode em paralelo quando possível. Devolva todos os outputs."
+    ),
+)
+
+ Variante content-builder-agent: o exemplo + oficial de content-builder acrescenta uma tool de geração de imagem + (generate_image usando o modelo de imagem atual + gemini-3.1-flash-image — o tutorial oficial original usa + gemini-2.5-flash-image) + que salva a arte gerada no filesystem virtual (ex.: + blogs/<slug>/hero.png), de forma que cada post acompanha sua + imagem de capa produzida pelo próprio agente. +
+
+ +
+

R4. Receita · Text-to-SQL com skills

+

Origem: text-to-sql-agent. Skill carrega contexto de schema/SQL sob demanda.

+
from deepagents import create_deep_agent
+from deepagents.backends import FilesystemBackend
+from deepagents.middleware.skills import SkillsMiddleware
+
+# skills/postgres-tpch/SKILL.md ; skills/dbt-conventions/SKILL.md ; skills/sql-style/SKILL.md
+backend = FilesystemBackend(root_dir="/abs/path/to/workspace", virtual_mode=True)
+
+agent = create_deep_agent(
+    model="anthropic:claude-opus-4-8",
+    middleware=[SkillsMiddleware(backend=backend, sources=["/skills/"])],
+    tools=[run_sql, describe_table],
+    system_prompt=(
+        "Você responde perguntas dos analistas em SQL.\n"
+        "Antes de escrever uma query, carregue a skill 'postgres-tpch' para o schema "
+        "e 'sql-style' para as convenções de naming."
+    ),
+)
+
+ +
+

R5. Receita · Ralph mode (loop)

+

Origem: examples/ralph_mode. O agent fica em loop persistente, lê fila de tarefas, executa cada uma e marca como done — pattern de "agente residente".

+
from deepagents import create_deep_agent
+from time import sleep
+
+agent = create_deep_agent(
+    model="anthropic:claude-opus-4-8",
+    tools=[fetch_next_task, mark_done, notify_slack],
+    system_prompt=(
+        "Você é Ralph. Faça um loop:\n"
+        "1) chame fetch_next_task; se vazio, espere.\n"
+        "2) execute a tarefa.\n"
+        "3) chame mark_done(task_id) e, em falha, notify_slack(reason).\n"
+        "4) Repita indefinidamente."
+    ),
+)
+
+state = {"messages": [{"role":"user","content":"start"}]}
+while True:
+    state = agent.invoke(state)
+    if state.get("done"): break
+    sleep(1)
+
+ +
+

R6. Receita · REPL swarm com skill TypeScript

+

Origem: examples/repl_swarm. Vários sub-agents que compartilham um REPL via skill TS.

+
from deepagents import create_deep_agent
+from deepagents.backends import FilesystemBackend
+from langchain_quickjs import CodeInterpreterMiddleware
+from deepagents.middleware.skills import SkillsMiddleware
+
+backend = FilesystemBackend(root_dir="/abs/path/to/workspace", virtual_mode=True)
+
+agent = create_deep_agent(
+    model="anthropic:claude-opus-4-8",
+    middleware=[
+        CodeInterpreterMiddleware(skills_backend=backend),        # JS/TS sandbox embutido (QuickJS)
+        SkillsMiddleware(backend=backend, sources=["/skills/"]),  # skills/ts-utils/SKILL.md, skills/data-viz/SKILL.md
+    ],
+    subagents=[
+        {"name":"data","description":"Carrega/limpa dados.","system_prompt":"Use skill ts-utils."},
+        {"name":"viz","description":"Plota gráficos.","system_prompt":"Use skill data-viz."},
+        {"name":"writer","description":"Escreve insights.","system_prompt":"Sintetize achados."},
+    ],
+    system_prompt="Você é um swarm de analistas em REPL. Cada subagent reusa o mesmo CodeInterpreter.",
+)
+
+ +
+

30. Catálogo dos 15 exemplos oficiais

+

Lista verificada em 2026-06-10 em github.com/langchain-ai/deepagents/examples. Cada entrada inclui o que demonstra e qual receita acima cobre.

+
+ + + + + + + + + + + + + + + + + + +
ExemploO que demonstraReceita
deep_researchSupervisor + N researchers + criticR1
deploy-mcp-docs-agentMCP filesystem + docs agent deployado§28
deploy-coding-agentCoding agent com sandbox ModalR2
nvidia_deep_agentPipeline pesquisa-mercado sobre press releasesR1
content-builder-agentSubagents por tipo de conteúdoR3
text-to-sql-agentSkills para schema + SQL styleR4
llm-wikiWiki automaticamente construído por researchersR1
deploy-content-writerWriter multi-canal deployadoR3
deploy-gtm-agentGo-to-market analyst com web toolsR1
async-subagent-serverArquitetura async-deep-agents§27
ralph_modeAgente residente em loopR5
rlm_agentReasoning-as-LLM (long-horizon)§27
repl_swarmSwarm com QuickJS + TS skillsR6
downloading_agentsAgent que baixa/cataloga assets externosR2
better-harnessHarness próprio que substitui o default—
+
+ Como navegar. Cada pasta de exemplo tem README.md, agent.py e (quando é deployavel) langgraph.json. Clone o repo: git clone https://github.com/langchain-ai/deepagents.git && cd deepagents/examples. +
+
+ +
+
+ + + + + diff --git a/references/agents_tools_best_guides/guia_estado_contexto_memoria.html b/references/agents_tools_best_guides/guia_estado_contexto_memoria.html new file mode 100644 index 0000000..8a9bbd7 --- /dev/null +++ b/references/agents_tools_best_guides/guia_estado_contexto_memoria.html @@ -0,0 +1,1640 @@ + + + + + +Estado, Contexto & Memória — Núcleo agnóstico de agentes + + + + + + + + +
+
+
Estado, Contexto & Memória Núcleo agnóstico de agentes
+
+ Verificado em 2026-06-11 + Núcleo · agnóstico de provider + Conceitual + referência + +
+
+
+ +
+ + +
+ +
+

Estado, Contexto & Memória

+

+ O capítulo que decide quem é dono do histórico. A regra que atravessa todo o + núcleo: o estado real pertence ao runtime da aplicação; os mecanismos de estado dos providers — + previous_response_id, conversation, sessions, cache, thinking blocks, + thought signatures — são carriers e projeções, não a base de auditoria. Aqui + você modela o ledger canônico, preserva reasoning/thinking sem expô-los, projeta para cada + provider e compacta sem perder o que importa. +

+
+ Núcleo · agnóstico de provider + Conceitual + referência + SOTA · verificado 2026-06-10 +
+
+ +
+

Sobre este guia

+

+ Este é um guia para IA e humanos: combina o modelo conceitual de estado com + contratos tipados prontos para copiar (ledger, asset registry, compaction item) e tabelas de + decisão por provider. A prosa é em PT-BR; nomes de campos, parâmetros e código permanecem em + inglês, como nas APIs oficiais. +

+
+ Tese deste capítulo: separe estado durável, projeção para + provider e execução de capabilities. O runtime possui um ledger tipado; a payload + enviada ao modelo é sempre uma projeção reconstruída desse ledger — nunca a fonte única da + verdade. Esse princípio nasce no + blueprint SOTA do capítulo de + arquitetura e aqui ganha estrutura de dados. +
+
+ Fronteira de escopo (cross-link, sem duplicar): a estratégia detalhada + de compactação (escada de compactação, teto X, snapshots cumulativos) vive em + Contexto & compactação — estratégias; + a contagem de tokens por provider (tokenizadores, count_tokens, custos de + imagem) vive em Token counting. Aqui tratamos do + contrato de estado e de compaction — o invariante que aquelas estratégias devem + respeitar. +
+
+ +
+

Fontes & verificação

+

+ Os fatos perecíveis (parâmetros de estado, modos de reasoning/thinking, campos de retenção) foram + conferidos contra a documentação oficial em 2026-06-10 e consolidados na folha de + fatos SOTA do projeto. Os contratos de dados (ledger, compaction item, asset registry) são + recomendações de engenharia derivadas dos padrões oficiais. +

+
+ + + + + + + + + +
TemaFonte oficial
OpenAI — estado de conversa (previous_response_id, conversation, store)developers.openai.com/api/docs/guides/conversation-state
OpenAI — reasoning (effort, encrypted reasoning, stateless/ZDR)developers.openai.com/api/docs/guides/reasoning
Anthropic — extended/adaptive thinking (blocks & signatures)platform.claude.com/docs/en/build-with-claude/extended-thinking
Anthropic — context windowsplatform.claude.com/docs/en/build-with-claude/context-windows
Google — thinking (thinking_level, thought summaries)ai.google.dev/gemini-api/docs/thinking
Google — thought signaturesai.google.dev/gemini-api/docs/thought-signatures
+

+ Legenda dos selos: Verificado confirmado na doc oficial · + Novo recurso recente · + UNVERIFIED não confirmado dentro do orçamento de verificação · + N/D não documentado. +

+
+ +
+

Mapa do núcleo — onde cada assunto mora

+
+ + + + + + + + + + +
Você procura…Vá para
Primitivos, capability registry, active plan, skeleton de loopNúcleo · Arquitetura & orquestração
Tool result envelopes, MCP, RAG, leitura de PDF/imagem/planilhaNúcleo · Ferramentas, MCP & RAG
Parâmetros de provider, adapters, provider-switchingNúcleo · Providers & adapters
Retenção/ZDR, tracing, evals, runbooks, threat modelNúcleo · Operação, segurança & evals
Escada de compactação, teto X, snapshots cumulativos (estratégia)Contexto & compactação — estratégias
Contagem de tokens, tokenizadores, custos por providerToken counting
Reasoning/thinking em profundidade por providerOpenAI · Claude API · Gemini Interactions API
+
+ + +
+

Parte 1 — Modelo de estado

+

Quem é dono do histórico, como ele é estruturado, o ciclo de ingestão e os três modos de gerir + estado entre a aplicação e o provider.

+
+ +
+

1. Estado durável versus payload de provider

+

+ A regra mais importante: o histórico real pertence ao runtime da aplicação. APIs e SDKs oferecem + conveniências de estado — previous_response_id, conversation, sessions, + cache, thought signatures ou thinking blocks — mas esses mecanismos são carriers / + projeções, não a base de auditoria. Tratar o estado do provider como fonte única é o + antipadrão "provider como banco de estado" descrito no + capítulo de arquitetura. +

+
+ + + + + + + +
Mecanismo do providerO que éPor que não é a fonte da verdade
OpenAI previous_response_id / conversationEncadeamento de estado server-side entre respostas.Sujeito a retenção/expiração; instructions antigas não são recarregadas automaticamente.
Anthropic message historyVocê reenvia as mensagens; thinking blocks/signatures viajam junto.É o seu payload — só é durável se você o persistir.
Google chat/history no SDKO SDK pode manter o histórico da sessão de chat.Conveniência de processo; precisa ser persistida pela aplicação.
Prompt cache (qualquer provider)Acelera prefixos repetidos.Otimização de custo/latência com TTL — não é armazenamento.
+
+ Para fluxos protegidos: quando requisitos de retenção/privacidade exigem controle + estrito, prefira store=false quando aplicável e carregue você mesmo os itens + necessários de reasoning/tool/replay, usando encrypted reasoning ou carriers equivalentes quando + suportados. As decisões de retenção/ZDR têm tratamento próprio em + Operação, segurança & evals. +
+ +
+ +
+

2. Ledger canônico

+

+ O ledger canônico deve preservar itens em vez de achatar tudo para texto. Ele + precisa distinguir usuário, sistema, developer/instructions, output do modelo, tool call, tool + result, asset, citação de RAG, carrier de reasoning, signature de thinking, summary de compaction, + approval e usage. Essa granularidade é o que permite reidratar para qualquer provider sem perder + informação essencial e sem transformar reasoning/thinking privado em texto comum. +

+
{
+  "conversation_id": "uuid",
+  "ledger_version": 3,
+  "items": [
+    {"type": "instruction", "scope": "system", "text_ref": "..."},
+    {"type": "message", "role": "user", "content": [{"type": "text", "text": "..."}]},
+    {"type": "provider_reasoning_carrier", "provider": "openai", "encrypted_content": "..."},
+    {"type": "tool_call", "tool_call_id": "call_1", "capability_id": "retrieve.v1", "args_hash": "..."},
+    {"type": "tool_result", "tool_call_id": "call_1", "reduced_output_ref": "artifact://..."},
+    {"type": "asset", "asset_id": "file_1", "sha256": "...", "classification": "sensitive"},
+    {"type": "usage", "input_tokens": 1234, "output_tokens": 567, "reasoning_tokens": 200}
+  ],
+  "indexes": {"by_asset": {}, "by_tool_call": {}, "by_provider_item": {}}
+}
+
+ Por que itens e não texto: um tool_call achatado para texto perde o + tool_call_id que o provider exige para parear o resultado; um thinking block achatado + perde a signature que o provider valida no próximo turno. O ledger guarda a estrutura; o adapter + decide o formato de cada provider na projeção (§8). +
+
+ +
+

3. Ciclo correto: registrar, reduzir, projetar

+

+ Não projete direto da interface do usuário para o provider. Primeiro normalize, classifique e + registre. Não injete tool result bruto: primeiro reduza, atribua provenance, aplique caps e + registre. Não faça compaction como resumo genérico: preserve decisões, fatos, links, hashes, + carriers e pendências. +

+
+ + Ciclo registrar, reduzir, projetar + Entrada bruta passa por validação de ingresso e vai ao ledger; depois redaction/classificação; seleção de itens; compaction/rehydration; projeção por provider; chamada de modelo; e ingestão de items, usage, tool calls e reasoning carriers de volta ao ledger. + + + entrada bruta + validação de ingresso + ledger + redaction / classificação + seleção de itens + compaction / rehydration + projeção por provider + chamada de modelo + + + + + + + + + ingestão: items · usage · tool calls · reasoning carriers + +
O loop nunca vai da UI direto para o provider. Tudo passa pelo ledger, é reduzido e + classificado, e só então é projetado. A resposta volta como ingestão estruturada — fechando o + ciclo de auditoria.
+
+
+ +
+

4. Modos de estado: provider-managed, app-managed e híbrido

+

Três modos, com trade-offs explícitos. O baseline conceitual recomendado é app-managed; os + mecanismos provider-managed entram como otimização controlada.

+
+ + + + + + +
ModoVantagemRiscoUso recomendado
Provider-managedMenos payload manual e conveniência de continuidade.Retenção, billing, perda de controle e menor portabilidade.Fluxos de baixo risco ou protótipos, com política explícita.
App-managed (stateless)Controle máximo de retenção, replay e provider switch.Mais engenharia: carregar itens, carriers e budgets.Fluxos sensíveis, auditáveis ou multi-provider.
HíbridoCombina conveniência local com ledger próprio.Divergência entre estados se não houver ingestão rigorosa.Produção comum, desde que o provider state nunca seja a fonte única.
+
+ Regra do híbrido: use o estado do provider como cache/conveniência, mas escreva + cada resposta de volta no ledger por ingestão estruturada. Se o estado do provider expirar ou + divergir, o ledger continua sendo a verdade — e a próxima projeção o reconstrói. +
+
+ + +
+

Parte 2 — Reasoning, assets & projeção

+

O que cada provider expõe de reasoning/thinking e como preservá-lo; como tratar arquivos como + estado de primeira classe; e como projetar o ledger para cada API.

+
+ +
+

5. Regras por provider para reasoning/thinking

+

+ Cada provider expõe o raciocínio interno de forma diferente, e a regra universal é a mesma: + preserve o carrier oficial quando ele for exigido em turnos subsequentes, e + nunca converta reasoning/thinking privado em mensagem comum nem peça a cadeia de + pensamento bruta. A profundidade de cada modo (por modelo) está nos guias de provider; aqui está o + contrato de estado. +

+
+ + + + + + + + + + + + + + + + + + + + + +
ProviderCarrier internoO que preservarO que não fazer
OpenAI ResponsesReasoning items, summaries opcionais e encrypted reasoning quando incluído.Itens de output relevantes, tool calls/results, encrypted_content para fluxos stateless/store=false, usage e reasoning summaries quando solicitados.Não pedir nem inventar chain-of-thought; não converter reasoning item em mensagem comum; não assumir que instructions anteriores são carregadas com previous_response_id.
Anthropic MessagesThinking blocks e signatures em adaptive/extended thinking + tool use.Thinking blocks exigidos junto dos tool_result correspondentes, signatures, tool_use IDs e a ordem dos blocos.Não remover thinking/signature necessário em tool loop; não esquecer que o thinking budget compete com max_tokens em modelos/documentação aplicáveis.
Google GeminiThought signatures em parts e thoughts_token_count/summaries quando habilitados.parts com thought_signature exatamente como recebidas; histórico completo quando o SDK não o faz automaticamente; function responses pareadas.Não concatenar signatures em texto; não reordenar parts; não omitir signatures em chamadas subsequentes de function calling quando exigido.
+

Controles de reasoning/thinking — parâmetros canônicos

+

Os controles abaixo são os nomes de parâmetro atuais (não modelos). Para a + disponibilidade por modelo, siga os cross-links — IDs de modelo são perecíveis e ficam concentrados + nos guias de provider.

+
+ + + + + + +
ProviderParâmetroValoresNotas de estado
OpenAIreasoning.effortnone · low · medium (default) · high · xhigh (dependente do modelo)Reasoning tokens contam no orçamento; reasoning não é exposto como cadeia bruta. Verificado
Anthropicthinkingadaptive · enabled + budget_tokens · disabled (disponibilidade do modo varia por modelo)Thinking blocks/signatures devem voltar no tool loop; display pode ser summarized (default) ou omitted. Verificado
Googlethinking_levellow · medium · high (Flash/Flash-Lite também minimal)Direto em generation_config na Interactions API; aninhado em thinking_config no generateContent/SDK. thinking_budget é legado (série 2.5); não misturar com thinking_level (erro 400). Verificado
+
+ Onde aprofundar: adaptive/extended thinking, budget e display no + guia do Claude; reasoning.effort e verbosity no + guia da OpenAI; thinking_level, thought + summaries e telemetria usage.total_thought_tokens/total_output_tokens no + guia da Gemini Interactions API + (no generateContent, os mesmos contadores aparecem como usage_metadata.thoughts_token_count/candidates_token_count). +
+ +
+ +
+

6. Estado suportado pela OpenAI Responses API

+

+ Na Responses API, previous_response_id encadeia respostas anteriores e + conversation referencia um objeto de conversa; a documentação explicita que os dois + mecanismos não devem ser usados juntos em certas condições e que instructions de + chamadas anteriores não são automaticamente carregadas com + previous_response_id. A política correta é registrar a sua própria versão de + instructions e reprojetá-las quando necessário. +

+
# Padrão stateless com store=false e reasoning encrypted quando o caso exige
+# retenção controlada. Note model="..." — IDs de modelo ficam nos guias de provider.
+response = client.responses.create(
+    model="...",
+    input=projected_items,                       # projeção do ledger, não a UI crua
+    instructions=current_instructions,           # reprojetadas a cada turno
+    tools=allowed_tools,                          # só as tools permitidas da fase
+    store=False,                                  # nada retido no provider
+    include=["reasoning.encrypted_content"],      # carrier de reasoning p/ próximo turno
+    max_output_tokens=output_budget,             # reserve tokens p/ reasoning + final
+)
+ledger.ingest(response.output, usage=response.usage)
+
+ Cuidado com truncation: a truncation automática do provider pode + remover contexto crítico sem aviso. Prefira controlar a seleção de itens no seu lado (seleção + + compaction) a delegar o corte ao provider. Os parâmetros completos da Responses API estão no + capítulo de providers. +
+ +
+ +
+

7. Asset registry detalhado

+

+ Assets são parte do estado, não anexos soltos. Cada arquivo, imagem, planilha, PDF, resultado de + parser ou artefato gerado deve ter identidade e política. Isso evita que arquivos virem "texto + mágico" sem origem e torna a citação verificável. +

+
+ + + + + + + + + +
CampoMotivo
asset_id, sha256, size_bytesIntegridade, deduplicação e replay.
mime_type, parser_version, extraction_methodReprodutibilidade da leitura.
classification, tenant_id, retention_policyPrivacidade e fronteira de autorização.
source_uri/origin, upload_actorAuditoria e cadeia de custódia.
provenance spans: página, range, bbox, sheetCitação verificável e reidratação precisa.
projection_policyDefine se o asset pode ir ao modelo, ao RAG, à tool ou só ficar interno.
+
+ Cross-link: como extrair texto/estrutura de PDFs, imagens e planilhas (e como + reidratar imagens antigas via visual RAG) é tratado em + Multimodal. Aqui o asset é apenas uma entrada tipada do + ledger com provenance e política de projeção; o consumo como evidência de RAG está em + Ferramentas, MCP & RAG. +
+
+ +
+

8. Projeções por provider

+

+ O adapter converte o ledger canônico para o formato de cada API. Cada linha é um elemento + canônico; cada coluna mostra como ele aparece em cada provider. O adapter deve ser + explícito sobre perdas: trocar de provider pode perder carriers, roles, + built-ins, semântica de token budget, suporte multimodal ou paralelismo. +

+
+ + + + + + + + + +
Elemento canônicoOpenAI ResponsesAnthropic MessagesGoogle Gemini
Instructions / system / developerinstructions e/ou items de role conforme adapter.system top-level + messages.system_instruction + contents.
User/assistant messagesInput items multimodais.Messages com content blocks.Contents com parts.
Function toolstools com function schema; o client executa.tools com input_schema; o client retorna tool_result.Function declarations; o SDK Python pode executar automaticamente.
Reasoning / thinkingReasoning items / summaries / encrypted_content.Thinking blocks / signatures.Thought signatures em parts.
Structured outputJSON Schema / output format conforme docs.output_config.format (json_schema) conforme API/modelo.response schema / structured output conforme Gemini.
State convenienceprevious_response_id ou conversation.Message history / context management.Stateless generate_content com history/SDK chat.
+
+ A perda é decisão operacional, não detalhe técnico. Registre uma + loss declaration a cada provider switch (qual carrier/semântica se perde) e rode um eval + de regressão. O contrato de provider-switching está em + Providers & adapters; o gate de eval + correspondente em Operação, segurança & evals. + Para o invariante de wrapping do conteúdo de role=user quando o turno mistura runtime + context com prompt humano, veja §8b — Zonas canônicas. +
+
+ +
+

8b. Zonas canônicas da projeção e dados transitórios

+

+ A projeção do ledger (§8) pode ser organizada em zonas canônicas tipadas. Cada + zona tem uma função, um lugar no wire de cada provider e uma política de compactação própria. É + isso que torna o budget por fatia da + estratégia de compactação auditável: cada + token projetado pertence a uma zona, com autoridade, proveniência e TTL explícitos. +

+
+ + + + + + + + + +
Zona canônicaFunçãoOnde mora no wire (OpenAI / Gemini / Anthropic)Compactação
authority_contextAutoridade normativa: fixed kernel, protocolos, catálogo L1, L2 ativo exato, ledger de skills, output contract.instructions / system_instruction / top-level systemFixed kernel nunca compacta; L2 é atômico; L1 filtra.
conversation_contextPares user/assistant reais e resumos conversacionais.input / input timeline / messages — com roles reaisCompactação por pares + snapshots cumulativos.
turn_working_contextPrompt atual, arquivos inline do turno, tool calls abertas e seus results, carriers exigidos.itens de input + function_call(_output) / steps + function_result / tool_use+tool_resultTTL curtíssimo; expira ao fechar o loop.
hot_followup_contextDado transitório que precisa sobreviver a 1 follow-up: return packet de agent-as-tool, L3 pequeno, evidência hot.bloco tagueado no próximo turno role=user (ver invariante abaixo)TTL default 1 turno; depois digest/ref/reload.
evidence_contextRAG, web, fontes e dados externos coletados.tool result no loop aberto, ou bloco tagueado role=user fora do loopDefault digest/ref; hot opcional por domínio.
recall_contextSínteses, EvidenceCards, refs para o bruto, itens reidratáveis.conforme a autoridade do itemDigest/ref; reidratação sob demanda.
+ +

Invariante de colocação do hot follow-up

+

+ Quando o loop de tools já fechou e o modelo respondeu ao usuário, um dado transitório ainda pode + precisar influenciar o próximo turno (o clássico "e agora, transforme isso em mensagem?", + "aplique o template", "continue desse resultado"). A pergunta operacional é: em qual + role do wire ele entra? A resposta canônica é role=user + — nunca o bloco de autoridade, nunca assistant, e nunca um tool_result + fabricado. +

+
+ + + + + + + +
Candidato a roleVereditoMotivo
system / instructionsNãoÉ a autoridade estável e o prefixo de cache. Mudá-la a cada turno invalida o prompt cache e mistura dado com instrução, colidindo com o invariante do fixed kernel (§1.2).
assistant / modelNãoFalsifica "o que o modelo disse"; o modelo pode tratar dado externo como sua própria conclusão anterior.
tool_result / function_call_output / function_resultSó com loop abertoExige tool_use_id/call_id pareado no turno imediatamente anterior — isso é turn_working, não follow-up. Fabricar um par só para carregar dado é frágil e pode confundir o modelo.
user (bloco tagueado)SimMesma natureza de como a Anthropic já carrega tool_result dentro de role=user: wire role ≠ autoria canônica (§1.5). Mantém a autoridade byte-estável para cache.
+

+ O padrão portável é renderizar o pacote como bloco(s) de conteúdo no início do próximo + turno user, na mesma mensagem do prompt humano (bloco runtime primeiro, texto + do humano depois). Isso evita mensagens consecutivas de mesmo role (Anthropic e Gemini exigem + alternância) e mantém system/instructions intactos. No ledger, o item + permanece tipado como RuntimeContext / SubagentReturn / + EvidencePacket — jamais um UserPromptItem. + O padrão XML abaixo é organização auditável, não enforcement: veja o callout + danger logo após sobre por que tags não são fronteira de segurança. +

+
+ Atributos do payload vs campos do ledger. No payload XML abaixo, + ttl_turns é metadado descritivo opcional (sinaliza intenção + ao leitor humano e ao auditor); a elegibilidade real de projeção vive no ledger + via visible_from_turn/expires_after_turn/consumed_at_turn + — ver callout "Mecânica do TTL" mais adiante para o predicado canônico. +

+ Atributos de mesmo nome em zonas diferentes vivem em namespaces separados e + carregam value-spaces distintos por tipo de item — não tente unificar: +
    +
  • trust_tier em RuntimeContext (esta zona): autoridade de + projeção — valores típicos internal_reviewed/external_unverified/verified; + em SourceRecord + (File inputs): proveniência da fonte — + user_supplied/official_guideline/peer_reviewed/educational_reference/unknown. + São conceitos diferentes (autoridade ↔ proveniência) com o mesmo nome de wire; cada + consumidor lê o seu.
  • +
  • projection_policy em RuntimeContext: enum binário de + elegibilidade — allowed ou blocked; + em SourceRecord: modo de projeção do anexo — + inline_current_turn/summary/rag_only/blocked; + em Asset registry (§7 deste guia): destino do asset — + model/rag/tool/internal + (semântica de roteamento, não de elegibilidade); + em skills L2: marcador de re-injeção exata — + inject_l2_exact_while_active. Apenas blocked é compartilhado + entre RuntimeContext e SourceRecord; Asset registry e skills L2 + usam vocabulários disjuntos. Schema é per-item-type; serializer não deve + coerce valores entre zonas.
  • +
+
+
# Projeção do próximo turno (portável OpenAI/Gemini/Anthropic), role=user:
+<runtime_context not_user_authored="true" data_not_instructions="true"
+                 ttl_turns="1" source_item_ids="sub_42,ev_7" trust_tier="internal_reviewed">
+  <![CDATA[ return packet / L3 pequeno / evidência hot — schema fechado, não texto bruto ]]>
+</runtime_context>
+<human_prompt user_authored="true">
+  <![CDATA[ texto real do usuário aqui ]]>
+</human_prompt>
+

+ Quando coexistem múltiplos itens transitórios (return packets paralelos de + sub-agentes, evidência hot + L3 pequeno, etc.), aninhe-os como hierarquia tipada — Anthropic + recomenda esse padrão para múltiplos documents ("nest tags when content has a natural + hierarchy") e ele se aplica diretamente ao runtime_context: + derived +

+
# Projeção multi-item (vários return packets + evidência + L3 num único turno):
+<runtime_context not_user_authored="true" data_not_instructions="true"
+                 ttl_turns="1" task_id="task_77">
+  <return_packet index="1" source_agent_id="sub_42" trust_tier="internal_reviewed"
+                 projection_policy="allowed" source_item_id="rp_42_a" spawn_order="1"
+                 task_id="task_77">
+    <![CDATA[ packet condensado do agente A — schema fechado, não texto bruto ]]>
+  </return_packet>
+  <return_packet index="2" source_agent_id="sub_43" trust_tier="internal_reviewed"
+                 projection_policy="allowed" source_item_id="rp_43_b" spawn_order="2"
+                 task_id="task_77">
+    <![CDATA[ packet condensado do agente B ]]>
+  </return_packet>
+  <evidence index="1" source_item_id="ev_7" trust_tier="external_unverified"
+            projection_policy="allowed">
+    <![CDATA[ EvidenceCard digest — sanitize antes de renderizar ]]>
+  </evidence>
+  <l3 index="1" skill_id="skk_foo" source_item_id="l3_foo" projection_policy="allowed">
+    <![CDATA[ trecho L3 destacado para o follow-up ]]>
+  </l3>
+</runtime_context>
+<human_prompt user_authored="true">
+  <![CDATA[ texto real do usuário aqui ]]>
+</human_prompt>
+

+ Envolva o prompt humano em seu próprio bloco (<human_prompt user_authored="true">) em vez + de concatená-lo livre após o runtime: o fixed_kernel deve declarar que apenas + <human_prompt> carrega autoria humana e que todo o resto do turno + user é dado tagueado, sem autoridade de instrução. O wrapping é responsabilidade + do runtime/serializador: qualquer ocorrência de <human_prompt>/</human_prompt> + — ou de <runtime_context> e atributos como user_authored — dentro de + evidência, return packet ou texto externo DEVE ser escapada/rejeitada antes de ir ao payload; sem isso, + um atacante forja autoria humana injetando a tag (confused deputy via XML hostil). +

+

+ Ordem dentro de <runtime_context> (derivada): + (i) pré-filtro: só projection_policy="allowed" entra; + blocked não renderiza; + (ii) por causal dependency e topic/task_id + (manter pacotes do mesmo fio juntos); + (iii) por tipo — decisão condensada (return_packet) + → prova/proveniência (evidence) → recurso de apoio (l3); + se l3 for externo/unverified, trate-o como evidence e reordene; + (iv) por trust_tier desc (verified/internal antes de unverified/external); + (v) por spawn_order/created_at_turn asc como tiebreaker estável. + Em contextos longos, tende a haver melhor recuperação nos bordos (literatura + lost-in-the-middle/position bias), então o item de maior autoridade abre o + <runtime_context> e o <human_prompt> fecha o turno + user. Nunca colocar evidência externa unverified imediatamente antes + de <human_prompt> — a recência amplifica seu peso na resposta. + derived sem doc oficial prescrevendo ordem entre múltiplos + return_packets paralelos. +

+
+ Por que dado antes, prompt depois. Padrão recomendado por Anthropic e Gemini; + em OpenAI é compatível com cache-prefix guidance, não regra oficial de ordem. Anthropic + long-context: documentos e inputs longos no topo do prompt, query/instruções no fim — ganho + medido de até ~30% em respostas com inputs multi-documento + (long-context-tips, verificado 2026-05-26). + Gemini converge: contexto primeiro, query/instruções no fim + (prompting-strategies, 2026-04-28). + OpenAI não prescreve ordem mas o padrão é compatível com cache-prefix + (prompt-caching). + Vale também para follow-ups curtos ("sim, prossiga"): não inverta a ordem; + se o pacote já é redundante, reduza-o a digest ou ref via source_item_id em + vez de reordenar. +
+
+ XML tagging vs blocos nativos de content: dois mecanismos, mesmo invariante. + O wrapping com <human_prompt>/<runtime_context> é a forma + canônica quando o turno role=user é colapsado em um único bloco de texto + (caso comum para portabilidade cross-provider). Quando o provider permite separar o conteúdo em + múltiplos blocos nativos de content — caption como bloco texto, documento + como bloco file/document, planilha como bloco file, instruções como bloco texto, prompt humano como + bloco texto final — a fronteira de bloco já cumpre o papel de "dados não carregam autoridade de + instrução" sem precisar de wrapper XML. Os exemplos por provider em + File inputs sem provider storage (§10, §14.1–§14.3) + usam essa segunda forma: cada item de content é por si só um bloco tipado, e o invariante + é honrado pela própria estrutura da mensagem. Use XML tagging quando estiver concatenando dentro de um + único text; use blocos nativos quando o adapter os preserva — não os dois ao mesmo tempo. +

+ Exceção dura — Anthropic citations/search_result blocks: documentos cita-veis + e resultados de busca precisam vir como blocos nativos tipados + ({"type":"document",...,"citations":{"enabled":true}} ou + {"type":"search_result",...}); envolver o conteúdo em XML quebra citations nativas. + Nesse caso, <runtime_context> carrega apenas metadados/transitórios + não-documentais e o documento/search_result fica como bloco nativo separado no + mesmo content[], posicionado antes do <human_prompt>. Para RAG + citável, prefira search_result nativo; quando cacheável, + cache_control fica no próprio bloco nativo; citations devem ser all-or-none no + mesmo request + (citations, + search-results, 2026-05-26). +
+
+ Tags não são fronteira de segurança. data_not_instructions é + organização, não defesa. Return packets e evidência podem conter injeção de prompt, XML hostil ou + fatos stale. Serialize com schema fechado, escaping/CDATA, trust_tier, + hashes e source_item_ids; sanitize antes de renderizar; e cubra com evals de + prompt-injection (Operação, segurança & evals). + Nunca renderize texto bruto de fonte externa como XML livre dentro da projeção. +
+
+ Mecânica do TTL: eviction acontece na projeção, não no ledger. + O item RuntimeContext permanece no ledger com campos + created_at_turn, visible_from_turn, expires_after_turn, + projection_id, projected_at_turn (receipt do último envio, NÃO + relógio de expiração) e consumed_at_turn. Predicado de projeção (avaliado a + cada turno do usuário): + current_user_turn >= visible_from_turn && current_user_turn <= expires_after_turn && consumed_at_turn == null. + Não decremente mutavelmente no item (race em tool loops paralelos); compute na + projeção. Quando "consumido", grave consumed_at_turn=<current_user_turn> — + ele some da projeção mas sobrevive no ledger para re-materialização via + source_item_id se o próximo turno do usuário pedir ("explique aquele item X"). +

+ Invariante de tool loop: dentro de um único turno do usuário, o + runtime_context é projetado UMA vez no primeiro request com tools; + iterações tool_use→tool_result NÃO re-projetam (cada iteração + re-envia o histórico crescente; mexer no transitório quebra cache N vezes e duplica + evidência). TTL conta turnos do usuário, não iterações de tool. +

+ Posição na cauda do role=user é cache-preservation, não só + anti-confused-deputy. Anthropic prompt-caching trabalha com até 4 breakpoints e ~20 blocos + de lookback do cache_control mais recente; OpenAI faz match exato de prefixo + (volatile content no fim); Gemini cachedContent só vale para contexto estático + — hot_followup, por ser transitório, NÃO entra no cachedContent. +

+ Três camadas distintas — não confundir: + (i) Memory tool (Anthropic) = persistência cross-sessão client-side em + /memories; + (ii) Context-editing (Anthropic clear_tool_uses_20250919 / + clear_thinking_20251015) = server-side FIFO sobre tool_result/ + thinking, NÃO atinge blocos role=user transitórios; + (iii) hot_followup ledger TTL = projection-time, role=user, qualquer + provider — esta seção. +

+ Notas por provider: + OpenAI chaining/cache: veja o callout "Cache-hit em projeção manual" abaixo; + Gemini Interactions stateful preserva apenas inputs+outputs — + tools/system_instruction/generation_config são + interaction-scoped e re-enviados a cada turno; + Anthropic stateless: histórico completo client-side, com cache breakpoint no fim do system + ou primeiro user estável. +
+
+ Cache-hit em projeção manual: maximize com disciplina de prefixo estável. + Toda a arquitetura desta zona (kernel byte-estável + tools/system idênticos + hot_followup + só na cauda do role=user com TTL) foi desenhada para tirar proveito do prompt caching + cross-provider. Resumo operacional por provider: +

+ OpenAI Responses — cache automático de prefixos (geralmente ≥1024 tokens); + ative prompt_cache_key para rotear requests do mesmo "fio" para o mesmo worker + (aumenta hit rate em fan-out / concorrência); meça na Responses API via + usage.input_tokens_details.cached_tokens; em Chat Completions, via + usage.prompt_tokens_details.cached_tokens. Em + previous_response_id chaining, não fazer manual prune do histórico do chain + (prompt-caching, + prompt_cache_key, 2026-05-26). +

+ Anthropic Messages — caching explícito via cache_control em + até 4 breakpoints; ~20 blocos de lookback; TTL 5min default, extensível + para 1h via {"cache_control":{"type":"ephemeral","ttl":"1h"}} no próprio + bloco. Coloque breakpoints no fim do system (kernel estável) e no último bloco estável de + messages; meça via usage.cache_creation_input_tokens e + usage.cache_read_input_tokens. Nunca empurre runtime_context + transitório para dentro do system — quebra o cache do kernel + (prompt-caching, 2026-05-26). +

+ Gemini Interactions — somente implicit caching + (habilitado por default em Gemini 2.5+ e modelos posteriores). + previous_interaction_id é o mecanismo de continuidade da conversa + (preserva history server-side); por preservar prefixo estável, conversas encadeadas + tipicamente se beneficiam do implicit caching que já roda + derived — causalidade direta + previous_interaction_id→cache não está literalmente documentada. + Explicit caching com + cached_content/cachedContent é do generateContent, + não da Interactions API; hot_followup fica fora de caches explícitos por + ser transitório. Naming wire vs SDK: REST cachedContent (camelCase); Python + SDK config cached_content; JS SDK config cachedContent + (Interactions caching, + generateContent caching, 2026-05-26). +

+ Disciplina cross-provider que esta zona já enforce: + (1) kernel byte-estável (system/instructions imutável na sessão); + (2) tools/system_instruction declarados no início e re-enviados + idênticos, incluindo ordem, schemas, names/descriptions e structured-output + schemas (Gemini interaction-scoped exige re-envio idêntico a cada turno); + (3) histórico append-only (nunca modificar mensagens anteriores); + (4) volatile content (hot_followup, timestamps, IDs por request) SEMPRE na cauda do role=user + atual; + (5) compactação antes do breakpoint = invalida o prefixo cacheado — preferir drop + ao final do histórico estável ou compactação que mova o breakpoint atomically (ver + guia de compactação §5/§6 sobre + escada de degraus e snapshots). +
+
+ Reasoning summary entre turnos: canal nativo dentro do provider, runtime_context + cross-provider, NUNCA <thinking> em role=assistant. + Reasoning persistido entre turnos vive sempre no carrier nativo — + thinking block + signature (Anthropic), + reasoning item (OpenAI Responses; encrypted_content só em + stateless/store=false/ZDR), + part com thought_signature (Gemini). + Em loops de tools esses carriers são obrigatórios: Anthropic exige o + thinking block intacto; Gemini exige thought_signature para function-calling + signatures (omissão pode gerar erro ou perda de continuidade); OpenAI cookbook: + "you do need to include the reasoning items". + Em chat puro são opcionais — mas a alternativa é omissão, nunca duplicação + como <thinking> text em role=assistant (infla tokens cobrados, invalida + prefix-cache e cria role-confusion: o modelo infere autoridade por estilo — texto + pseudo-thinking em assistant vira "minha conclusão anterior", quebrando o invariante desta + zona). +

+ Cross-provider migration: carriers nativos NÃO migram. O summary do + provider de origem entra como loss declaration tagueada em + <runtime_context source_provider="anthropic" trust_tier="internal_reviewed" projected_from_native="true" summary_only="true" no_signature="true" not_model_authored="true"><reasoning_summary>…</reasoning_summary></runtime_context> + no role=user do próximo turno. Use <reasoning_summary> em vez de + <thinking> para reduzir confusão de role/autoridade. +

+ Sub-agent reasoning summary: com loop de agent-as-tool aberto, vai no + tool_result payload (role=user no wire); fechado o loop, sobrevive em + <runtime_context><subagent_return><reasoning_summary>…</reasoning_summary></subagent_return></runtime_context> + no próximo role=user. Não assuma promoção automática de reasoning de subagent ao parent — + trate como contrato explícito do return_packet (decida o que sobe e + tagueie). +

+ Única exceção em que <thinking> text é aceitável: + few-shot examples no kernel/system/L2 para ensinar estilo (Anthropic: + "Use <thinking> tags inside your few-shot examples") — + few-shot fictício/exemplar, não replay de reasoning real. +
+
+ Contrato aqui, números lá. As zonas acima são o contrato. Os budgets por + fatia (targets/hard caps por tier), a ordem de compactação e os watermarks que as governam + estão em Contexto & compactação — + estratégias. O ciclo de vida de L2/L3 de skills (incluindo a reinjeção de L2 exato em + follow-up) está em Agent Skills. +
+
+ + +
+

8c. Agent-as-tool multi-turno & continuidade conversacional

+

+ O §8b resolve o follow-up de um turno. Esta seção resolve o caso mais difícil: um + agent-as-tool que tem vida interna multi-turno — delibera, chama tools, faz + vários passes de reasoning antes de uma resposta definitiva — e a + continuidade conversacional entre agentes, inclusive quando o sub-agente + precisa de mais informação e o orquestrador volta ao usuário para buscá-la, e quando o + sub-agente é, ele mesmo, orquestrador de um sub-agente (recursão). O modelo é o mesmo do + §8: ledger canônico app-managed como única fonte de verdade, e + projeção wire descartável por turno. A novidade é que cada conversa + agente↔agente vira um ledger isolado próprio. +

+ +
+ Invariante mestre (abre toda esta seção). + Caching é uma otimização da projeção, não um mecanismo de continuidade. O request + enviado ao provider deve ser completo, válido e seguro mesmo se todo cache der + miss. Estado vive no nosso ledger; provider-state (Conversations API, + session_thread_id, previous_interaction_id) é, no máximo, + cache hint não-autoritativo e descartável — nunca fonte de verdade. +
+ +

8c.1 — Persistência completa & isolamento absoluto

+

+ Cada sub-conversação (orquestrador↔especialista, especialista↔sub-especialista) é um + ledger append-only isolado. Dentro dele guardamos tudo, turno + a turno, até a resposta definitiva: input completo, multimodais (por asset_id + + SourceRecord, não bytes duplicados), + carriers nativos de reasoning serializados (§8b — thinking block+signature, + reasoning item+encrypted_content, part com thought_signature), e + todos os tool_call/tool_result íntegros. Compactação + é projeção derivada (§10) — nunca apaga o log bruto. +

+

+ O orquestrador nunca vê o ledger interno do filho. Recebe apenas o + return packet final, projetado como + <runtime_context><subagent_return>…</subagent_return></runtime_context> + no role=user do seu próximo turno (mesma natureza do + hot_followup_context do §8b). Isolamento é o que mantém o cache do pai estável: o + ledger pai não cresce a cada passe interno do filho. +

+ +
+ + + + + + +
CamadaRetémNÃO retém
Ledger isolado do filhoReasoning carriers, tool pairs íntegros, SourceRecord do que recuperou, input multimodal por ref, todos os turnos internos.—
Return packet (filho→pai)final_answer curto, reasoning_summary redacted, asset_refs (ponteiros), exec_meta.Reasoning carrier bruto; bytes de assets; histórico interno de turnos.
Ledger do paiSuas próprias decisões + o return packet do filho + ponteiro isolated_ledger_ref.O ledger interno do filho — só o ref.
+ +

8c.2 — Schema canônico da sub-conversação & marcador de fechamento

+

+ A identidade da sub-conversação reusa os tipos do ledger (§8) e acrescenta o necessário para + recursão, retomada e governança. Campos em negrito são obrigatórios. +

+
# Tipo de item no ledger (PascalCase); wire tag = <runtime_context><subagent_return>
+SubConversation {
+  # identidade / árvore
+  conversation_id, root_conversation_id, parent_conversation_id, parent_call_id,
+  depth, max_depth, path[],                 # path[] = ancestrais; loop-check O(1)
+  agent_id,
+
+  # governança / multi-tenancy
+  tenant_id, classification,                # public | internal | pii | phi | regulated
+  retention_policy, region_policy,
+  actor_role, actor_id, actor_tenant_id,
+  created_at_turn, last_resumed_at_turn, lease_expires_at,
+
+  # retomada / idempotência
+  pending_request_ids[],                    # LISTA: resolução parcial é caso real
+  request_nonce_hash, idempotency_key,
+
+  # execução (per-call, não per-conversation)
+  provider_route { provider, model, adapter_version, api_surface },
+  projection_version, event_schema_hash, return_packet_schema_hash,
+  capability_set_hash, available_capabilities_hashes[],   # tools mutáveis mid-conversa
+
+  # cache hints (NÃO-autoritativo — ver 8c.6)
+  cache_hints[] { provider, kind, opaque_ref, ttl, expires_at,
+                  non_authoritative=true, tenant_scope, allowed_under_zdr },
+
+  # carriers nativos (opacos, provider-scoped — NÃO normalizar; §8b)
+  native_carriers[] { provider, carrier_kind, wire_payload_ref, canonical_position,
+                      provider_schema_version, sha256, replay_requirements,
+                      native_reasoning_portability,        # provider_native_replay
+                                                           #  | gemini_validation_bridge
+                                                           #  | summary_only | unavailable
+                      required_for_open_tool_loop, safe_to_omit_after_closed_turn },
+  reasoning_continuity_mode,                # native_carrier_in_ledger | summary_only
+                                            #  | unavailable | not_applicable
+
+  # retorno / auditoria
+  return_packet_ref, redaction_policy_version,
+  phi_scan_status,                          # passed | scrubbed | blocked
+  provider_audit_refs[],
+  closure_marker
+}
+
+closure_marker {
+  closure_id, closed_at_turn, closed_at_wall_clock,
+  final_state,                              # closed_final | closed_failed | closed_cancelled
+                                            #  | closed_superseded | closed_retries_exhausted
+  return_packet_ref, return_packet_hash, return_packet_schema_version,
+  native_carrier_manifest_hash, tool_pair_integrity_status,
+  loss_declaration_refs[], redaction_status,   # passed | scrubbed | blocked
+  replay_authorization_roles[], recovery_policy, retention_until, purge_after,
+  non_projectable_raw_child_log = true      # INVARIANTE HARD (ver 8c.7)
+}
+ +
+ Reuso, não reinvenção. SubConversation é um item do mesmo ledger + do §8; asset_refs usam SourceRecord; + native_carriers seguem o invariante de carrier nativo do §8b; cache_hints + seguem o §10 (caching+ZDR). Nada aqui é vocabulário novo — é o §8 aplicado à profundidade. +
+ +

8c.3 — Round-trip ao usuário (pause/resume)

+

+ Quando o sub-agente precisa de informação que só o usuário tem, ele emite um + request_info de schema fechado (não texto livre) e a + sub-conversação entra em state=awaiting_user_info — o mesmo estado que a + estratégia de compactação §6 chama de + waiting_user_input (alias formal). O lease_expires_at impede que ela + fique pendurada para sempre. +

+
    +
  1. Sub-agente → request_info { request_id, schema (JSON Schema), prompt_to_user, rationale, expires_at }.
  2. +
  3. Orquestrador traduz para linguagem humana (i18n-aware) — não injeta o request_info bruto no seu próprio role=user.
  4. +
  5. Usuário responde; orquestrador valida contra o schema antes de retornar à sub-conversação.
  6. +
  7. Orquestrador re-chama o sub-agente com o mesmo conversation_id (resume, não spawn), ligando a resposta ao request_nonce_hash.
  8. +
+

+ A forma de injetar a resposta segue o invariante do §8b — não fabricar + tool_result se não houve tool_call real: +

+
+ + + + + +
O sub-agente emitiu…A resposta volta como…
tool_use/function_call real (ex.: tool ask_user)tool_result / function_result / function_call_output nativo, pareado pelo id.
request_info como conteúdo estruturado do output (sem tool_call)role=user no input do próximo turno, carregando o JSON validado. Nunca tool_use_id fabricado (Anthropic rejeita id desconhecido; quebra cache).
+
+ Topic-switch guard. Se o usuário muda de assunto durante + awaiting_user_info, não consuma a fala fora-de-tópico como resposta + ao sub-agente. Mantenha a sub-conversação suspensa sob TTL ou marque + closed_superseded com cancel_reason="user_topic_switch"; retome depois + via Opção B (8c.7). Idempotência: request_nonce_hash + idempotency_key + + registro delivered=true/false no ledger bloqueiam entrega dupla em retry. +
+ +

8c.4 — Caso recursivo & bubble-up sem duplicação

+

+ O especialista primário pode ser, ele mesmo, orquestrador de um especialista secundário. Mesma + estrutura, profundidade limitada por max_depth (default 3 em fluxos end-user). + Invariantes de recursão: +

+
    +
  • Path-uniqueness: nenhum agent_id em path[] aparece duas vezes (mata reentrância direta e indireta).
  • +
  • Monotonicidade: filho nunca reduz classification nem amplia region_policy; capability_acl é intersect_parent.
  • +
  • Budget finito: cada filho recebe budget_grant do residual do pai; nenhum descendente cria orçamento fora do root.
  • +
  • Cancellation cascade: root cancela → descendants ativos cancelam com cancel_reason="parent_cascade".
  • +
+

+ O return packet bubble-up carrega só o essencial. asset_refs sobem + por valor (mesmo URI), nunca por cópia de bytes: se o secundário cita uma guideline com + ref://…, o primário propaga o mesmo ref ao orquestrador, que renderiza + a citação ao usuário sem nunca carregar os bytes. +

+
+ Isolamento por nível: o conversacional nem enxerga o secundário. + Cada pai vê apenas o return packet do seu filho DIRETO — nunca de um neto. No exemplo + de 3 níveis (8c.5), o orquestrador conversacional recebe só o return packet consolidado do + especialista primário; ele não tem ledger, conversation_id nem qualquer visibilidade + sobre o especialista secundário (consulta-guidelines), que existe inteiramente dentro do escopo do + primário. A conversa primário↔secundário tem seu próprio conversation_id e ledger + isolado, com possíveis múltiplos turnos internos e até seu próprio awaiting_user_info + (que sobe ao primário, não pula direto ao usuário). Os três casos cobertos por esta seção: + (1) turnos internos do agent-as-tool sem volta ao usuário (8c.1, 8c.6); + (2) continuação conversacional usuário↔agent-as-tool com volta ao usuário para + coletar info (8c.3); (3) continuação agent-as-tool↔agent-as-tool que o + conversacional nem enxerga (este bloco + 8c.5). Todos com persistência completa no ledger isolado e + closure_marker ao terminar. +
+ +

8c.5 — Exemplo canônico: triagem administrativa/educacional (não-clínica)

+
+ Boundary obrigatória. Este exemplo é orientação administrativa/educacional + sobre quando procurar avaliação — não é prática clínica nem aconselhamento médico. Só é + defensável sob rota enterprise/BAA: Gemini via Vertex AI HIPAA-flagged + project + Web Grounding for Enterprise (Google Search Grounding comum + retém 30d, mesmo sob ZDR — §10); Claude via Enterprise BAA. Não + usar a Gemini API geral para triagem symptom-specific (os Termos da Gemini API proíbem clinical + practice / medical advice em uso geral). PHI mínima por nível; patient_context_id opaco. +
+
NÍVEL 0  conv_main  (orquestrador conversacional · Claude Sonnet 4.6 · low_friction)
+  T0 user  "tosse há 6 dias, meio sufocada à noite, é grave?"
+  T1 assistant → call_education_triage(...)        cache_key=HMAC(tenant, orchestrator, ...)
+     │
+     ▼ spawn NÍVEL 1  conv_triage_001  (Opus 4.8 xhigh · deliberative · path=[main,triage])
+        T1.1 reasoning_native (thinking+signature, no ledger isolado)
+        T1.2 request_info{ idade, dias, febre, comorbidade, tabagismo }
+             state=awaiting_user_info · lease=+15min            ↑ return_packet(request_info)
+  T2 orquestrador TRADUZ ao usuário (não copia request_info bruto)
+  T3 user  "58 anos, 6 dias, febre 37.8, catarro amarelo, ex-fumante, HAS"
+  T4 valida contra schema → OK
+  T5 re-chama call_education_triage(resume_conversation_id=conv_triage_001, info=...)   ← RESUME
+     │
+     ▼ conv_triage_001 retoma (state=open)
+        T1.3 role=user  {info validada}            # NÃO tool_result fabricado
+        T1.4 reasoning_native → query_education_guidelines(...)
+             │
+             ▼ spawn NÍVEL 2  conv_guidelines_001a  (Gemini 3.1 Pro · Vertex+BAA · path=[main,triage,guidelines])
+                T2.1 retrieve_guideline (Web Grounding for Enterprise — HIPAA-safe)
+                T2.2 tool_result → SourceRecord NICE patient-info §3.2 (asset_id, sha256)  [bytes só aqui]
+                T2.3 cite_source(ref, span)
+                T2.4 final_answer educacional (não-diagnóstico)  · phi_scan_status=passed
+                     closure: non_projectable_raw_child_log=true   ↑ return_packet{asset_refs}
+        T1.5 recebe return_packet (sem raw child log)
+        T1.6 final_answer: "procurar avaliação presencial em <24h" + red flags
+             closure: non_projectable_raw_child_log=true             ↑ return_packet
+  T6 orquestrador comunica empático + cita NICE/SBPT como referência educacional + red flags
+

+ Pontos canônicos: a pausa awaiting_user_info nasce no nível 1 (o filho + não fala com o usuário; o orquestrador intermedia); bytes do guideline vivem só no + ledger do nível 2, e sobem como asset_refs; reasoning nativo de cada + nível fica no seu próprio ledger e jamais atravessa a fronteira — só o reasoning_summary + curto e redacted. +

+ +

8c.6 — Cache, pause/resume & por que o orquestrador não sofre token explosion

+

+ A história interna de um sub-agente cresce a cada passe — custo cumulativo + O(n²) dentro da sub-conversação. Mas isso não vira + explosão no orquestrador: cada turno do pai vê só o seu próprio diálogo + o + return_packet do filho (poucos KB). A explosão fica contida no escopo + isolado, e é mitigada por prompt-caching por agent_id — desde que o pai mantenha o + return packet bounded: +

+
+ Hard caps no pai (HOT-FU-001). parent_hot_followup_budget (token cap), + max_return_packets_projected (n), TTL no hot_followup; após N turnos do pai, packets + antigos viram digest/ref ou EvidenceCard bounded — nunca acumulam raw. Sem isso, a + explosão volta no pai. +
+

Disciplina de cache por provider (cache é hint, nunca estado):

+
+ + + + + + +
ProviderMecanismo (hint)Rota ZDR/store=false estrita
OpenAIprompt_cache_key por agent_id; extended retention 24h obrigatório em gpt-5.5 (in_memory → erro); desde 2026-05-29 o default de prompt_cache_retention é "24h" para qualquer organização sem ZDR (não só gpt-5.5)permitido (cached tokens contam para TPM/janela)
Anthropiccache_control em até 4 breakpoints (ttl "5m"|"1h" no bloco)permitido; usar breakpoints explícitos em tools/system/L2 estável — não confiar em automatic caching (escolhe o último bloco cacheável → pode pegar o hot_followup volátil)
Geminiimplicit in-memory caching (prefixo estável) ZDR-compatible — RAM-only, isolado por projeto, TTL 24hpermitido; NÃO criar cachedContents; NÃO usar previous_interaction_id (é state handle server-side; store=false o impede)
+
+ Gemini, duas rotas (CACHE-004). O implicit cache do Gemini é ZDR-friendly e + sempre permitido — não confunda com handles de estado. Em ZDR estrito ficam + bloqueados apenas os objetos/handles que implicam armazenamento server-side: + cachedContents, previous_interaction_id, File API persistente, Live + SessionResumptionConfig. previous_interaction_id só vale como cache hint + não-autoritativo em rota não-ZDR opt-in. Detalhe canônico em + Token counting — §10 caching+ZDR. +
+

+ Pause/resume é wall-clock, não em turnos do pai: 3 turnos do orquestrador podem ser + 30 s ou 30 min. Para retomar com cache-hit: mesmo model/tools (ordem + estável)/instructions/prompt_cache_key; em Anthropic a sequência até o + breakpoint deve ser byte-idêntica. Pausa esperada > 5 min: ttl "1h". Pausa > 1 h: + aceitar miss, mitigar com snapshot compactado antes da pausa. +

+ +

8c.7 — Lifecycle, GC & recuperação histórica

+

+ Ao fechar, o closure_marker torna o raw child log + não-projetável ao modelo do pai (non_projectable_raw_child_log=true). + Tooling/framework que tente auto-carregar o histórico do filho deve falhar fail-closed. + O pai lê o filho por apenas dois caminhos: o return_packet_ref (durante a conversa) ou o + gateway histórico (mode=historical), quando precisa relembrar uma decisão + anterior (ex.: o usuário volta no dia seguinte). +

+
+ + + + + + + +
RecuperaçãoQuandoEmite
A — flashback (default)Esclarecer decisão anterior; sem novo julgamento.Re-projeta o return packet antigo (redacted) como <runtime_context kind="historical_subagent_decision"> em role=user. Não rehidrata raw log.
B — nova sub-conversaçãoNovo julgamento (situação mudou).Spawn com parent_call_id apontando à anterior; return packet antigo entra como EvidenceCard, não raw log.
C — child-recall gatewayReturn packet não basta; auditor precisa de detalhe.EvidenceCard bounded redacted (phi_scan_status=passed). Nunca transcript bruto.
D — forensic replayAuditoria forense.audit-only, fora do live path — nunca projetável ao modelo do pai.
+
+ Vetores residuais de contaminação a fechar. O closed só impede + contaminação se você também bloquear: (1) cache leak por prefixo compartilhado → + prompt_cache_key por agent_id + tenant_id/security partition + no seed (em workloads regulados, domain-separation via HKDF com labels versionados + security_fingerprint:v1/cache_affinity:v1/provider_prompt_cache_key:v1); + (2) índice RAG/vector contaminado pelo raw child log → retrieval_scope=child_only|audit_only; + (3) trace/exporter vazando refs como texto → trace_export_scope=redacted; + (4) PHI bubbling via reasoning_summary → redactor obrigatório antes do bubble-up, + phi_scan_status=passed (se blocked, o packet não é projetável). +
+
+ Observabilidade de cache. Registre no run ledger/telemetria — sem objeto novo — + provider_usage.cached_tokens, cache_hit_tokens, cache_write_tokens, + cache_read_tokens, cache_miss_reason, cache_hint_kind e o + projection_hash quando o provider expõe. Cache que não se mede vira ilusão de economia. +
+
+ Cross-links. Carriers nativos e colocação do follow-up: + §8b. Cache+ZDR por provider (IMPLICIT-ONLY Gemini): + Token counting §10. Degraus de compactação e microconversas: + Contexto & compactação §5/§6. Assets e + SourceRecord: File inputs. +
+ + +
+ Como usar este bloco (para IA). Um agente/scraper pode pular direto para + script[type="application/ld+json"] desta seção e tratar additionalProperty + como uma matriz de fatos. Os propertyID seguem o padrão 8c.<tópico> + (e 8c.cache.<provider> para caching por provider) — fácil de mapear a + YAML/JSONSchema downstream sem reparsear a prosa. +
+
+ + +
+

Parte 3 — Compaction & budgets

+

Como medir o orçamento de contexto, qual é o contrato de compaction (e o que ele jamais pode + perder) e como provar, com testes, que a memória sobrevive ao replay.

+
+ +
+

9. Budgets e invariantes

+

+ Um princípio simples atravessa o material: limite que não é medido não existe. + Defina budgets por turn, subagente, capability, provider, usuário e síntese final. O orçamento de + contexto de um turno é a soma do que será projetado mais a reserva da resposta: +

+
tokens(instructions + projected_dialogue + projected_assets + projected_tool_context)
+  + max_output_tokens (inclui reasoning/thinking conforme o provider)
+  + margem_de_seguranca
+  ≤ janela_do_modelo
+
+ Reasoning/thinking consome orçamento. Em todos os três providers, os tokens de + raciocínio interno contam contra o limite de saída ou a janela. Reserve explicitamente + (final_reserve_tokens no active plan) + para não esgotar a resposta final abrindo tools. +
+
+ Cross-link (não duplicar): como contar esses tokens — tokenizadores por + provider, count_tokens/usage, custo de imagem e receitas copy-paste — + está inteiramente em Token counting. Aqui o budget é o + invariante que o loop respeita; lá está a aritmética. +
+
+ Hard cap de fatia ≠ soma simultânea. Ao subdividir o orçamento em fatias por + zona (authority, diálogo, turn_working, + hot follow-up, recall…), trate cada hard como um teto local não-simultâneo: + a soma dos hards costuma exceder a janela de propósito — isso é folga de design, não um budget + somável. O que vincula é sempre a fórmula acima + (projeção + reserva de saída + margem ≤ janela efetiva). E mantenha o + reserved_unallocated (folga de tokenização/overhead de provider) separado + da margem de segurança da resposta, para não contar a mesma folga duas vezes. +
+
+ +
+

10. Compaction e reidratação — o contrato

+

+ Compaction não é "resumir a conversa". É substituir partes do ledger por + artefatos menores mantendo rastreabilidade. Uma compaction aceitável preserva: fatos + confirmados, decisões, incertezas, pendências, tool calls/results relevantes, assets e hashes, + citações, preferências do usuário, carriers que precisam de replay e limites de confiança. +

+
{
+  "compaction_item": {
+    "replaces_item_ids": ["msg_10", "tool_11", "tool_12"],
+    "summary": "...",
+    "facts": [{"claim": "...", "source_item_id": "tool_11", "confidence": "high"}],
+    "open_issues": [],
+    "asset_refs": ["asset_pdf_1"],
+    "provider_carriers_preserved": ["openai_reasoning_enc_3"],
+    "losses_declared": ["verbatim wording removed"]
+  }
+}
+
+ Contrato aqui, estratégia lá. Este capítulo define o que uma compaction + deve preservar e declarar. Como escolher o teto X, montar a escada de compactação e + manter snapshots cumulativos está em + Contexto & compactação — estratégias. + Os dois são complementares: a estratégia deve sempre produzir um compaction_item que + satisfaça este contrato. +
+
+ +
+

11. Perdas aceitáveis e perdas proibidas na compaction

+

A tabela abaixo é o gate de revisão de qualquer compaction antes de ela substituir itens reais:

+
+ + + + + + + + + +
Tipo de informaçãoPode ser compactada?Como preservar
Estilo/verbatim de conversa antigaSim, geralmente.Resumo curto ou remoção declarada.
Fato usado em decisãoNão como perda silenciosa.Fact item com source_id e confiança.
Tool call/result necessário para auditoriaNão.IDs, args hash, status, reduced output e provenance.
Reasoning/thinking carrier exigido pelo providerNão converter em texto.Preservar o carrier oficial ou declarar indisponibilidade.
Preferência estável do usuárioSim, com cuidado.Memory item versionado com origem.
Dado sensível irrelevanteDeve ser removido/redigido.Redaction item + hash quando necessário.
+
+ Perda proibida silenciosa = incidente. Se uma compaction descartar um fato que + sustentava uma decisão, o replay reconstrói uma história falsa. Toda perda relevante deve ser + declarada em losses_declared e, se for um fato de decisão, preservada como + fact item — nunca apenas "resumida". +
+
+ +
+

12. Testes de memória e contexto

+

+ Memória não é "funcionou uma vez". Estes testes pertencem ao pacote de regressão do sistema e + mapeiam diretamente aos gates de eval do capítulo de + operação (gate CTX-001): +

+
    +
  • ☐ Replay determinístico: reidratar o ledger reproduz a mesma projeção (mod. timestamps/nonces).
  • +
  • ☐ Sobrevivência à compaction: após compactar, nenhum fato de decisão, tool result auditável ou pendência some do replay.
  • +
  • ☐ Integridade de carrier: thinking blocks/signatures e reasoning carriers exigidos voltam corretamente no tool loop (sem erro do provider).
  • +
  • ☐ Provider switch com loss declaration: projetar para outro provider produz uma loss declaration e passa no eval de regressão.
  • +
  • ☐ Budget e wind-down: ao atingir a reserva final, o sistema finaliza sem abrir novas tools.
  • +
  • ☐ Isolamento de tenant: nenhum asset/fato de outro tenant entra na projeção.
  • +
+
+ Como falsificar barato: o teste de sobrevivência à compaction é o mais valioso e + o mais barato — monte um ledger com 3 fatos de decisão, compacte, reidrate e asserte que os 3 + fact items continuam presentes com source_item_id. Falha aqui é perda silenciosa. +
+
+ + +
+

Checklist de estado

+

Gate antes de promover qualquer gestão de estado/memória para produção:

+
    +
  • ☐ O ledger distingue mensagens, tools, assets, carriers, approvals, usage e compactions.
  • +
  • ☐ Cada provider adapter é uma projeção pura a partir do ledger, não uma mutação escondida.
  • +
  • ☐ Reasoning/thinking privado é preservado no carrier oficial quando necessário, sem expor a cadeia de pensamento.
  • +
  • ☐ Compactions declaram itens substituídos, perdas e fontes preservadas.
  • +
  • ☐ Budgets incluem reasoning/thinking/output final e margem de segurança.
  • +
  • ☐ Fluxos sensíveis não dependem de estado retido por provider sem política explícita.
  • +
  • ☐ Assets têm identidade, provenance, classificação e projection_policy.
  • +
+
+ +
+

Notas de verificação

+
    +
  • Atualizado 2026-06-10 Varredura de 2026-06-10. Fatos perecíveis re-conferidos contra docs oficiais + PyPI/npm. Mudança incorporada no §8c.6 (prosa + JSON-LD): desde 2026-05-29 o default de prompt_cache_retention na OpenAI é "24h" para qualquer organização sem ZDR — o fato gpt-5.5 (24h obrigatório; in_memory → erro) segue válido. Nota "Sem IDs de modelo fixos" clarificada (exceção do §8c). Demais contratos deste capítulo sem mudança upstream.
  • +
  • Atualizado 2026-06-10 Zonas canônicas & colocação do hot follow-up (§8b). Integrada a proposta de gestão manual de contexto v0.6 (debate gpt-5.5-pro + revisão adversarial codex/gpt-5.5). Decisão validada: dado transitório de follow-up entra em role=user tagueado, não no system/autoridade — preservando o prefixo de cache e a separação autoria/dado. Re-confirmado contra docs oficiais que a Gemini Interactions API usa generation_config.thinking_level (não thinking_config aninhado) e usage.total_thought_tokens/total_output_tokens (renomeado de total_reasoning_tokens em 2025-12-19; thoughtsTokenCount é do generateContent).
  • +
  • Resolvido Controles de reasoning/thinking. Conferidos na folha de fatos SOTA (2026-06-10): OpenAI reasoning.effort = none|low|medium|high|xhigh; Anthropic thinking = adaptive/enabled+budget_tokens/disabled com display summarized|omitted; Google thinking_level = low|medium|high (Flash/Flash-Lite também minimal), com thinking_budget legado não-combinável.
  • +
  • Resolvido Estado na Responses API. previous_response_id/conversation são conveniência; instructions não são recarregadas automaticamente; store=false + include=["reasoning.encrypted_content"] para fluxos stateless/ZDR — confirmado na doc oficial.
  • +
  • Resolvido Sem duplicação. Compaction estratégica e contagem de tokens permanecem nos guias dedicados; este capítulo trata apenas do contrato de estado e de compaction.
  • +
  • Resolvido Sem IDs de modelo fixos. O capítulo cita parâmetros (perenes) e não modelos (perecíveis); disponibilidade por modelo fica nos guias de provider e na folha de fatos SOTA (exceção deliberada: o §8c cita IDs datados como exemplos verificados em 2026-06-10 — gpt-5.5, Claude Sonnet 4.6, Claude Opus 4.8, Gemini 3.1 Pro).
  • +
  • UNVERIFIED Detalhes de domínio. O número exato de cache breakpoints e TTLs por provider, e limites de janela por modelo, mudam com frequência — consulte os guias de provider e a folha de fatos antes de afirmar valores específicos.
  • +
+
+ +
+
+ +
+
+
+
Estado, Contexto & Memória Núcleo agnóstico de agentes
+

+ Capítulo de estado do núcleo agnóstico, construído a partir da documentação oficial pública em + 2026-06-10. Para fatos perecíveis (controles de reasoning, janelas, retenção), + consulte os guias de provider e as + fontes oficiais. +

+
+
+
Crédito de produção
+
Gerado por subagentes Claude Opus 4.7 (xhigh)
+
revisão e montagem pelo orquestrador · 2026-06-10
+
+ Núcleo · agnóstico de provider + Conceitual + referência +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_ferramentas_mcp_rag.html b/references/agents_tools_best_guides/guia_ferramentas_mcp_rag.html new file mode 100644 index 0000000..211f5ee --- /dev/null +++ b/references/agents_tools_best_guides/guia_ferramentas_mcp_rag.html @@ -0,0 +1,1001 @@ + + + + + +Ferramentas, MCP & RAG — Núcleo agnóstico de agentes + + + + + + + + +
+
+
Ferramentas, MCP & RAG Núcleo agnóstico de agentes
+
+ Verificado em 2026-06-25 + Núcleo · agnóstico de provider + Conceitual + referência + +
+
+
+ +
+ + +
+ +
+

Ferramentas, MCP & RAG

+

+ Ferramentas são superfície de autoridade. Este capítulo trata cada tool como + uma capability versionada com contrato de entrada e saída, side-effect level, aprovação, timeout, + idempotência, provenance e política de dados. Cobre a fronteira formal do MCP (spec + 2025-11-25), RAG como capability (não despejo de chunks), envelopes de resultado, + segurança, aprovação humana e métricas — tudo agnóstico de provider. +

+
+ Núcleo · agnóstico de provider + Conceitual + referência + SOTA · verificado 2026-06-25 +
+
+ +
+

Sobre este guia

+

+ Este é um guia para IA e humanos: combina o modelo conceitual de ferramentas + como capabilities com contratos tipados prontos para copiar (capability, tool result envelope, + schema estrito) e tabelas de decisão de segurança. A prosa é em PT-BR; nomes de campos, + parâmetros e código permanecem em inglês. +

+
+ Princípio central: o modelo solicita ações; o runtime autoriza, + valida e executa. Credenciais, tenant_id confiável e a aprovação final nunca + vêm de campos preenchidos pelo modelo — vêm do runtime, do usuário autenticado ou de um workflow + humano. Esse é o mesmo invariante do + capability registry do + capítulo de arquitetura; aqui ele é aplicado a tools, MCP e RAG. +
+
+ Fronteira de escopo (cross-link, sem duplicar): a mecânica completa de + paralelismo de tools por provider (schedulers, truth tables, built-ins) vive em + Paralelismo & tools; a + leitura de PDF, imagem e planilha em profundidade vive em + Multimodal. Aqui tratamos do contrato e da + fronteira de segurança — o que vale para qualquer provider. +
+
+ +
+

Fontes & verificação

+

+ Os fatos perecíveis (parâmetros de tools, versão da spec MCP, restrições de paralelismo) foram + conferidos contra a documentação oficial em 2026-06-10 e consolidados na folha + de fatos SOTA do projeto. Os contratos de dados (capability, envelope, schema) são recomendações + de engenharia derivadas dos padrões oficiais. +

+
+ + + + + + + + + +
TemaFonte oficial
OpenAI — tools (built-ins, function tools, MCP remoto, tool search)developers.openai.com/api/docs/guides/tools
OpenAI — function calling (parallel_tool_calls, tool_choice)developers.openai.com/api/docs/guides/function-calling
MCP — especificação 2025-11-25 (arquitetura host/client/server)modelcontextprotocol.io/specification/2025-11-25
MCP — tools (schemas, structuredContent, outputSchema, HITL).../2025-11-25/server/tools
MCP — elicitation (consentimento/entrada do usuário).../2025-11-25/client/elicitation
Google — document processing (assets multimodais)ai.google.dev/gemini-api/docs/document-processing
+

+ Legenda dos selos: Verificado confirmado na doc oficial · + Novo recurso recente · + UNVERIFIED não confirmado dentro do orçamento de verificação · + N/D não documentado. +

+
+ +
+

Mapa do núcleo — onde cada assunto mora

+
+ + + + + + + + + + + +
Você procura…Vá para
Primitivos, capability registry, active plan, skeleton de loopNúcleo · Arquitetura & orquestração
Ledger canônico, compaction, asset registry detalhado, budgetsNúcleo · Estado, contexto & memória
Parâmetros de provider, adapters, structured output por APINúcleo · Providers & adapters
Guardrails, tracing/cost ledger, evals, runbooks, threat modelNúcleo · Operação, segurança & evals
Paralelismo de tools (scheduler, built-ins, truth tables) por providerParalelismo & tools
Leitura de PDF/imagem/planilha, visual RAG, OCRMultimodal
Construir um MCP server do zero (TypeScript/Python, spec 2025-11-25)skill mcp-server-builder
MCP por framework (Agents SDK / Claude / Deep Agents / ADK)Agents SDK · Claude API · Deep Agents · Google ADK
+
+ + +
+

Parte 1 — Capabilities & fronteiras

+

A taxonomia das ferramentas, como a OpenAI separa fases de execução, o MCP como fronteira formal + de segurança e o RAG tratado como capability — não como despejo de chunks.

+
+ +
+

1. Ontologia de tools e capabilities

+

+ "Tool" é um termo sobrecarregado. Antes de projetar segurança ou paralelismo, separe os tipos — + cada um tem fronteira de execução e risco diferentes. Todos são registrados sob o mesmo + contrato de capability; o que + muda é onde o código roda e quem é responsável por validá-lo. +

+
+ + + + + + + + + +
TipoOnde executaQuem valida/autorizaRisco característico
Function toolNo cliente/orquestrador.O seu runtime (schema + regra de negócio).Schema vago, side effect sem aprovação, output gigante.
Provider built-inNo lado do provider (web/file/code).O provider executa; você governa exposição e billing.Presumir retenção/ZDR/paralelismo sem validar a doc.
MCP toolEm um servidor MCP (host/client/server).O host controla permissões; o servidor resolve auth.Tratar MCP como túnel irrestrito para ações perigosas.
MCP resourceServidor MCP expõe dado/documento.O host filtra por tenant e minimiza exposição.Recurso retornado tratado como instrução (injection).
RAG (capability)No retriever/index, atrás de uma tool.O runtime reduz, atribui provenance e aplica caps.Injetar chunks brutos como verdade automática.
Agent-as-toolSubagente chamado como tool.O parent envia pacote mínimo e consome envelope.O child despejar histórico bruto no parent.
+
+ Por que isso importa para segurança: a fronteira de execução define quem pode + injetar instruções no agente. Um resource MCP e um chunk de RAG são dados não confiáveis + — nunca comandos. Esse princípio reaparece no + hardening de MCP (§11) e na + segurança de ferramentas (§8). +
+
+ +
+

2. Tools OpenAI: built-ins, functions e fases de execução

+

+ Na Responses API, tools pode incluir built-ins, MCP tools e function tools; + tool_choice controla a seleção; parallel_tool_calls permite que o modelo + emita várias function calls; max_tool_calls limita as chamadas de built-in + processadas numa response. A documentação oficial ressalta que parallel function calling + não é possível ao usar built-in tools — então o padrão seguro é separar fases. +

+
+ + Separação de fases de execução de tools + Fase A: recuperação e built-ins permitidos. Fase B: funções externas paralelizáveis. Fase C: síntese sem novas tools perigosas. + + + + Fase A + recuperação / built-ins + permitidos + obter evidências e registrar + + Fase B + funções externas + paralelizáveis + client-side · validação · caps + + Fase C + síntese + sem novas tools perigosas + resposta com citações + + + +
A separação de fases melhora a previsibilidade, reduz loops e evita que uma built-in + consuma orçamento antes das function calls necessárias. Built-ins e function calls paralelas não + coexistem no mesmo boundary.
+
+
+ Limite verificado: "parallel function calling não é possível ao usar built-in + tools" é uma restrição atual da OpenAI (folha de fatos SOTA, 2026-05-25). A mecânica completa de + paralelismo — quem paraleliza o quê em cada provider, schedulers recomendados, truth tables — está + em Paralelismo & tools. + Aqui fica apenas o padrão de orquestração (fases). +
+ +
+ +
+

3. MCP como fronteira formal

+

+ O Model Context Protocol define uma arquitetura host/client/server sobre JSON-RPC, com tools, + resources, prompts e outras primitivas. Use MCP quando quiser expor capabilities reusáveis para + muitos agentes/hosts, com schemas e fronteiras de segurança claras. Não use MCP + como desculpa para expor um shell irrestrito. A versão alvo do super-guia é a spec + 2025-11-25. +

+
+ Próxima revisão MCP — alvo 2026-07-28 (ainda em draft; mudanças seguem entrando até a publicação — verificado 2026-06-11): protocolo + stateless sem handshake initialize/Mcp-Session-Id (versão, + identidade e capabilities passam a viajar em _meta), novo server/discover, + subscriptions/listen (substitui o GET e resources/subscribe/unsubscribe), Tasks vira a extensão io.modelcontextprotocol/tasks + e Roots/Sampling/Logging ficam deprecados. Itens mais recentes do draft: MRTR (Multi Round-Trip Requests, SEP-2322 — substitui requests iniciadas pelo servidor como sampling/createMessage por inputRequests/inputResponses), interface CacheableResult (ttlMs/cacheScope em tools/list & afins, SEP-2549), headers obrigatórios Mcp-Method/Mcp-Name no Streamable HTTP, e deprecação do OAuth Dynamic Client Registration (RFC 7591) em favor de Client ID Metadata Documents. No SDK Python, o mcp v2.0.0a1 (alpha, 2026-06-11) antecipa a arquitetura nova — FastMCP renomeado para MCPServer, pipeline Dispatcher no lugar de ServerSession; v2.0.0 estável tem alvo em 2026-07-28, junto com a spec. Planeje a adoção desde já; a 2025-11-25 + segue sendo a revisão vigente hoje (SDK estável: mcp 1.27.2). +
+
+ + Arquitetura host/client/server do MCP + Um host agentic com três clients MCP, cada um falando com um servidor MCP distinto: conhecimento interno, ações de negócio e ferramentas de arquivo. + + + + Host agentic + permissões · consentimento · agregação + MCP client A + MCP client B + MCP client C + server: conhecimentoresources + tools read-only + server: açõestools write (HITL) + server: arquivossandbox + allowlist + + + + + + + +
O host controla permissões, consentimento e agregação. Cada servidor declara suas + capabilities no lifecycle e recebe apenas o necessário — nunca a conversa inteira.
+
+
+ + + + + + + + +
PrimitivaLadoUso corretoRegra de segurança
ToolservidorAção ou consulta invocável pelo modelo.Classificar side effect e exigir aprovação quando necessário.
ResourceservidorDado ou documento acessível pelo host/modelo.Filtrar por tenant e minimizar exposição; resource é dado, não comando.
PromptservidorTemplate/rotina controlada pelo servidor.Versionar e auditar mudanças.
SamplingclienteCapability de cliente: o servidor pede ao cliente para rodar uma completação de LLM.Controlar consentimento/escopo; o host media o modelo — servidor não chama o modelo direto.
ElicitationclienteCapability de cliente: o servidor solicita input estruturado ao usuário via cliente.Introduzida em 2025-06-18 (2025-11-25 refina: modo URL, schema/result). Não é o mecanismo geral de aprovação de tools perigosas — isso é separado (host/HITL).
+
+ Atribuição de versão (precisa). Nem tudo é "novo" na 2025-11-25: o + Streamable HTTP e o framework OAuth entraram em + 2025-03-26; structured tool output, OAuth Resource Server + (Protected Resource Metadata + Resource Indicators) e elicitation entraram em + 2025-06-18. A revisão 2025-11-25 adiciona, entre outros, + consentimento incremental de escopo, descoberta OIDC, elicitation em modo URL e o default de + JSON Schema 2020-12. Cite a revisão certa ao afirmar um recurso. +
+
+ Construir um servidor MCP: a skill mcp-server-builder guia a + implementação em TypeScript/Python contra a spec 2025-11-25 (Streamable HTTP, OAuth com + consentimento incremental de escopo, paginação, tratamento de erros). A integração de MCP em cada + framework está nos guias de framework (ver mapa acima). +
+ +
+ +
+

4. RAG como capability, não como despejo de chunks

+

+ O padrão recomendado é encapsular RAG como uma capability com contrato de input/output. A tool + deve retornar um objeto reduzido, com evidências, citações, scores, freshness, + limitações e campos adequados à síntese. Não injete chunks brutos indiscriminadamente — chunks com + score não viram verdade automática, e documentos podem conter prompt injection. +

+
{
+  "query": "string",
+  "filters": {"tenant_id": "derived_by_runtime", "doc_types": ["policy", "ticket"]},
+  "max_evidence_items": 8,
+  "freshness_required": "2025-01-01..present",
+  "return": {
+    "answerable": true,
+    "summary": "síntese curta do que foi encontrado",
+    "evidence": [
+      {"source_id": "doc:abc", "span": "p. 3 §2", "quote": "trecho curto", "score": 0.82, "hash": "..."}
+    ],
+    "missing_evidence": [],
+    "confidence": "medium"
+  }
+}
+
+ RAG é conteúdo novo neste super-guia — nenhum guia dedicado o cobre. O contrato + acima atravessa quatro pontos: filters.tenant_id derivado pelo runtime (não pelo + modelo); evidence com source_id/span/hash para + citação verificável; answerable/missing_evidence para forçar lacuna + explícita em vez de alucinação; e max_evidence_items como cap de contexto. As + métricas de RAG (§12) medem cada um desses campos. +
+
+ + +
+

Parte 2 — Contratos de tool

+

O envelope tipado que todo resultado de ferramenta deve usar, as regras de design do schema de + entrada e o tratamento de multimodal como asset.

+
+ +
+

5. Tool result envelopes

+

+ Todo resultado de ferramenta deve voltar em um envelope com status, dados reduzidos, erros, + provenance e limites. Mesmo uma falha é evidência operacional e deve ser + registrada — nunca silenciada. +

+
+ Este é um payload de aplicação, não o envelope MCP de fio. O contrato abaixo é a + forma recomendada do super-guia para o conteúdo de um resultado de tool. No protocolo MCP, + o resultado de tools/call (CallToolResult) usa content[] + (blocos), structuredContent (dados tipados) e isError. Ao expor isto via + MCP, coloque este objeto em structuredContent (e espelhe um resumo em + content[]) — não o devolva como se fosse o CallToolResult inteiro. +
+
{
+  "tool_result": {
+    "tool_call_id": "call_123",
+    "capability_id": "read_spreadsheet.v1",
+    "status": "success | partial | error | denied | timeout",
+    "summary": "o que a ferramenta encontrou em até N tokens",
+    "data": {"rows_sampled": 100, "columns": ["..."], "findings": []},
+    "provenance": [{"asset_id": "asset_1", "sheet": "Q1", "range": "A1:G120", "sha256": "..."}],
+    "tokens_estimate": 700,
+    "redactions": ["tenant_secret", "personal_identifier"],
+    "next_allowed_actions": ["ask_user", "query_more", "finalize"]
+  }
+}
+
+ Por que next_allowed_actions: o envelope não só devolve dados — ele + guia o próximo passo do loop dentro da política. Combinado com o + status estruturado, permite autocorreção (em error/partial) + sem vazar segredos e sem o modelo inventar a próxima ação. O envelope é ingerido no ledger do + capítulo de estado. +
+
+ +
+

6. Regras de design de schema de tool

+

O schema de entrada é a primeira linha de defesa. Schemas frouxos transferem decisão de segurança + para o modelo — exatamente o que se quer evitar.

+
    +
  • ☐ Use nomes de campos específicos, não data, payload ou query genéricos sem constraints.
  • +
  • ☐ Defina enums para modos críticos; evite strings livres para ações perigosas.
  • +
  • ☐ Separe filtros sugeridos pelo modelo de filtros impostos pelo runtime.
  • +
  • ☐ Adicione dry_run, idempotency_key e approval_token quando houver side effect.
  • +
  • ☐ Retorne status estruturado: success, partial, error, denied, timeout.
  • +
  • ☐ Inclua provenance e limites de confiança; não retorne apenas texto narrativo.
  • +
+
{
+  "type": "object",
+  "additionalProperties": false,
+  "required": ["subject", "intent", "max_results"],
+  "properties": {
+    "subject": {"type": "string", "minLength": 3, "maxLength": 200},
+    "intent": {"type": "string", "enum": ["retrieve", "compare", "summarize"]},
+    "max_results": {"type": "integer", "minimum": 1, "maximum": 10}
+  }
+}
+
+ additionalProperties: false quando suportado. Schema estrito impede + que o modelo "invente" campos que o runtime não validou. A aderência ao schema (structured output) + por provider — OpenAI text.format, Anthropic output_config.format, + Gemini response_json_schema — está no + capítulo de providers. O inputSchema de uma + tool MCP é JSON Schema válido; mas os schemas de structured output de cada provider + aceitam apenas subconjuntos de JSON Schema (constraints como minimum/ + maxLength podem ser ignoradas ou rejeitadas) — valide contra o subconjunto do provider, + não assuma portabilidade 1:1. +
+
+ +
+

7. Multimodal: o princípio (e o cross-link)

+

+ A regra universal de multimodal é simples: arquivos entram por um asset registry, não + pelo prompt. Tipo, tamanho, hash, classificação, origem, permissões, parser usado, versão + do parser e provenance de trechos viram metadados; o modelo recebe somente a projeção útil ao + turno. O pipeline: +

+
upload/anexo
+  → asset registry + hash + classificação
+  → escolha de parser: texto nativo | visão multimodal | tabela/planilha | OCR de último recurso
+  → extração com provenance e bounding/posição quando aplicável
+  → redução / caps
+  → RAG ou tool result tipado
+  → projeção mínima ao modelo
+
+ Profundidade no guia dedicado. Como extrair PDF textual vs escaneado, quando usar + visão direta vs OCR de último recurso, leitura de planilha sem despejar o workbook, visual RAG e + reidratação de imagens antigas, e os detalhes operacionais por SDK estão inteiramente em + Multimodal. O asset registry em si (campos, + projection_policy) está no + capítulo de estado. Aqui multimodal + é só uma fonte de tool results/evidência tipada — não reescrevemos o guia dedicado. +
+
+ Código/shell nunca por sugestão do modelo: execução de código, shell ou rede vai + para sandbox com allowlist, timeout e captura de stdout/stderr — e jamais executa comandos + sugeridos pelo modelo sem política. Ver segurança de + ferramentas (§8). +
+ +
+ + +
+

Parte 3 — Segurança & operação

+

Níveis de risco e política mínima por tool, o fluxo de aprovação com human-in-the-loop, o controle + de fan-out/wind-down, o hardening de servidores MCP e as métricas de RAG.

+
+ +
+

8. Segurança de ferramentas

+

Classifique cada tool por side-effect level e aplique a política mínima correspondente. O nível + decide o grau de automação aceitável.

+
+ + + + + + + + +
NívelExemplosPolítica mínima
none / read-onlyBusca, leitura de docs, cálculo local sem side effect.Auto permitido com caps e logging.
write_lowCriar rascunho, salvar nota, gerar arquivo local.Auto ou aprovação leve conforme contexto.
write_highEnviar mensagem, alterar registro, atualizar sistema externo.Aprovação explícita e preview.
financial / legal / securityPagamento, contrato, acesso, deleção, permissão.Human-in-the-loop obrigatório, idempotência e dupla validação.
dangerous executionShell, rede, código arbitrário, acesso a secrets.Sandbox, allowlist, bloqueio por padrão e revisão.
+
    +
  • ☐ Argumentos de tool são validados por schema e por regra de negócio.
  • +
  • ☐ Auth/tenant vêm do runtime, nunca de campos livres preenchidos pelo modelo.
  • +
  • ☐ Tool outputs têm limite de tamanho e redaction antes de voltar ao modelo.
  • +
  • ☐ Side effects são idempotentes ou têm confirmação humana.
  • +
  • ☐ Traces registram quem pediu, quem aprovou, o que executou e o que retornou.
  • +
+
+ Cross-link: os guardrails de entrada/tool/saída em três pontos, o threat model de + agentes (prompt injection, confused deputy, BOLA/IDOR em tools) e os gates de eval de segurança + estão em Operação, segurança & evals. +
+
+ +
+

9. Fluxo de aprovação de tool (HITL)

+

+ O caminho de uma tool call, do emissor (modelo) até o ledger, passa por validações que o modelo + não controla. O modelo nunca fornece credenciais, tenant_id confiável ou a aprovação + final. +

+
model emits tool_call
+  → schema validation
+  → policy validation
+  → side-effect classification
+  → auth/tenant injection by runtime
+  → human approval if required
+  → execution in sandbox/client/server
+  → reduced tool_result
+  → ledger + trace + projection
+
+ Timing da aprovação importa. Para side effects altos, a aprovação deve ser + block-until-validated (a execução só ocorre após o humano aprovar), não assíncrona depois + do fato. O MCP 2025-11-25 prevê elicitation para coletar consentimento/entrada do + usuário; tools MCP devem expor indicadores claros ao usuário quando invocadas. O HITL por + framework (interrupt do LangGraph, Tool Confirmation do ADK, approvals do Agents SDK) está nos + guias de framework. +
+ +
+ +
+

10. Fan-out e wind-down

+

+ Fan-out é útil para pesquisa, RAG multi-índice, avaliação multi-modelo ou subagentes especialistas + — mas deve ser encerrado por política. O runtime precisa saber quando parar de + abrir novas chamadas e reservar orçamento para a síntese. +

+
if tokens_remaining < final_reserve_tokens:
+    disable_new_tools()
+    synthesize_from_current_evidence()
+
+if fanout_results_total_tokens > aggregate_cap:
+    rank_reduce_before_parent_ingest()
+
+if tool_errors_consecutive >= threshold:
+    switch_strategy_or_ask_user()
+
+ Wind-down é o par do fan-out. Abrir muitas chamadas sem reservar a resposta final + é o antipadrão "sem wind-down" do + capítulo de arquitetura. O + final_reserve_tokens vem do active plan; a reserva inclui reasoning/thinking (ver + budgets). A latência e o + custo do fan-out por provider estão em + Paralelismo & tools. +
+
+ +
+

11. Hardening de MCP server

+

+ A especificação MCP destaca consentimento, controle do usuário, privacidade e segurança de + ferramentas. Estes são os controles operacionais que transformam esses princípios em prática: +

+
+ + + + + + + + + + + + + + +
ControleImplementação prática
Tool allowlistExpor somente as tools necessárias ao host/agent.
Auth contextualResolver usuário/tenant no servidor ou gateway, não por argumento livre.
Rate limitLimites por tool, tenant e agent.
Output capsReduzir respostas grandes antes de retornar ao host.
Audit logRegistrar request_id, actor, tool, args hash, status e duration.
Prompt-injection boundaryRecursos retornados são dados, não instruções.
Human-in-loopObrigatório para side effects altos.
Transporte (Streamable HTTP)Validar o header Origin (responder 403 a origens inválidas) contra DNS rebinding; em servidor local, fazer bind em 127.0.0.1, não 0.0.0.0; autenticar toda conexão; honrar MCP-Protocol-Version.
SessãoMcp-Session-Id não-determinístico e seguro; sessão não é mecanismo de auth — autenticar cada request.
OAuth (Resource Server)Validar audience/resource do token (Resource Indicators, RFC 8707); expor Protected Resource Metadata; nunca repassar tokens de terceiros (token passthrough proibido); consentimento incremental de escopo (2025-11-25).
SSRF na descobertaAo buscar metadata OAuth/cards, bloquear IPs privados/link-local e cadeias de redirect; allowlist de hosts.
+
+ O confused deputy do MCP: um servidor MCP que confia em tenant_id + vindo de um argumento livre pode ser induzido por prompt injection a operar no contexto de outro + tenant. Resolva auth/tenant no servidor ou gateway a partir de claims autenticados — + nunca de um campo que o modelo preenche. +
+ +
+ +
+

12. Métricas para RAG e leitura de arquivos

+

Cada métrica mapeia a um campo do envelope de RAG (§4) e a um gate + de qualidade. Sem elas, "o RAG funciona" é uma afirmação não verificável.

+
+ + + + + + + + + +
MétricaO que medeComo usar
citation_precisionSe as citações suportam as alegações.Gate antes da resposta final.
recall@kSe as evidências relevantes aparecem entre os top-k.Tuning de retriever/ranker.
freshnessIdade das fontes usadas.Filtrar ou marcar incerteza.
chunk_coverageCobertura de páginas/abas/seções importantes.Detectar leitura parcial.
answerabilitySe há evidência suficiente para responder.Forçar pergunta ao usuário ou lacuna explícita.
parser_error_rateFalhas de extração por tipo de arquivo.Escolher parser/visual model/OCR.
+
+ Onde estes gates rodam: citation_precision e + answerability correspondem aos gates RAG-001 e SEC-001 + (prompt injection) do capítulo de operação. + Métricas de retrieval mais profundas (nDCG, MRR, faithfulness) e tuning de retriever são domínio + de RAG dedicado — a skill rag-systems cobre a engenharia de retrieval em detalhe. +
+
+ + +
+

Checklist de tools, MCP & RAG

+

Gate antes de promover qualquer superfície de ferramentas para produção:

+
    +
  • ☐ Cada tool é uma capability versionada com contrato de entrada/saída, side-effect level e approval policy.
  • +
  • ☐ Built-ins e function calls paralelas não coexistem no mesmo boundary (fases separadas).
  • +
  • ☐ Servidores MCP expõem allowlist mínima; auth/tenant resolvidos no servidor/gateway.
  • +
  • ☐ RAG retorna envelope reduzido com provenance, score, freshness e answerable — não chunks brutos.
  • +
  • ☐ Todo tool result usa envelope tipado com status e provenance, inclusive falhas.
  • +
  • ☐ Side effects altos exigem HITL block-until-validated, idempotency key e preview.
  • +
  • ☐ Resources MCP e chunks de RAG são tratados como dados não confiáveis (boundary de injection).
  • +
  • ☐ Fan-out tem aggregate cap e wind-down que reserva a resposta final.
  • +
  • ☐ Métricas de RAG/arquivo (citation precision, answerability, parser error rate) são gates.
  • +
+
+ +
+

Notas de verificação

+
    +
  • Resolvido Spec MCP = 2025-11-25. Versão alvo reconfirmada contra a doc oficial em 2026-06-10; as primitivas (tools/resources/prompts) e o fluxo HITL valem nesta revisão. structuredContent/outputSchema e elicitation foram introduzidos em 2025-06-18 — a 2025-11-25 refina (ver "Atribuição de versão" no §3). SDK Python de referência: mcp 1.27.2 (PyPI, 2026-06-10).
  • +
  • Resolvido Parallel function calling × built-ins (OpenAI). "Parallel function calling não é possível ao usar built-in tools" — confirmado contra a doc oficial de tools/function calling; daí o padrão de fases.
  • +
  • Resolvido Sem duplicação. Paralelismo profundo fica em Paralelismo & tools; leitura multimodal fica em Multimodal; engenharia de retrieval fica na skill rag-systems. Aqui só o contrato e a fronteira.
  • +
  • Resolvido Sem IDs de modelo fixos. O capítulo cita parâmetros (perenes) e tipos de tool, não modelos (perecíveis).
  • +
  • UNVERIFIED Detalhes de built-ins por provider. O conjunto exato de hosted/built-in tools (web search, file search, code interpreter, computer use, image gen) e suas restrições muda com frequência — consulte os guias de provider e a folha de fatos antes de afirmar disponibilidade específica.
  • +
+
+ +
+
+ +
+
+
+
Ferramentas, MCP & RAG Núcleo agnóstico de agentes
+

+ Capítulo de ferramentas do núcleo agnóstico, construído a partir da documentação oficial pública + em 2026-06-10. Para fatos perecíveis (built-ins por provider, versão de spec), + consulte os guias de provider e as + fontes oficiais. +

+
+
+
Crédito de produção
+
Gerado por subagentes Claude Opus 4.7 (xhigh)
+
revisão e montagem pelo orquestrador · 2026-05-25
+
+ Núcleo · agnóstico de provider + Conceitual + referência +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_file_inputs_no_storage.html b/references/agents_tools_best_guides/guia_file_inputs_no_storage.html new file mode 100644 index 0000000..03dc03e --- /dev/null +++ b/references/agents_tools_best_guides/guia_file_inputs_no_storage.html @@ -0,0 +1,1314 @@ + + + + + +File Inputs sem Provider Storage + Hosted Execution — Núcleo + + + + + + + + +
+
+
File Inputs sem Provider Storage Núcleo agnóstico · super-guia de agentes
+
+ Verificado em 2026-06-11 + Núcleo · v1 + Modo A estrito + Modo B hosted + +
+
+
+ +
+ + +
+ +
+

File Inputs sem Provider Storage + Hosted Execution

+

+ Como entregar arquivos (imagem, PDF, planilha, áudio, vídeo) a um agente sem deixar estado + retido do lado do provider — o caminho exigido por cargas ZDR/PHI — e como, quando a política + permitir, usar execução hospedada (Code Interpreter, Hosted Shell, code execution) de + forma explicitamente não-estrita. Define dois modos operacionais (A estrito · B hosted opcional), a + disciplina de proveniência SourceRecord/EvidenceCard, a regra de payload por + turno, o pipeline de imagem da web e os adapters em OpenAI, Gemini e Anthropic sobre Agents SDK, + LangGraph, Deep Agents e Google ADK. Formatos/limites e retenção por provider têm dono próprio na + coleção e são cross-linkados, não duplicados. +

+
+ Núcleo · v1 + OpenAI · Gemini · Anthropic + SOTA · verificado 2026-06-10 +
+
+ +
+

Sobre este guia

+

+ Este é um guia para IA e humanos: combina o "quando usar" com referência rápida (tabelas, + schemas e código copy-paste). Ele responde a uma pergunta que os guias de capacidade não respondem: + como ingerir arquivos sensíveis ponta-a-ponta sem que o provider retenha cópia, e quando é aceitável + abrir mão disso para ganhar execução hospedada. O como envio uma imagem/PDF e quais os + limites é dono do guia Multimodal; a retenção/ZDR e os + guardrails em geral são donos do guia Operação, + Segurança & Evals. Aqui o conteúdo primário é a política de ingestão sem provider storage e + a disciplina de proveniência que a torna auditável. +

+
+ Tese: o arquivo bruto é uma projeção temporária dentro do payload de um turno — + não um objeto que vive no provider. A fonte da verdade é o seu SourceRegistry (application-owned); + o modelo recebe só o que precisa inspecionar naquele passo, sempre com proveniência, e devolve + EvidenceCards com source_id — nunca um arquivo retido. +
+
+ Vizinhança no super-guia: formatos, limites e deep dive por provider em + Multimodal · OpenAI, + Gemini e + Anthropic; ZDR/retenção e o contrato de privacidade por rota + em Operação · Privacidade, retenção e + ZDR; o ledger canônico e a regra "payload é projeção" em + Estado, contexto & memória. +
+
+ +
+

Fontes & verificação

+

+ Todo fato perecível (limites, parâmetros, strings de versão, elegibilidade ZDR) foi conferido contra a + documentação oficial em 2026-06-10 por um time de validação com debate cruzado, ou anotado + como UNVERIFIED nas notas de verificação. Os + exemplos usam apenas modelos atuais (gpt-5.5, gemini-3.5-flash, + claude-opus-4-8). +

+
+ + + + + + + + + + + +
TemaRecurso oficial
OpenAI — file inputsdevelopers.openai.com/api/docs/guides/file-inputs
OpenAI — images & visiondevelopers.openai.com/api/docs/guides/images-vision
OpenAI — data controls / ZDRdevelopers.openai.com/api/docs/guides/your-data
OpenAI — Code Interpreter / Hosted Shelltools-code-interpreter · tools-shell
Gemini — Interactions APIai.google.dev/gemini-api/docs/interactions
Gemini — Zero Data Retentionai.google.dev/gemini-api/docs/zdr
Anthropic — Vision / PDFvision · pdf-support
Anthropic — data retention / Code executionapi-and-data-retention · code-execution-tool
+

+ Legenda dos selos: Verificado confirmado na doc oficial em 2026-06-10 · + Novo recurso/versão recente · + UNVERIFIED não confirmado em URL oficial direta (fonte/lacuna anotada) · + Evitar proibido no Modo A / antipadrão. +

+
+ + +
+

Parte 1 — A política

+

+ Antes de qualquer código: decida em qual modo a rota opera, declare o que é proibido do lado do provider e + escolha o caminho de transporte do arquivo. Essas três decisões são a diferença entre um sistema auditável + e um vazamento silencioso de retenção. +

+
+ +
+

1. Dois modos operacionais

+

+ A maior fonte de confusão em ingestão de arquivos sensíveis é tratar "execução hospedada" como se fosse o + mesmo que "sem retenção". Não é. Separe explicitamente dois modos e registre o run_mode em cada + execução. +

+
+ + + + + +
ModoDefiniçãoStatus para PHI/ZDR estrito
Modo A — direct payload / no provider storageArquivos entram como base64 inline, signed URL efêmera controlada pela aplicação, ou chunks/evidências geradas pela aplicação. Sem Files API, file_id, vector store, background, provider containers.Recomendado para o caminho sensível. Ainda exige contrato ZDR/BAA quando aplicável.
Modo B — hosted execution opcionalUsa Code Interpreter, Hosted Shell, code execution ou containers gerenciados para executar código/processar arquivos do lado do provider.Não é o modo estrito. Útil para Excel/cálculo, mas exige análise de retenção. Em Anthropic Code Execution, não é ZDR elegível.
+
+ Armadilha número um: store=false controla o estado da resposta/conversa — não + garante que um container hospedado não tenha filesystem temporário durante a execução. Um container do Modo B + pode escrever estado temporário enquanto ativo, mesmo com store=false. +
+
+ +
+

2. Escopo e garantias

+

+ Este guia é um blueprint auditável, não uma garantia legal. A garantia real vem de testes + automáticos (§17) que bloqueiam file_id, Files API, vector stores, background, previous IDs e + containers hospedados quando o run exige Modo A — e que marcam run_mode=hosted_optional_non_strict + sempre que alguma ferramenta hospedada é usada. +

+
+ ZDR no provider ≠ ZDR no seu sistema. Se você guarda o SourceRegistry, os + traces e o ledger sem redaction, você ainda retém o dado — só mudou de lugar. A política de retenção interna + precisa ser tão explícita quanto a do provider. Ver + Operação · Privacidade, retenção e ZDR. +
+
+ +
+

3. Modo A — política sem provider storage

+

+ Declare, por provider, o transporte permitido e o que é proibido do lado do provider. Esta política vira + configuração e é enforced pelos evals da §17. +

+
MODE_A_STRICT_NO_PROVIDER_STORAGE:
+  allowed_transport:
+    - inline_base64_in_request
+    - short_lived_signed_url_controlled_by_application
+    - application_generated_text_chunks
+    - application_generated_csv_json_markdown
+    - application_generated_pdf_page_render_or_image_crop
+    - application_owned_worker_for_code_shell_ocr_spreadsheet_parsing
+  forbidden_provider_side:
+    openai:
+      - Files API /v1/files
+      - file_id in input_file/input_image
+      - File Search / vector stores / retrieval API stores
+      - hosted Code Interpreter for user files
+      - Hosted Shell containers for user files
+      - background mode as context strategy
+      - previous_response_id as source of truth
+    gemini:
+      - Files API upload
+      - uploaded_file.uri
+      - File Search stores
+      - cached_content for user files
+      - background=true
+      - store=true
+      - previous_interaction_id as source of truth
+      - Google Search / Maps grounding (retains ~30 days)
+    anthropic:
+      - Files API / file_id
+      - code_execution tool for user files
+      - container uploads / generated files in provider containers
+      - Agent Skills if ZDR is required
+      - prompt caching if policy forbids provider-side retained cache
+
+ Por que cada item: a maioria dos recursos da lista forbidden_provider_side cria ou + depende de estado retido no provider — confirmado nas feature-eligibility tables de cada provider (ver §13 e as + notas de verificação). Exceção a registrar: o prompt caching da Anthropic é, + por padrão, ZDR elegível (cache em memória deletado ao fim do TTL); incluí-lo aqui é uma decisão + de política mais estrita, não uma inelegibilidade ZDR. +
+
+ +
+

4. Caminhos permitidos

+
+ + + + + + + + +
CaminhoQuando usarLimite / risco
Base64 inlinePHI/PII, PDFs pequenos/médios, imagens críticas.Payload cresce; precisa de orçamento de tokens/tamanho.
Signed URL efêmeraArquivos não sensíveis ou quando inline seria grande demais.TTL curto, domínio controlado, logs; sem PHI quando a política proíbe.
Chunks / evidências app-sidePDF grande, Excel, RAG interno, OCR.O claim fica limitado ao chunk/evidência fornecido.
Crop / page render app-sideImagem médica dentro de PDF ou detalhe fino.parent_source_id obrigatório.
Worker próprioExcel, código, OCR, Python, shell, geração de arquivos.Mais engenharia, mas mantém o controle de retenção.
+
+ + +
+

Parte 2 — Disciplina de proveniência

+

+ Sem provider storage, a aplicação é a única dona da fonte. Três artefatos tornam isso rastreável: o + SourceRecord (o que é cada fonte), o caption (como ela entra no payload) e a regra + de payload por turno (o que reinjetar em cada passo). +

+
+ +
+

5. SourceRecord

+

Cada arquivo/asset é registrado uma vez no SourceRegistry da aplicação com proveniência completa.

+
type SourceRecord = {
+  source_id: string;
+  kind:
+    | "image_original"
+    | "image_crop"
+    | "image_web_reference"
+    | "pdf"
+    | "pdf_page_render"
+    | "xlsx"
+    | "csv"
+    | "docx"
+    | "pptx"
+    | "text_chunk"
+    | "web_page"
+    | "search_result_text"
+    | "audio"
+    | "video"
+    | "video_frame"
+    | "computed_artifact";
+  role:
+    | "primary_case_image"
+    | "derived_visual_detail"
+    | "textual_context"
+    | "medical_reference_image"
+    | "medical_reference_text"
+    | "tabular_evidence"
+    | "computed_evidence"
+    | "tool_result";
+  title: string;
+  description: string;
+  mime_type?: string;
+  internal_uri: string;              // application-owned storage
+  signed_url?: string;               // short-lived app URL, if used
+  base64?: string;                   // generated just-in-time for request payload
+  external_url?: string;             // source URL if from web
+  source_page_url?: string;          // page where image/doc was found
+  parent_source_id?: string;         // crop/render derived from original/PDF
+  bytes_sha256?: string;
+  perceptual_hash?: string;
+  page_range?: string;
+  sheet_name?: string;
+  pii_phi_class: "none" | "possible_phi" | "confirmed_phi";
+  trust_tier: "user_supplied" | "official_guideline" | "peer_reviewed" | "educational_reference" | "unknown";
+  allowed_use: ("visual_analysis" | "textual_grounding" | "comparison" | "citation" | "computation")[];
+  provider_storage_allowed: false;
+};
+

Política de projeção e campos de reidratação

+

+ Identidade e proveniência não bastam: todo SourceRecord deve carregar uma + política de projeção explícita, que decide se — e como — o conteúdo entra no payload. + Some também os campos que permitem reidratar e orçar tokens sem reanexar o arquivo inteiro. +

+
{
+  "projection_policy": "inline_current_turn",  // | summary | rag_only | blocked
+  "page_count": 42,
+  "token_estimate": 38000,
+  "parsed_ref": "artifact://parsed/src_pdf_123",
+  "parser_version": "pdfx-2.3.1"
+}
+
+ + + + + + + +
projection_policySignificado
inline_current_turnPáginas/blocos entram no payload do turno atual, dentro dos caps; depois saem.
summarySó o digest/EvidenceCard entra; o bruto fica no store.
rag_onlyNunca inline; acesso só via retrieval/reidratação sob demanda.
blockedNão pode ir ao modelo (classificação/retenção/escopo proíbem).
+

+ O bruto (internal_uri) e o parse (parsed_ref + parser_version) ficam + sempre armazenados; o que entra no payload é decisão por tier, turno e budget. page_count e + token_estimate alimentam o cálculo de caps antes de projetar. +

+
+ +
+

6. Caption / contexto

+

Toda fonte entra no payload precedida de um caption que fixa o source_id e as regras de uso.

+
function caption(source: SourceRecord): string {
+  return `[SOURCE ${source.source_id}]
+Kind: ${source.kind}
+Role: ${source.role}
+Title: ${source.title}
+Description: ${source.description}
+Trust tier: ${source.trust_tier}
+Parent source: ${source.parent_source_id ?? "none"}
+External URL: ${source.external_url ?? "n/a"}
+Source page: ${source.source_page_url ?? "n/a"}
+
+Rules:
+- Preserve source_id=${source.source_id}.
+- Do not merge this source with another source.
+- Cite source_id=${source.source_id} for any claim using this source.
+- If this is WEBIMG_REF_*, treat it as educational reference only, not patient evidence.
+- If the raw file/image/chunk is not present in this call, say you cannot inspect it.
+- Do not provide diagnosis; provide observations, evidence, uncertainty, limitations.`;
+}
+
+ +
+

7. Regra de payload por turno

+
+ Regra: mantenha tudo no SourceRegistry/TurnLedger; reinjete no payload + apenas o que o agente/nó/subagente precisa inspecionar naquele passo. A síntese final usa + EvidenceCards, não pixels — salvo uma nova reavaliação explícita. +
+
+ + + + + + + + +
PassoPayload
Visual reviewImagem/crop base64 ou signed URL + caption.
PDF QAPDF base64/signed URL ou chunks/páginas geradas pela aplicação.
ExcelCSV/JSON/Markdown computado; XLSX inline só se suportado e necessário.
SubagenteSubagentInputPacket + fontes explícitas ou tool app-owned.
Síntese finalEvidenceCards + source_ids; sem arquivo bruto salvo reanálise.
+

Páginas inline e token cap por tier (política)

+

+ Os limites por provider documentados adiante (tamanho de arquivo, nº de páginas/imagens) são + tetos físicos da API. Acima deles existe uma camada de política de produto + por tier — quase sempre bem mais restritiva — que decide quantas páginas valem o custo/latência de ficar + inline no turno. Valores ilustrativos, parametrizáveis (recalibrar por densidade de + documento, idioma, modelo e SLO): +

+
+ + + + + + + +
TierPáginas inline/turnoToken cap adicional (sugerido)Observação
Free~1012k–18kDocumento denso: priorizar páginas relevantes.
Plus~3036k–48kPDFs moderados e docs curtos.
Pro~4056k–72kManter no payload durante a interação atual.
Super~6096k–128kSó se modelo/provider e latência permitirem.
+
+ Página vs token. Páginas variam muito de densidade; o scheduler aplica o menor + entre o cap de páginas e o cap de tokens. Depois do turno, o arquivo não permanece bruto no payload por + default — vira EvidenceCard/refs e reidrata sob demanda. A camada de fatias/budget que governa + isso está em Compactação — estratégias + e o contrato em Estado & contexto. +
+
+ + +
+

Parte 3 — Modo A por provider

+

+ Os três providers aceitam arquivos no payload sem armazenamento. O que muda é o formato do bloco. Os + formatos e limites completos são dono do guia Multimodal + · catálogo de limitações; aqui mostramos só o recorte do Modo A. +

+
+ +
+

8. OpenAI Responses — Modo A

+

+ Use input_image e input_file sem file_id: para arquivos, + file_data base64 (com prefixo data URI) ou file_url/signed URL. Use + store=False. O valor detail:"original" é válido (low/high/original/auto) e indicado + para imagem grande/densa/espacial; em gpt-5.5, auto equivale a original. +

+
content = [
+    {"type": "input_text", "text": caption(IMG_ORIG_001)},
+    {
+        "type": "input_image",
+        "image_url": f"data:image/png;base64,{IMG_ORIG_001.base64}",
+        "detail": "original"
+    },
+
+    {"type": "input_text", "text": caption(WEBIMG_REF_001)},
+    {
+        "type": "input_image",
+        "image_url": WEBIMG_REF_001.signed_url,
+        "detail": "high"
+    },
+
+    {"type": "input_text", "text": caption(PDF_001)},
+    {
+        "type": "input_file",
+        "filename": "PDF_001_laudo.pdf",
+        "file_data": f"data:application/pdf;base64,{PDF_001.base64}"
+    },
+
+    {"type": "input_text", "text": caption(CSV_001_SUMMARY)},
+    {"type": "input_text", "text": CSV_001_SUMMARY.markdown},
+
+    {"type": "input_text", "text": FINAL_SOURCE_BOUND_INSTRUCTIONS}
+]
+
+response = client.responses.create(
+    model="gpt-5.5",
+    store=False,                      # sob ZDR, store é sempre tratado como false
+    input=[{"role": "user", "content": content}],
+    text={"format": {"type": "json_schema", "name": "EvidenceCard", "schema": EVIDENCE_SCHEMA}}
+)
+
+ Limites (verificados): até 512 MB de payload e 1500 imagens por + request; cada arquivo input_file < 50 MB e a soma dos arquivos na request ≤ 50 MB. + PDF vision extrai texto + imagem por página. Detalhe completo em + Multimodal · OpenAI. +
+ +
+ +
+

9. Gemini Interactions — Modo A

+

+ Use store=False, background=False e blocos image/document com + data base64 ou uri/signed URL. Se houver combinação de tools em modo stateless, + preserve id/signature entre turnos conforme a documentação. +

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    store=False,
+    background=False,
+    input=[{
+        "type": "user_input",
+        "content": [
+            {"type": "text", "text": caption(IMG_ORIG_001)},
+            {"type": "image", "data": IMG_ORIG_001.base64, "mime_type": "image/png"},
+
+            {"type": "text", "text": caption(WEBIMG_REF_001)},
+            {"type": "image", "uri": WEBIMG_REF_001.signed_url, "mime_type": "image/png"},
+
+            {"type": "text", "text": caption(PDF_001)},
+            {"type": "document", "data": PDF_001.base64, "mime_type": "application/pdf"},
+
+            {"type": "text", "text": caption(CSV_001_SUMMARY)},
+            {"type": "text", "text": CSV_001_SUMMARY.markdown},
+
+            {"type": "text", "text": FINAL_SOURCE_BOUND_INSTRUCTIONS}
+        ]
+    }],
+    # Teto de tokens por mídia de ENTRADA (custo/latência). media_resolution é
+    # interaction-scoped e vive em generation_config (comportamento do modelo),
+    # NÃO em response_format. Forma global suportada na Interactions API.
+    generation_config={"media_resolution": "MEDIA_RESOLUTION_HIGH"}
+)
+
+ Limites inline (verificados): 100 MB por request/payload, sendo 50 MB para PDFs. O schema de + bloco inline {type, data|uri, mime_type} usado acima é exatamente o documentado para a Interactions + API (página file input methods). +
+
+ Resolução de mídia (Verificado na Interactions — forma global): + media_resolution controla o teto de tokens alocados por imagem/PDF de entrada (enum + MEDIA_RESOLUTION_LOW/MEDIUM/HIGH; ULTRA_HIGH só na forma por-part). + A forma global em generation_config.media_resolution é suportada + na Interactions API: generation_config é parâmetro interaction-scoped de + comportamento do modelo (junto de thinking_level, temperature) — é a forma + usada no exemplo acima. A forma por-part (no próprio bloco de mídia) segue documentada + apenas para generateContent (Gemini 3; ainda v1alpha/experimental) — não a + use nos blocos da Interactions. Detalhe em + Multimodal · Gemini. +
+ +
+ +
+

10. Anthropic Messages — Modo A

+

+ Use image com base64/URL e document (PDF) com base64/URL. Não use file_id + se o run exige Modo A. O document aceita title, context e + citations. +

+
message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=2500,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text", "text": caption(IMG_ORIG_001)},
+            {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": IMG_ORIG_001.base64}},
+
+            {"type": "text", "text": caption(WEBIMG_REF_001)},
+            {"type": "image", "source": {"type": "url", "url": WEBIMG_REF_001.signed_url}},
+
+            {"type": "text", "text": caption(PDF_001)},
+            {
+                "type": "document",
+                "source": {"type": "base64", "media_type": "application/pdf", "data": PDF_001.base64},
+                "title": "PDF_001_LAUDO",
+                "context": "Laudo textual; use as context, not as primary visual source.",
+                "citations": {"enabled": True}
+            },
+
+            {"type": "text", "text": caption(CSV_001_SUMMARY)},
+            {"type": "text", "text": CSV_001_SUMMARY.markdown},
+
+            {"type": "text", "text": FINAL_SOURCE_BOUND_INSTRUCTIONS}
+        ]
+    }]
+)
+
+ Limites (verificados): request máximo 32 MB; até 600 páginas de PDF + (100 para modelos com janela de 200k) e até 600 imagens por request (100 para modelos 200k). + GIF animado usa só o primeiro frame. PDF vision = texto extraído + imagem por página. Detalhe em + Multimodal · Anthropic e + Claude API · PDF. +
+
+ ZDR vs HIPAA: PDF inline via Messages API é ZDR elegível (e a elegibilidade + HIPAA aplica a PDFs inline, não via Files API). Para PHI, além de ZDR, a Anthropic oferece HIPAA readiness via + BAA como alternativa. Ver Claude API · Files. +
+ +
+ + +
+

Parte 4 — Adapters Modo A nos frameworks

+

+ Em qualquer framework, o padrão é o mesmo: a tool/nó chama um strict payload builder por provider, ou + um worker próprio (não uma ferramenta hospedada). Nenhum exemplo abaixo faz upload para o + provider; todos usam responses.create/interactions.create/messages.create + com payload direto. +

+ +

11.1. OpenAI Agents SDK

+
@function_tool
+async def review_sources_no_provider_storage(packet: ReviewSourcesInput) -> str:
+    sources = app.registry.resolve(packet.source_ids)
+
+    if packet.provider == "openai":
+        raw = await openai_client.responses.create(**build_openai_strict_payload(sources, packet))
+    elif packet.provider == "gemini":
+        raw = await gemini_client.interactions.create(**build_gemini_strict_payload(sources, packet))
+    else:
+        raw = await anthropic_client.messages.create(**build_anthropic_strict_payload(sources, packet))
+
+    evidence = normalize_to_evidence_card(raw, packet.provider)
+    app.ledger.record(evidence)
+    return evidence.model_dump_json()
+
+@function_tool
+async def run_app_owned_python(packet: SpreadsheetComputeInput) -> str:
+    # Application-owned worker, NOT a provider hosted tool.
+    result = app_python_worker.compute(packet.source_id, packet.operation)
+    evidence = computed_result_to_evidence_card(result)
+    app.ledger.record(evidence)
+    return evidence.model_dump_json()
+ + +

11.2. LangGraph

+
class State(TypedDict):
+    sources: dict[str, SourceRecord]
+    selected_source_ids: list[str]
+    provider: Literal["openai", "gemini", "anthropic"]
+    question: str
+    evidence_cards: Annotated[list[EvidenceCard], add]
+    turn_ledger: Annotated[list[TurnLedgerEntry], add]
+
+def provider_node(state: State):
+    sources = [state["sources"][sid] for sid in state["selected_source_ids"]]
+
+    if state["provider"] == "openai":
+        raw = openai_client.responses.create(**build_openai_strict_payload(sources, state["question"]))
+    elif state["provider"] == "gemini":
+        raw = gemini_client.interactions.create(**build_gemini_strict_payload(sources, state["question"]))
+    else:
+        raw = anthropic_client.messages.create(**build_anthropic_strict_payload(sources, state["question"]))
+
+    return normalize_to_state(raw, provider=state["provider"])
+ + +

11.3. Deep Agents

+
workspace/
+  registry/sources.json
+  sources/IMG_ORIG_001.png
+  sources/PDF_001.pdf
+  sources/XLS_001.csv
+  evidence/
+
+tools = [
+  call_openai_strict_payload,
+  call_gemini_strict_payload,
+  call_anthropic_strict_payload,
+  app_owned_python_worker,
+  app_owned_image_harvester
+]
+
+# Deep Agent instruction:
+# - never request provider file upload
+# - never use provider code execution for PHI
+# - use source_ids and EvidenceCards only
+# - files in workspace are application-controlled, not provider storage
+
+ Nota: a estrutura workspace/ é convenção arquitetural deste guia, não prescrita + pelo framework; o backend de filesystem é o FilesystemBackend documentado em + Deep Agents · backends. +
+ +

11.4. Google ADK (v1/v2)

+
# ADK v1/v2: provider tools/nodes use strict adapters.
+session.state["app:source_registry"] = source_registry
+session.state["app:turn_ledger"] = []
+
+def review_openai(source_ids: list[str], question: str) -> dict:
+    return call_openai(build_openai_strict_payload(resolve(source_ids), question))
+
+def review_gemini(source_ids: list[str], question: str) -> dict:
+    return call_gemini(build_gemini_strict_payload(resolve(source_ids), question))
+
+def review_anthropic(source_ids: list[str], question: str) -> dict:
+    return call_anthropic(build_anthropic_strict_payload(resolve(source_ids), question))
+
+def spreadsheet_worker(source_id: str, operation: str) -> dict:
+    # Application-owned execution.
+    return run_internal_worker(source_id, operation)
+ +
+ + +
+

Parte 5 — Web & execução hospedada

+

+ Dois cenários que saem do payload puro: imagens descobertas na web (que precisam de validação antes de virar + evidência) e a execução hospedada do Modo B (que precisa de gating explícito). +

+
+ +
+

12. URL de imagem na web

+

+ O modelo/tool pode descobrir URLs, mas a análise visual só começa depois que a aplicação valida e + reinjeta a imagem como input_image/image. A referência web nunca é evidência do + paciente/caso. +

+
+ + + + + + + + + +
EtapaControle
Buscaweb_search / Google Search / Anthropic Web Search, ou buscador app-side.
ExtraçãoHTML img/srcset, figure/caption, OpenGraph, PDFs/artigos.
ValidaçãoMIME, resolução, hash, licença, domínio, safety, duplicidade.
RegistroSourceRecord WEBIMG_REF_* com external_url e source_page_url.
PayloadBloco visual separado da imagem do caso.
Respostasource_id por observação; referência web nunca é evidência do paciente.
+
+ Sob ZDR/Modo A: Google Search e Maps grounding do Gemini retêm dados (~30 dias) e não são + desativáveis — para footprint absoluto, prefira um buscador app-side e reinjete só a imagem validada. +
+
+ +
+

13. Modo B — Hosted Shell / Code / Container

+
+ Separação importante: Hosted Shell/Code/Container é opcional e não pertence ao + Modo A estrito. store=false não significa que um container hospedado não tenha filesystem + temporário durante a execução. +
+
MODE_B_OPTIONAL_HOSTED_EXECUTION:
+  purpose:
+    - deterministic spreadsheet calculations
+    - Python/bash data analysis
+    - generating charts or output artifacts
+    - complex extraction from messy files
+  critical_warning:
+    - This is NOT the same as strict no-provider-storage mode.
+    - store=false controls response/conversation state, not the tool/container ephemeral filesystem.
+    - Hosted containers may write temporary application state while active.
+    - For PHI/ZDR-critical workloads, prefer an application-owned worker/sandbox.
+  provider_notes:
+    openai:
+      code_interpreter:
+        container_required: true
+        memory_limit: "1g (default) | 4g | 16g | 64g; applies for the whole container lifetime"
+        container_lifecycle: "ephemeral; expires after idle; container data discarded"
+        zdr_notes: "Responses can be ZDR-eligible and ZDR forces store=false, but hosted containers may write temporary state while active; validate contract."
+      hosted_shell:
+        strict_mode: "not allowed for user files"
+    gemini:
+      code_execution:
+        language: "Python"
+        stateless_requirement: "with store=false, replay id/signature fields for tool combination"
+        zdr_notes: "store=false required for Interactions ZDR footprint; avoid Google Search/Maps/File API/cached_content for absolute zero footprint."
+      deep_research:
+        background_required: true
+        strict_mode: "not allowed when no provider state is permitted"
+    anthropic:
+      code_execution:
+        languages: ["Python", "Bash"]
+        preferred_version: "code_execution_20260120"
+        compat_version: "code_execution_20250825 (incl. Haiku 4.5)"
+        zdr: "NOT eligible for ZDR (container data retained up to 30 days)"
+        strict_mode: "not allowed for PHI/ZDR strict path"
+      files_api: { zdr: "not eligible for ZDR" }
+      messages_pdf_vision: { zdr: "eligible when org has ZDR and no disallowed features are used" }
+
+ + + + + + + + + +
ProviderFerramentaZDR / store=false / compatibilidade
OpenAICode Interpreter / Hosted ShellResponses é ZDR elegível e ZDR força store=false, mas containers podem escrever estado temporário enquanto ativos. Use só se a política aceitar container efêmero do provider.
GeminiCode executionstore=false para Interactions; se stateless com tools, reenviar id/signature. ZDR absoluto exige evitar store=true, File API, cached_content e Google Search/Maps.
GeminiDeep Research / backgroundIncompatível com Modo A: background=true e estado fazem parte do fluxo.
AnthropicCode ExecutionNão é ZDR elegível; container retém dados até 30 dias. Evitar para PHI/ZDR estrito.
AnthropicFiles API / SkillsNão ZDR elegíveis; evitar em Modo A.
TodosWorker próprioCaminho recomendado para Excel, OCR, PDF render/crop, cálculos e geração de artefatos em dados sensíveis.
+
+ +
+

14. Hosted execution por provider

+

Exemplos do Modo B. Use somente se a computação hospedada for permitida pela política; para PHI/ZDR estrito, substitua por um worker próprio.

+ +

14.1. OpenAI — Code Interpreter / Hosted Shell

+
# Optional Mode B: OpenAI Code Interpreter / Hosted Shell.
+# Not part of the strict no-provider-storage path.
+
+response = client.responses.create(
+    model="gpt-5.5",
+    store=False,
+    tools=[{"type": "code_interpreter", "container": {"type": "auto", "memory_limit": "4g"}}],
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "Use the python tool to validate this CSV summary. Do not retain artifacts."},
+            {"type": "input_text", "text": CSV_001_SUMMARY.markdown}
+        ]
+    }]
+)
+# For strict PHI/no-provider-storage: replace with an application-owned Python worker.
+
+ memory_limit (verificado): escolha entre 1g (default), 4g, + 16g ou 64g; o valor escolhido vale por toda a vida do container (criado em modo + auto ou via /v1/containers) e é cobrado às taxas de built-in tools. O ciclo é efêmero: + o container expira por inatividade e os dados são descartados. +
+ +

14.2. Gemini — Code execution

+
# Optional Mode B: Gemini code_execution.
+# With store=false, keep and replay id/signature fields if tool combination needs continuity.
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    store=False,
+    input=[{"type": "user_input", "content": [
+        {"type": "text", "text": "Compute and verify the summary from this CSV excerpt."},
+        {"type": "text", "text": CSV_001_FILTERED_TEXT}
+    ]}],
+    tools=[{"type": "code_execution"}]
+)
+ +

14.3. Anthropic — Code execution

+

+ Roda Python/Bash em sandbox e não é ZDR elegível. Prefira a versão + code_execution_20260120 (adiciona persistência de REPL e programmatic tool calling), + suportada em Opus 4.5+ e Sonnet 4.5+ — inclui Opus 4.8/4.7/4.6 e Sonnet 4.6; + não inclui Haiku 4.5. code_execution_20250825 permanece suportada em + todos os modelos (única opção para Haiku 4.5). +

+
# Optional Mode B: Anthropic code_execution. NOT ZDR eligible per Anthropic docs.
+
+message = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=2000,
+    tools=[{"type": "code_execution_20260120", "name": "code_execution"}],
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text", "text": "Use code execution to validate this CSV excerpt, then return an EvidenceCard."},
+            {"type": "text", "text": CSV_001_FILTERED_TEXT}
+        ]
+    }]
+)
+# For strict mode: use application-owned code execution and pass only computed EvidenceCards to Claude.
+ +
+ +
+

15. Hosted execution dentro dos frameworks

+
+ + + + + + + +
FrameworkModo AModo B opcional
Agents SDKFunction tools chamam workers próprios e adapters strict.Function tool pode chamar Code Interpreter/Hosted Shell, Gemini code_execution ou Anthropic code_execution — mas marque o run como non-strict.
LangGraphNós strict chamam provider payload ou app worker.Nó hosted_exec separado; o checkpoint registra que houve provider container/tool.
Deep AgentsFilesystem/backend app-side + tools strict.Subagent/tool hosted só com gating, aprovação e sem PHI/ZDR.
ADK v1/v2FunctionTool/nó chama app worker.FunctionTool/nó chama provider code tool; session.state marca non-strict.
+
+ + +
+

Parte 6 — Controle

+

O que fecha o contrato: o schema de saída, os evals que bloqueiam, os riscos e o checklist.

+
+ +
+

16. Output schema (EvidenceCard)

+
{
+  "summary": "string",
+  "observations": [
+    {
+      "observation": "string",
+      "source_ids": ["IMG_ORIG_001"],
+      "comparison_source_ids": ["WEBIMG_REF_001"],
+      "modality": "visual|textual|tabular|computed",
+      "confidence": "low|medium|high",
+      "limitations": "string"
+    }
+  ],
+  "discarded_sources": [
+    {"source_id": "WEBIMG_REF_002", "reason": "irrelevant, unsafe, unsupported, expired URL, or low quality"}
+  ],
+  "cannot_answer": ["string"],
+  "human_review_required": true
+}
+
+ +
+

17. Evals obrigatórios

+
+ + + + + + + + + + +
EvalPassa se…
No provider storage strictModo A não contém file_id, uploaded_file.uri, vector store, File Search, background ou container hospedado.
Hosted mode flagQualquer Code/Shell/Container marca run_mode=hosted_optional_non_strict.
Source attributionTodo claim tem source_id/EvidenceCard.
Visual visibilityClaim visual só se imagem/crop entrou no payload ou existe EvidenceCard visual.
Web URL pipelineURL descoberta só vira observação visual após SourceRecord validado.
Excel exactnessNúmeros batem com worker próprio (ou hosted mode explicitamente permitido).
ZDR gatingRuns PHI/ZDR bloqueiam Anthropic Code Execution/Files API, Gemini Google Search/background, OpenAI vector/File APIs.
+ +
+ +
+

18. Riscos

+
+ + + + + + + + + + + +
RiscoMitigação
Confundir store=false com zero container stateSeparar Modo A e Modo B; registrar run_mode.
Provider hosted tool em PHIPolicy gate bloqueia hosted tools para PHI.
URL assinada com PHIPreferir base64 inline; TTL curto e domínio controlado se necessário.
Imagem web sem licençaImageHarvester exige license_note/trust_tier.
PDF grande estoura contextoChunking/render/crop app-side.
Excel erradoWorker próprio; hosted só como Modo B.
Subagente sem fonteSubagentInputPacket e EvidenceCard obrigatórios.
String de versão de tool desatualizadaTratar versões (ex.: code_execution_*) como perecíveis; preferir a mais recente suportada pelo modelo.
+
+ +
+

19. Checklist final

+
+ + + + + + + + + +
Modo AModo BFile inputsResposta
☐ Sem Files API/file_id
☐ Sem File Search/vector store
☐ Sem container hospedado
☐ store=false/background=false
☐ Base64/signed URL/chunks app-side
☐ run_mode=hosted_optional_non_strict
☐ ZDR/BAA validado
☐ PHI bloqueado se não permitido
☐ TTL/cleanup/egress registrado
☐ Política de download/deleção de artefato
☐ Caption antes de cada fonte
☐ source_id por claim
☐ parent_source_id em crops
☐ Excel calculado fora
☐ PDF visual crítico renderizado
☐ EvidenceCards
☐ limitações
☐ sem diagnóstico
☐ human_review_required
☐ referências web separadas
+
+ + +
+

Cheat sheet — Modo A vs Modo B

+
+ + + + + + + + + +
PerguntaModo A (estrito)Modo B (hosted)
PHI/ZDR estrito?Sim — este é o caminho.Não — exige análise de retenção/contrato.
Como o arquivo entra?base64 inline / signed URL efêmera / chunk-render app-side.container hospedado processa o arquivo.
Excel / cálculo determinístico?worker próprio → CSV/JSON/EvidenceCard.code execution hospedado (se permitido).
Estado retido no provider?Nenhum (store=false, sem Files/vector/background).Filesystem efêmero do container enquanto ativo.
Anthropic code execution?Proibido (não ZDR elegível).code_execution_20260120 (compat: 20250825).
run_modestrict_no_provider_storagehosted_optional_non_strict
+

Mapa de cross-links

+
+ + + + + + + + +
Preciso de…Onde ler
Formatos/limites por providerMultimodal · OpenAI · Gemini · Anthropic · catálogo
ZDR/retenção (agnóstico + por provider)Operação · ZDR · OpenAI · Gemini · Claude
Ledger canônico / payload é projeçãoEstado, contexto & memória
Evals / acceptance gatesOperação · Evals
HITL por frameworkLangGraph · ADK · Agents SDK
+
+ +
+

Notas de verificação

+

Pontos perecíveis conferidos contra a documentação oficial em 2026-06-10 por time de validação (debate cruzado), e os que permanecem em aberto.

+
    +
  • Verificado detail:"original" (OpenAI). Valor válido (low/high/original/auto), "available on gpt-5.4 and future models"; em gpt-5.5, auto equivale a original. Fonte: developers.openai.com/api/docs/guides/images-vision.
  • +
  • Verificado Limites OpenAI. 512 MB de payload e 1500 imagens/request; input_file < 50 MB por arquivo e soma ≤ 50 MB. ZDR força store=false. Fontes: /images-vision, /file-inputs, /your-data.
  • +
  • Verificado Limites Anthropic. Request 32 MB; 600 páginas de PDF (100 p/ modelos 200k) e 600 imagens/request (100 p/ 200k); GIF animado usa só o 1º frame; PDF vision = texto + imagem por página. PDF inline = ZDR elegível; Files API e Code Execution = NÃO ZDR elegíveis (container retém até 30 dias). Fontes: /vision, /pdf-support, /api-and-data-retention, /code-execution-tool.
  • +
  • Verificado Gemini ZDR. store=false = zero-data footprint; incompatível com background=true e previous_interaction_id; Google Search/Maps retêm ~30 dias (não desativável); File API e cached_content persistem. Fonte: /zdr.
  • +
  • Atualizado Versão do code execution (Anthropic). code_execution_20250825 é válido em todos os modelos, mas code_execution_20260120 é mais recente e suportado em Opus 4.5+ e Sonnet 4.5+ (inclui Opus 4.8/4.7/4.6 e Sonnet 4.6; não inclui Haiku 4.5) — adiciona persistência de REPL + programmatic tool calling. Este guia usa 20260120 como preferida e cita 20250825 como compatibilidade (única opção para Haiku 4.5). A versão legada anterior (Python-only) foi omitida. Fonte: /code-execution-tool — reconferido 2026-06-10.
  • +
  • Verificado Gemini media_resolution — funciona na Interactions API. A forma global (generation_config={"media_resolution": "MEDIA_RESOLUTION_HIGH"}) é válida na Interactions: a doc lista generation_config como parâmetro interaction-scoped de comportamento do modelo (junto de thinking_level, temperature) e a migração de maio/2026 confirma que generation_config permanece focado em comportamento. Enum MEDIA_RESOLUTION_UNSPECIFIED/LOW/MEDIUM/HIGH (ULTRA_HIGH só por-part). O modo por-part é exclusivo do Gemini 3 / v1alpha e documentado para generateContent — não cravado nos blocos da Interactions; por isso §9 usa a forma global. (Correção da rodada anterior, que marcara o parâmetro como não-suportado.) Fonte: ai.google.dev/gemini-api/docs/media-resolution + /interactions + /interactions-breaking-changes-may-2026 — 2026-05-25.
  • +
  • Verificado OpenAI memory_limit de container. Documentado: 1g (default), 4g, 16g, 64g; vale por toda a vida do container (modo auto ou via /v1/containers) e é cobrado às taxas de built-in tools. Ciclo efêmero (expira por inatividade, dados descartados). Fonte: developers.openai.com/api/docs/guides/tools-code-interpreter#containers — 2026-05-25.
  • +
  • Verificado Schema de content-block do Gemini Interactions. O formato {type, data|uri, mime_type} (image/document/audio/video) e os limites inline 100 MB/request (50 MB para PDF) constam na página oficial file input methods da Interactions API. Fonte: ai.google.dev/gemini-api/docs/interactions/file-input-methods — 2026-05-25.
  • +
  • UNVERIFIED (menor) model_dump_json() como retorno de tool (Agents SDK). Método Pydantic v2 válido; aceitável se EvidenceCard for um modelo Pydantic, mas não é um pattern explicitamente documentado no SDK.
  • +
  • Verificado Âncoras de cross-link. Todos os destinos usados resolvem em 2026-05-25: guia_multimodal#h-openai/#h-gemini/#h-anthropic/#h-limits-catalog, guia_operacao_seguranca_evals#privacidade-retencao-zdr/#evals-acceptance-gates, guia_openai_modelos#s-conversation, guia_gemini_interactions_api#s-store, guia_claude_api#b-pdf/#b-files, guia_agents_sdk#s-guardrails, guia_langgraph#s-persistence/#s-hitl, guia_deepagents#s-backends, guia_google_adk#tool-confirm.
  • +
  • Atualizado Integração da proposta v0.6 (2026-05-26). Adicionado ao SourceRecord o campo projection_policy (inline_current_turn/summary/rag_only/blocked) e os campos de reidratação/orçamento (page_count, token_estimate, parsed_ref, parser_version). Em §7, incluída a tabela de páginas inline e token cap por tier como camada de política de produto (valores ilustrativos, parametrizáveis), explicitamente distinta dos limites físicos da API por provider já documentados no guia.
  • +
  • Atualizado Varredura de 2026-06-10. Reconferência dos pontos perecíveis contra a documentação oficial. (1) media_resolution no Gemini: o callout de §9 foi promovido de UNVERIFIED para Verificado na forma global da Interactions API, alinhando-o à nota de verificação acima (per-part segue v1alpha/experimental, só generateContent / Gemini 3). (2) code_execution_20260120 (Anthropic): enunciado de suporte corrigido para Opus 4.5+ e Sonnet 4.5+ (inclui Opus 4.8/4.7/4.6 e Sonnet 4.6; não inclui Haiku 4.5) em §14.3 e na nota correspondente; code_execution_20250825 segue suportada em todos os modelos. (3) Marcadores de verificação (meta, header, hero, fontes, legenda, footer) re-datados para 2026-06-10.
  • +
+
+ +
+
+ +
+
+
+
File Inputs sem Provider Storage Núcleo agnóstico · super-guia de agentes
+

+ Referência técnica construída a partir da documentação oficial pública em 2026-06-10. + Modo A estrito sem provider storage; Modo B hosted opcional com retenção/ZDR claramente separado. Para + informação sempre atualizada, consulte as fontes oficiais. +

+
+
+
Crédito de produção
+
Validação por time Sonnet 4.6 (debate cruzado, fontes oficiais)
+
montagem e reconciliação pelo orquestrador Opus 4.7 · 2026-05-26
+
+ Núcleo · v1 + Modo A estrito +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_gemini_interactions_api.html b/references/agents_tools_best_guides/guia_gemini_interactions_api.html new file mode 100644 index 0000000..1d6709e --- /dev/null +++ b/references/agents_tools_best_guides/guia_gemini_interactions_api.html @@ -0,0 +1,4534 @@ + + + + + +Guia Gemini Interactions API — Referência completa + Migração de generateContent + + + + + + + + +
+
+
Guia Gemini Interactions API PT-BR · Referência completa + Migração
+
+ Verificado em 2026-06-25 + google-genai + GA + +
+
+
+ +
+ + +
+ +
+

Guia Gemini Interactions API — Referência completa + Migração

+

+ Documentação técnica exaustiva da Gemini Interactions API + (GA desde junho/2026 — a interface recomendada por padrão para novos projetos), + sucessora do método generateContent. + Cobre a anatomia da Interaction (timeline de steps), + texto, streaming SSE, multimodal (imagem/áudio/vídeo/PDF), + function calling, structured output, thinking, caching, Deep Research, + ferramentas server-side (Google Search, Maps, Code Execution, URL Context, + File Search, Computer Use, MCP), background tasks, webhooks + e a referência REST completa, além de uma seção dedicada com mapeamento + antes/depois e breaking changes de Maio 2026. +

+

+ ⭐ Destaque: a Interactions API é agora GA (junho/2026) e o caminho + SOTA recomendado pela Google para todo projeto novo. Modelos recomendados: + gemini-3.5-flash (Flash estável, padrão) e gemini-3.1-pro-preview + (reasoning/multimodal avançado). SDK google-genai ≥ 2.0.0 (último 2.10.0). +

+
+ google-genai · Python ≥ 2.0.0 (último 2.10.0) + @google/genai · JS ≥ 2.0.0 (último 2.10.0) + GA · jun/2026 + SOTA · 2026-06-25 + Schema steps · Api-Revision ignorado +
+
+ +
+

Sobre este guia

+

+ Este é um guia técnico exaustivo, em português brasileiro, da nova + Google Gemini Interactions API — a interface padrão recomendada + pela Google para novos projetos agênticos, conversas multiturno com estado + no servidor e fluxos com ferramentas. O método generateContent + continua suportado, mas a migração é incentivada e várias capacidades novas + (Deep Research, novos modelos da família Gemini 3.x) chegam apenas via Interactions. +

+

O guia é organizado em três partes e um apêndice:

+
    +
  • Parte A — Conceitos & Guias: explica cada capacidade da API + com exemplos em Python, JavaScript e REST, no formato encontrado na documentação oficial.
  • +
  • Parte B — Referência REST: enumera todos os endpoints, schemas, + enums, tipos de step, tipos de content, tipos de tool e eventos SSE.
  • +
  • Parte C — Migração: par-a-par de antes (generateContent) + e depois (Interactions), tabela completa de mapeamento, + checklist e as breaking changes oficiais de Maio 2026.
  • +
  • Apêndice: notebooks do cookbook, glossário e histórico do guia.
  • +
+
+ Como ler: cada capítulo expõe Python, JS e REST em paralelo, + preservando exatamente os exemplos oficiais. Se um detalhe divergir do + publicado em ai.google.dev, a documentação oficial é a fonte autoritativa. +
+
+ Status: GA (junho/2026). A Interactions API é agora + generally available e a interface recomendada por padrão para + todo desenvolvimento novo — a própria landing page da Gemini API + recomenda interactions.create para novos projetos. Importante: o + endpoint permanece em /v1beta/interactions — o rótulo GA não + promoveu o caminho para /v1/. O conjunto de breaking changes de + Maio 2026 (ver seção dedicada) + já foi consumado em 08/06/2026: a matriz outputs foi + substituída por steps, os eventos SSE foram renomeados, + response_format absorveu response_mime_type e + image_config, o schema legado foi removido permanentemente, o header + Api-Revision passou a ser ignorado (a janela de rollback + com Api-Revision: 2026-05-07 fechou nessa data) e os SDKs 1.x falham nas + chamadas de Interactions. O método generateContent continua suportado, + mas várias capacidades novas (Deep Research, agentes gerenciados) chegam só via Interactions. +
+
+ Superfície: Developer API (GA) vs Vertex / Gemini Enterprise Agent Platform (experimental). + Toda a documentação desta página e os exemplos REST abaixo usam a + Gemini Developer API (AI Studio): endpoint + generativelanguage.googleapis.com/v1beta/interactions e header + x-goog-api-key com chave do + AI Studio. + A Interactions API também existe na Vertex AI / Gemini Enterprise Agent Platform + (endpoint aiplatform.googleapis.com/v1beta1/projects/{project}/locations/global/interactions, + auth OAuth/ADC), porém rotulada como experimental — status diferente do + GA da Developer API. Nem toda ferramenta tem paridade documentada entre as duas: + code_execution dentro de Interactions é documentado/exemplificado só na Developer API; + na Vertex a execução de código é documentada via generateContent (ver + §17.3 e o guia de code tools). + Em produção na Vertex, valide a disponibilidade de cada recurso antes de migrar de + generateContent para Interactions. + Verificado em 2026-06-25, fontes oficiais Google. +
+
+ +
+

Fontes oficiais

+ +

+ Última verificação contra estas fontes: 2026-06-19. + Sempre que houver divergência entre este guia e a documentação oficial em + produção, a documentação oficial é a fonte autoritativa. Capturas literais + de exemplos e tabelas preservam a acentuação PT-BR original. +

+
+ +
+

TL;DR · Migração rápida

+

Se você já usa generateContent e precisa migrar, decore estes pontos:

+
+ + + + + + + + + + + + + + + + + + + +
AspectogenerateContent (legado)Interactions API (novo)
EndpointPOST /v1beta/models/{model}:generateContentPOST /v1beta/interactions
Streaming:streamGenerateContentmesmo endpoint + "stream": true
Históricocliente reenvia array contentsservidor mantém via previous_interaction_id
Resposta textoresponse.candidates[0].content.parts[0].textinteraction.output_text
Estrutura da respostacandidates[].content.parts[]steps[] tipados
Schema estruturadogenerationConfig.responseFormatresponse_format (top-level)
Image configgeneration_config.image_configresponse_format: {type:"image", ...}
Toolstools=[{google_search:{}}]tools=[{"type":"google_search"}]
Function declaration{name, description, parameters} aninhado em function_declarations{"type":"function", name, description, parameters} direto em tools
Function call IDnão garantidostep.id obrigatório (Gemini 3)
CitaçõesgroundingMetadata.groundingSupports com índicesannotations[] inline em content[].annotations
Tasks longasnão suportadasbackground=true + webhook_config
Retençãon/a (stateless)55 dias pago / 1 dia free (padrão store=true)
SDK Python mínimoqualquer google-genai≥ 2.0.0 (obrigatório desde 08/06/2026; SDKs 1.x falham nas chamadas de Interactions)
SDK JS mínimoqualquer @google/genai≥ 2.0.0 (obrigatório desde 08/06/2026; SDKs 1.x falham nas chamadas de Interactions)
+
+
+ Datas críticas (Breaking changes Maio 2026): +
    +
  • 07/05/2026 — SDKs Python 2.0.0 e JS 2.0.0 publicados. Opt-in via cabeçalho Api-Revision: 2026-05-20.
  • +
  • 26/05/2026 — Novo schema virou padrão; rollback temporário possível via Api-Revision: 2026-05-07 (janela já encerrada).
  • +
  • 08/06/2026 — Schema legado removido permanentemente (consumado). Headers de rollback ignorados; SDKs 1.x falham.
  • +
+
+

Detalhes completos em Parte C — Migração.

+
+ + + + + + +
+

Parte A — Conceitos & Guias

+

Capítulos 1–23 cobrindo todos os conceitos públicos da Gemini Interactions API, em ordem de leitura recomendada da documentação oficial. Exemplos em Python (google-genai), JavaScript (@google/genai) e REST/cURL.

+
+ +
+

1. Visão geral da Interactions API

+ +

A API Interactions é a nova interface padrão do Gemini para fluxos agênticos, conversas multiturno com estado server-side e operações longas. Está em Beta e seus esquemas estão sujeitos a mudanças incompatíveis (ver breaking changes de Maio 2026). O método generateContent continua funcional e suportado, mas novos recursos (Deep Research, novos modelos da família Gemini 3.x exclusivos) chegam apenas via Interactions.

+ +

1.1 Por que usar a Interactions API

+
    +
  • Gerenciamento de histórico server-side: conversa multiturno via previous_interaction_id. O servidor ativa estado por padrão (store=true); para modo stateless, defina store=false.
  • +
  • Etapas de execução observáveis: a resposta é uma timeline tipada de steps (thought, function_call, function_result, model_output, google_search_call, etc.), facilitando depuração e renderização de UI para eventos intermediários.
  • +
  • Criado para fluxos agênticos: orquestração nativa multi-turno com ferramentas.
  • +
  • Tarefas longas em background: background=true habilita operações assíncronas (Deep Think, Deep Research) com integração a webhooks.
  • +
  • Acesso exclusivo a novos modelos: agentes Deep Research e outros lançamentos saem direto na Interactions.
  • +
+ +

1.2 Quando usar cada API

+
+ + + + + + + + +
SituaçãoAPI recomendada
Novo projeto ou aplicação agênticaInteractions API
Integração existente em produção estávelgenerateContent
Recursos ainda não disponíveis em Interactions (Batch, cache explícito)generateContent
Deep Research, agentes nativos, background tasksInteractions API
+
+
+ Atualização (2026-06-10): a página oficial de migração + (migrate-to-interactions) + agora descreve a Interactions API como "the standard interface for building with Gemini" + e a recomenda para todo desenvolvimento novo. A página de visão geral mantém + o aviso de Beta e generateContent como caminho estável para produção — a tabela + acima reflete as duas fontes. +
+ +

1.3 Propriedades de conveniência do SDK

+
+ + + + + + + +
PropriedadeTipoDescrição
interaction.output_textstringÚltimos blocos TextContent consecutivos unidos automaticamente. Não captura texto separado por pensamentos, imagens, áudio ou tool calls.
interaction.output_imageImageContent ou NoneÚltimo bloco de imagem gerado pelo modelo.
interaction.output_audioAudioContent ou NoneÚltimo bloco de áudio gerado pelo modelo.
+
+
+ Quando iterar manualmente: para inspecionar pensamentos, function calls ou conteúdo intercalado (texto + imagem + áudio), itere interaction.steps. +
+ +

1.4 SDKs & versões mínimas

+
+ + + + + + + + + +
LinguagemPacoteVersão mínimaInstalação
Python (≥ 3.9)google-genai2.0.0 (SDKs 1.x falham desde 08/06/2026; último PyPI: 2.10.0)pip install -U google-genai
JavaScript / TypeScript (Node ≥ 18)@google/genai2.0.0 (SDKs 1.x falham desde 08/06/2026; último npm: 2.10.0)npm install @google/genai
Gogoogle.golang.org/genai—go get google.golang.org/genai
Javacom.google.genai:google-genai1.0.0Maven artifact
C#Google.GenAI—dotnet add package Google.GenAI
+
+

Nota (2026-06-25): o último google-genai / @google/genai é 2.10.0 (ambos; 2026-06-24). A 2.9.0 reimplementou a Interactions internamente mantendo a API pública compatível e a 2.10.0 segue compatível, então os exemplos deste guia seguem válidos; mantenha o piso prático ≥ 2.0.0 (1.x falha desde 08/06/2026).

+
+ Bibliotecas legadas descontinuadas em 30/11/2025: + google-generativeai (Python), @google/generativeai (JS), google.golang.org/generative-ai (Go), + google_generative_ai (Dart), generative-ai-swift, generative-ai-android. + Para Dart/Flutter e mobile (Swift/Android), a recomendação oficial passa a ser Firebase AI Logic, + e não o SDK google-genai. +
+ +

1.5 Limitações conhecidas (vs. generateContent)

+

Recursos ainda ausentes em Interactions API (presentes em generateContent):

+
    +
  • Metadados de vídeo (video_metadata: intervalos de corte, FPS customizado).
  • +
  • Batch API assíncrona em lote.
  • +
  • Chamada automática de função (Python apenas).
  • +
  • Cache explícito — porém cache implícito via previous_interaction_id está disponível.
  • +
  • MCP Remoto com Gemini 3 — "Gemini 3 não é compatível com MCP remoto, mas isso vai mudar em breve" (doc oficial). Além disso, apenas servidores Streamable HTTP são suportados — servidores baseados em SSE não são (e o name do servidor não pode conter -, use snake_case).
  • +
+ + +
+ +
+

2. Quickstart & SDKs

+ +

2.1 Chave de API

+

Obtenha uma chave em aistudio.google.com/app/apikey. Em ambientes Python/JS o SDK lê automaticamente a variável GEMINI_API_KEY:

+
# macOS / Linux
+export GEMINI_API_KEY="sk-..."
+
+# Windows PowerShell
+$env:GEMINI_API_KEY = "sk-..."
+
+# Windows CMD
+set "GEMINI_API_KEY=sk-..."
+ +

2.2 Instalação

+
# Mínimo para usar a Interactions API hoje (schema steps, único desde 08/06/2026):
+pip install -U "google-genai>=2.0.0"             # Python (último PyPI: 2.10.0)
+npm install "@google/genai@>=2.0.0"              # Node / TypeScript (último npm: 2.10.0)
+
+# SDKs 1.x (google-genai < 2.0.0 / @google/genai < 2.0.0) falham nas
+# chamadas de Interactions desde 08/06/2026 — schema legado removido.
+ +

2.3 Primeira interação (Hello world)

+

Python

+
from google import genai
+
+client = genai.Client()
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="How does AI work?"
+)
+print(interaction.output_text)
+ +

JavaScript

+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+
+const interaction = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  input: "How does AI work?",
+});
+console.log(interaction.output_text);
+ +

REST

+
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H 'Content-Type: application/json' \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{
+    "model": "gemini-3.5-flash",
+    "input": "How does AI work?"
+  }'
+ +
+ Header Api-Revision (histórico): entre 07/05/2026 e 26/05/2026 ele controlou o opt-in no novo schema (2026-05-20) e, até 08/06/2026, o rollback temporário (2026-05-07). Desde 08/06/2026 o header é ignorado e pode ser omitido das chamadas — o schema steps é o único aceito. Os exemplos REST da doc oficial (incl. o novo quickstart) ainda o incluem; enviá-lo é inofensivo (no-op). +
+ + +
+ +
+

3. Anatomia de uma Interaction

+ +

O recurso central da API é o objeto Interaction. Ele encapsula uma rodada completa de execução: as entradas do usuário, qualquer raciocínio (thoughts), chamadas de ferramentas, resultados e a resposta final do modelo — tudo organizado em uma timeline ordenada chamada steps.

+ +

3.1 Campos principais

+
+ + + + + + + + + + + + + + + + + + + + + + + +
CampoTipoDescrição
idstringIdentificador único (v1_...) usado em previous_interaction_id.
objectstringSempre "interaction".
modelModelOptionID do modelo (ex.: gemini-3.5-flash). Obrigatório se agent não for fornecido.
agentAgentOptionID do agente (ex.: deep-research-preview-04-2026, antigravity-preview-05-2026). Obrigatório se model não for fornecido.
environment / environment_idstring | EnvironmentConfigSandbox de agente gerenciado: "remote" (novo), "env_..." (reuso) ou config completa. A resposta traz environment_id. Usado com agent (ver §18.9–18.10).
statusInteractionStatusUm de in_progress, requires_action, completed, failed, cancelled, incomplete, budget_exceeded.
created / updatedstring ISO 8601Timestamps.
stepsStep[]Timeline ordenada de etapas (ver §3.2).
inputContent / Content[] / Step[] / stringEntrada (texto livre, lista de blocks ou lista de steps em modo stateless).
toolsTool[]Lista de ferramentas disponíveis para esta interação.
response_formatResponseFormat / listConfigura saída estruturada e modalidades de resposta.
system_instructionstringInstrução de sistema (precisa ser reespecificada por turno).
generation_configGenerationConfigParâmetros de inferência (temperature, thinking_level, tool_choice, etc.).
previous_interaction_idstringID da interação anterior para continuar o histórico.
storebooleanArmazenamento server-side. Padrão true.
backgroundbooleanExecuta em segundo plano (incompatível com store=false).
webhook_configWebhookConfigURIs para notificação assíncrona.
service_tierServiceTierflex | standard | priority.
usageUsageContagem de tokens (entrada, saída, cache, thinking, ferramentas) por modalidade.
+
+ +

3.2 Tipos de step

+

Cada elemento de steps tem um campo type que discrimina seu papel. Veja a referência completa em Parte B — Step types. Os tipos mais comuns:

+
+ + + + + + + + + + + + + + + +
typeQuando apareceCampos principais
user_inputApenas em GET /interactions/{id} com include_input=truecontent[]
model_outputResposta final do modelocontent[] (text, image, audio, ...)
thoughtRaciocínio interno (Gemini 3.x)signature, summary
function_callModelo solicita execução de função do clienteid, name, arguments, signature
function_resultCliente devolve resultadocall_id, name, result, is_error
google_search_call / google_search_resultGrounding com Pesquisa Googlearguments.queries, result.search_suggestions
code_execution_call / code_execution_resultExecução server-side de Pythonarguments.code, result, is_error
url_context_call / url_context_resultLeitura de URLsarguments.urls, result.status
google_maps_call / google_maps_resultGrounding com Google Mapsarguments.queries, result.places, widget_context_token
file_search_call / file_search_resultRAG sobre File Search Storesid, call_id
mcp_server_tool_call / mcp_server_tool_resultTool externa via MCP HTTP Streamingserver_name, name, arguments, result
+
+ +

3.3 Blocos de conteúdo (Content)

+

Dentro de step.content[] (e dentro de input multimodal) cada bloco tem type:

+
{ "type": "text",     "text": "..." , "annotations": [ ... ] }
+{ "type": "image",    "data": "<base64>",     "mime_type": "image/jpeg" }
+{ "type": "image",    "uri":  "files/abc...",  "mime_type": "image/png"  }
+{ "type": "audio",    "data": "<base64>",     "mime_type": "audio/mp3", "sample_rate": 16000, "channels": 1 }
+{ "type": "document", "uri":  "files/abc...",  "mime_type": "application/pdf" }
+{ "type": "video",    "uri":  "https://www.youtube.com/watch?v=..." }
+{ "type": "video",    "uri":  "files/abc...",  "mime_type": "video/mp4", "resolution": "low" }
+ +

3.4 Exemplo de resposta completa

+
{
+  "id": "v1_ChdPU0F4YWFtNkFwS2kxZThQZ05lbXdROBIXT1NBeGFhbTZBcEtpMWU4UGdOZW13UTg",
+  "object": "interaction",
+  "model": "gemini-3.5-flash",
+  "status": "completed",
+  "created": "2025-11-26T12:25:15Z",
+  "updated": "2025-11-26T12:25:15Z",
+  "steps": [
+    { "type": "thought",      "signature": "abc123..." },
+    { "type": "model_output", "content": [
+        { "type": "text", "text": "Hello! I'm functioning perfectly and ready to assist you.\n\nHow are you doing today?" }
+    ]}
+  ],
+  "usage": {
+    "input_tokens_by_modality": [{ "modality": "text", "tokens": 7 }],
+    "total_input_tokens": 7,
+    "total_output_tokens": 20,
+    "total_thought_tokens": 22,
+    "total_tokens": 49,
+    "total_tool_use_tokens": 0,
+    "total_cached_tokens": 0
+  }
+}
+ + +
+ +
+

4. Geração de texto

+ +

A operação mais básica da Interactions API: enviar uma string ou lista de blocos como input e receber uma Interaction com a resposta nos steps.

+ +

4.1 Exemplo mínimo

+

Python

+
from google import genai
+
+client = genai.Client()
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="How does AI work?"
+)
+print(interaction.output_text)
+ +

JavaScript

+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+
+const interaction = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  input: "How does AI work?",
+});
+console.log(interaction.output_text);
+ +

REST

+
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H 'Content-Type: application/json' \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{
+    "model": "gemini-3.5-flash",
+    "input": "How does AI work?"
+  }'
+ +

4.2 System instruction

+

Use system_instruction para definir persona, política ou contexto. Lembre-se: instruções de sistema têm escopo por interação — você precisa reespecificá-las em cada turno (mesmo com previous_interaction_id) se quiser mantê-las.

+ +
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    system_instruction="You are a cat. Your name is Neko.",
+    input="Hello there"
+)
+print(interaction.output_text)
+ +

4.3 Configuração de geração

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Explain how AI works",
+    generation_config={
+        "temperature": 1.0,
+        "top_p": 0.95,
+        "max_output_tokens": 1024,
+        "stop_sequences": ["END"],
+        "seed": 42
+    }
+)
+ +

4.4 Pensando com o Gemini (thinking_level)

+

Nos modelos Gemini 3.x é possível ajustar o esforço de raciocínio. Veja a seção Thinking para a tabela completa de valores aceitos por modelo.

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="How does AI work?",
+    generation_config={"thinking_level": "low"}
+)
+print(interaction.output_text)
+ +

4.5 Entrada multimodal (imagem + texto)

+
from google import genai
+client = genai.Client()
+
+uploaded_file = client.files.upload(file="path/to/organ.jpg")
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Tell me about this instrument"},
+        {"type": "image", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
+    ]
+)
+print(interaction.output_text)
+ +

4.6 Parâmetros principais

+
+ + + + + + + + + + + + + + + +
ParâmetroTipoDescrição
modelstringModelo Gemini (ver ModelOption).
inputstring · Content[] · Step[]Texto livre ou blocos multimodais.
system_instructionstringInstrução de sistema.
generation_configobjecttemperature, top_p, seed, thinking_level, max_output_tokens, stop_sequences...
toolsTool[]Função, Google Search, Code Execution, etc.
response_formatobject · arrayEstrutura de saída e modalidades.
streambooleanSSE incremental.
previous_interaction_idstringContinua histórico server-side.
storebooleanPadrão true (servidor mantém estado).
backgroundbooleanExecução assíncrona (Deep Research, Deep Think).
service_tierstringflex · standard · priority.
+
+ + +
+ +
+

5. Conversas multiturno

+ +

A Interactions API gerencia o histórico no servidor por padrão. Para continuar uma conversa, basta passar o id da interação anterior em previous_interaction_id. Não é mais necessário reenviar o array contents inteiro como no generateContent.

+ +

5.1 Padrão server-side (recomendado)

+

Python

+
from google import genai
+
+client = genai.Client()
+
+interaction1 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="I have 2 dogs in my house.",
+)
+print(interaction1.output_text)
+
+interaction2 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="How many paws are in my house?",
+    previous_interaction_id=interaction1.id,
+)
+print(interaction2.output_text)
+ +

JavaScript

+
const interaction1 = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  input: "I have 2 dogs in my house.",
+});
+
+const interaction2 = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  input: "How many paws are in my house?",
+  previous_interaction_id: interaction1.id,
+});
+console.log(interaction2.output_text);
+ +

REST

+
RESPONSE1=$(curl -s -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H 'Content-Type: application/json' \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{ "model": "gemini-3.5-flash", "input": "I have 2 dogs in my house." }')
+
+INTERACTION_ID=$(echo "$RESPONSE1" | jq -r '.id')
+
+curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H 'Content-Type: application/json' \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{
+    "model": "gemini-3.5-flash",
+    "input": "How many paws are in my house?",
+    "previous_interaction_id": "'$INTERACTION_ID'"
+  }'
+ +
+ Parâmetros com escopo por interação: ao usar previous_interaction_id, alguns parâmetros precisam ser reespecificados a cada turno se ainda forem desejados — tools, system_instruction e generation_config (inclui thinking_level, temperature). +
+ +

5.2 Modo sem estado (store=false)

+

Para conformidade ou casos onde você não quer armazenamento server-side, defina store=false. Nesse modo você é responsável por reenviar TODOS os steps gerados (incluindo thought com signature) em cada turno — caso contrário a continuidade de raciocínio quebra.

+
history = [
+    {"type": "user_input", "content": [{"type": "text", "text": "I have 2 dogs."}]}
+]
+
+interaction1 = client.interactions.create(
+    model="gemini-3.5-flash", store=False, input=history
+)
+
+for step in interaction1.steps:
+    history.append(step.model_dump())
+
+history.append({
+    "type": "user_input",
+    "content": [{"type": "text", "text": "How many paws are in my house?"}]
+})
+
+interaction2 = client.interactions.create(
+    model="gemini-3.5-flash", store=False, input=history
+)
+print(interaction2.steps[-1].content[0].text)
+ +
+ Restrições de store=false: +
    +
  • Incompatível com background=true (Deep Research exige store=true).
  • +
  • Impede usar a interação como previous_interaction_id em chamadas subsequentes.
  • +
  • Você precisa preservar e reenviar todas as etapas geradas pelo modelo — incluindo assinaturas de thought.
  • +
+
+ + +
+ +
+

6. Streaming (SSE)

+ +

O streaming usa o mesmo endpoint POST /v1beta/interactions, apenas adicionando "stream": true no body. A resposta é um fluxo Server-Sent Events com eventos tipados por step. Não há mais o endpoint dedicado :streamGenerateContent.

+ +
Transporte: a Interactions API é HTTP request-response (com estado no servidor via previous_interaction_id) e o streaming é SSE sobre HTTP — não há WebSocket nesse caminho. Interação bidirecional em tempo real (voz/vídeo, áudio-para-áudio) é a Live API sobre WebSocket (WSS, BidiGenerateContent, modelos como gemini-3.1-flash-live-preview) — uma superfície separada da Interactions API.
+ +

6.1 Streaming básico

+

Python

+
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Count from 1 to 25.",
+    stream=True,
+)
+for event in stream:
+    if event.event_type == "step.delta":
+        if event.delta.type == "text":
+            print(event.delta.text, end="", flush=True)
+ +

JavaScript

+
const stream = await client.interactions.create({
+  model: "gemini-3.5-flash",
+  input: "Count from 1 to 25.",
+  stream: true,
+});
+for await (const event of stream) {
+  if (event.event_type === "step.delta" && event.delta.type === "text") {
+    process.stdout.write(event.delta.text);
+  }
+}
+ +

REST (SSE)

+
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?alt=sse" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -H "Api-Revision: 2026-05-20" \
+  --no-buffer \
+  -d '{
+    "model": "gemini-3.5-flash",
+    "input": "Count from 1 to 25.",
+    "stream": true
+  }'
+ +

6.2 Tipos de evento SSE

+
+ + + + + + + + + + + +
event_typeCarga principalQuando
interaction.createdinteraction (id, status, model)Início do stream.
interaction.status_updateinteraction_id, statusMudança de status. O campo status carrega o enum in_progress/requires_action/completed/failed/cancelled/incomplete/budget_exceeded (ver B8). Não existem eventos interaction.in_progress ou interaction.requires_action separados — essas são apenas valores de status.
step.startindex, stepInicia um step (tipo: thought, model_output, function_call, etc.).
step.deltaindex, deltaTrecho incremental do step atual.
step.stopindexStep finalizado.
interaction.completedinteraction com usageFinal do stream com contagem de tokens.
errorerror.code, error.messageErro em tempo de execução.
+
+
+ Conjunto canônico de eventos SSE — schema novo (default desde 26/05/2026): interaction.created, interaction.in_progress, + interaction.requires_action, interaction.completed, step.start, step.delta, step.stop (mais error). No schema vigente, + interaction.in_progress e interaction.requires_action são eventos SSE distintos (cada um com seu event_type). O evento legado + interaction.status_update — que carregava o status num único evento — foi substituído por eles e foi removido junto do schema legado em 08/06/2026. + Verificado 2026-06-03 contra interactions-breaking-changes-may-2026#streaming (corrige a leitura anterior, baseada no schema legado). Os eventos de webhook (§19) são um namespace à parte e incluem + interaction.requires_action/cancelled. +
+ +

6.3 Tipos de delta em step.delta

+
+ + + + + + + + + + + + + +
delta.typeCamposOnde aparece
texttextmodel_output
imagedata, uri, mime_type, resolutionmodel_output
audiodata, uri, mime_type, sample_rate, channelsmodel_output
documentdata, uri, mime_typemodel_output
videodata, uri, mime_type, resolutionmodel_output
thought_summarycontent (texto/imagem)thought
thought_signaturesignaturethought (último delta)
arguments_deltaarguments (string JSON parcial)function_call — exige acumulação até step.stop
text_annotation_deltaannotations[]model_output (citações inline)
+
+ +

6.4 Exemplo de fluxo SSE completo

+
event: interaction.created
+data: {"interaction":{"id":"v1_...","status":"in_progress","object":"interaction","model":"gemini-3.5-flash"},"event_type":"interaction.created"}
+
+event: interaction.in_progress
+data: {"interaction_id":"v1_...","status":"in_progress","event_type":"interaction.in_progress"}
+
+event: step.start
+data: {"index":0,"step":{"type":"thought"},"event_type":"step.start"}
+
+event: step.delta
+data: {"index":0,"delta":{"signature":"...","type":"thought_signature"},"event_type":"step.delta"}
+
+event: step.stop
+data: {"index":0,"event_type":"step.stop"}
+
+event: step.start
+data: {"index":1,"step":{"type":"model_output"},"event_type":"step.start"}
+
+event: step.delta
+data: {"index":1,"delta":{"text":"1, 2, 3, 4, 5, 6, ","type":"text"},"event_type":"step.delta"}
+
+event: step.delta
+data: {"index":1,"delta":{"text":"7, 8, 9, 10","type":"text"},"event_type":"step.delta"}
+
+event: step.stop
+data: {"index":1,"event_type":"step.stop"}
+
+event: interaction.completed
+data: {"interaction":{"id":"v1_...","status":"completed","usage":{"total_tokens":346,"total_input_tokens":11,"total_output_tokens":90,"total_thought_tokens":245}},"event_type":"interaction.completed"}
+
+event: done
+data: [DONE]
+ +

6.5 Streaming com function calling

+

Diferente do generateContent, function calls em streaming chegam em partes: step.start entrega name e id, e cada step.delta com delta.type == "arguments_delta" traz um fragmento em delta.arguments (string JSON) que você precisa acumular até o step.stop.

+ +
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="What is the weather in Paris?",
+    tools=[weather_tool],
+    stream=True
+)
+
+current_calls = {}
+for event in stream:
+    if event.event_type == "step.start" and event.step.type == "function_call":
+        current_calls[event.index] = {
+            "id": event.step.id,
+            "name": event.step.name,
+            "arguments": ""
+        }
+    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
+        if event.index in current_calls:
+            current_calls[event.index]["arguments"] += event.delta.arguments
+
+# Após interaction.completed, parse final
+import json
+for index, call in current_calls.items():
+    call["arguments"] = json.loads(call["arguments"]) if call["arguments"] else {}
+print(current_calls)
+ +

6.6 Streaming com thinking summaries

+
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="What is the greatest common divisor of 1071 and 462?",
+    generation_config={"thinking_summaries": "auto"},
+    stream=True,
+)
+for event in stream:
+    if event.event_type == "step.delta":
+        if event.delta.type == "thought_summary":
+            if event.delta.content.type == "text":
+                print(f"[Thought] {event.delta.content.text}", end="")
+        elif event.delta.type == "text":
+            print(event.delta.text, end="")
+ +

6.7 Streaming de geração de imagem

+
stream = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="Search the history of the Colosseum and write a short illustrated story.",
+    tools=[{"type": "google_search", "search_types": ["web_search", "image_search"]}],
+    response_format=[{"type": "text"}, {"type": "image"}],
+    stream=True,
+)
+for event in stream:
+    if event.event_type == "step.delta":
+        if event.delta.type == "text":
+            print(event.delta.text, end="")
+        elif event.delta.type == "image":
+            print(f"[Image chunk: {len(event.delta.data)} bytes]")
+ +
+ Eventos desconhecidos: a política de versionamento da API admite novos tipos de eventos ao longo do tempo. Seu cliente deve registrar e pular tipos desconhecidos em vez de gerar erros. +
+ + +
+ +
+

7. Geração de imagens

+ +

Modelos da família Nano Banana geram imagens nativamente como parte do fluxo Interactions. A imagem retorna como bloco image dentro de steps[].content[] e pode ser acessada via interaction.output_image.

+ +

7.1 Modelos disponíveis

+
+ + + + + + +
Nome comercialModel IDFoco
Nano Banana 2gemini-3.1-flash-imageGA desde 28/05/2026 (saiu de preview; o ID -preview é desligado em 25/06/2026). Geração/edição de imagem de alta eficiência e alto volume; suporta thinking_level e saída intercalada texto+imagem
Nano Banana Progemini-3-pro-imageGA desde 28/05/2026. Qualidade máxima (estúdio): tipografia/texto precisos, composições complexas, até 4K; aceita mais imagens de referência por prompt
+
+

Todas as imagens geradas incluem marca d'água SynthID.

+ +

7.2 Limites técnicos

+
    +
  • Aspect ratios: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9. Apenas gemini-3.1-flash-image: 1:4, 4:1, 1:8, 8:1.
  • +
  • Resoluções: 0.5K (apenas Flash 3.1), 1K (padrão), 2K, 4K. O image_size exige K maiúsculo (ex.: "2K") — inclusive o menor valor é "0.5K", não 512.
  • +
  • Imagens de referência: Flash 3.1 aceita até 10 objetos / 4 personagens; Pro 3 aceita até 6 objetos / 5 personagens.
  • +
  • MIME types: image/png, image/jpeg.
  • +
+ +

7.3 Text-to-image

+

Python

+
from google import genai
+import base64
+
+client = genai.Client()
+
+interaction = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme",
+)
+
+with open("generated_image.png", "wb") as f:
+    f.write(base64.b64decode(interaction.output_image.data))
+ +

JavaScript

+
import { GoogleGenAI } from "@google/genai";
+import * as fs from "node:fs";
+
+const ai = new GoogleGenAI({});
+
+const interaction = await ai.interactions.create({
+  model: "gemini-3.1-flash-image",
+  input: "Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme",
+});
+if (interaction.output_image) {
+  fs.writeFileSync("gemini-native-image.png",
+    Buffer.from(interaction.output_image.data, "base64"));
+}
+ +

REST

+
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{
+    "model": "gemini-3.1-flash-image",
+    "input": [{"type": "text", "text": "Create a picture of a nano banana dish..."}]
+  }'
+ +

7.4 Controle de proporção e resolução

+
interaction = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="Da Vinci style anatomical sketch of a dissected Monarch butterfly",
+    response_format={
+        "type": "image",
+        "mime_type": "image/jpeg",
+        "aspect_ratio": "1:1",
+        "image_size": "1K"
+    },
+)
+ +

7.5 Edição (text+image-to-image)

+
import base64
+with open("/path/to/cat_image.png", "rb") as f:
+    image_bytes = f.read()
+
+interaction = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input=[
+        {"type": "text", "text": "Replace the cat with a corgi wearing sunglasses."},
+        {"type": "image", "data": base64.b64encode(image_bytes).decode('utf-8'),
+         "mime_type": "image/png"}
+    ],
+)
+ +

7.6 Edição multi-turn (conversacional)

+
interaction = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="Create a vibrant infographic that explains photosynthesis.",
+    tools=[{"type": "google_search"}],
+)
+
+interaction_2 = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="Update this infographic to be in Spanish. Do not change other elements.",
+    previous_interaction_id=interaction.id,
+    response_format={
+        "type": "image",
+        "mime_type": "image/jpeg",
+        "aspect_ratio": "16:9",
+        "image_size": "2K"
+    },
+)
+ +

7.7 Saída intercalada (texto + imagens)

+

Modelos como gemini-3.1-flash-image podem gerar conteúdo intercalado. Você precisa iterar steps[].content[] em vez de usar output_image:

+
interaction = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="Write the story of the lifecycle of a monarch butterfly, interleave illustrations",
+)
+
+image_counter = 1
+for step in interaction.steps:
+    if step.type == "model_output":
+        for block in step.content:
+            if block.type == "text":
+                print(block.text)
+            elif block.type == "image":
+                with open(f"butterfly_lifecycle_{image_counter}.png", "wb") as f:
+                    f.write(base64.b64decode(block.data))
+                image_counter += 1
+ +

7.8 Thinking durante geração de imagem

+

Thinking é ativado por padrão em modelos de imagem; não pode ser desativado. O modelo gera até dois "thought images" intermediários antes da imagem final. Tokens de thinking são cobrados normalmente.

+
interaction = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="A futuristic city built inside a giant glass bottle floating in space",
+    generation_config={"thinking_level": "high"},
+)
+
+# Inspecionar thought images intermediárias
+for step in interaction.steps:
+    if step.type == "thought":
+        for content_block in step.summary or []:
+            if content_block.type == "image":
+                # base64 de thought image
+                ...
+ +

7.9 Grounding com Google Search (web + image search)

+
interaction = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="A detailed painting of a Timareta butterfly resting on a flower",
+    tools=[{
+      "type": "google_search",
+      "search_types": ["web_search", "image_search"]
+    }],
+    response_format={"type": "image", "mime_type": "image/jpeg", "aspect_ratio": "16:9"}
+)
+
+ Ao usar Image Search é obrigatório exibir search_suggestions do step google_search_result na UI. +
+ + +
+ +
+

8. Compreensão de imagens

+ +

8.1 Métodos de envio

+
    +
  • Files API (recomendado para reuso e arquivos > 20 MB).
  • +
  • Inline Base64 (limite 20 MB no total do payload).
  • +
  • URI público / URL externo.
  • +
+ +

8.2 Formatos suportados

+
    +
  • image/png, image/jpeg, image/webp, image/heic, image/heif, image/gif, image/bmp, image/tiff.
  • +
+ +

8.3 Limites e tokenização

+
    +
  • Máximo: 3.600 imagens por requisição.
  • +
  • Tokens: imagens com ambas dimensões ≤ 384 px = 258 tokens; maiores são divididas em blocos de 768×768 px com 258 tokens cada.
  • +
  • tile_size = floor(min(width, height) / 1.5); blocos = ceil(width/tile_size) × ceil(height/tile_size).
  • +
  • Resolução: parâmetro media_resolution controla detalhe (custos mais altos).
  • +
+ +

8.4 Exemplo — upload via Files API

+
from google import genai
+client = genai.Client()
+
+my_file = client.files.upload(file="path/to/sample.jpg")
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Caption this image."},
+        {"type": "image", "uri": my_file.uri, "mime_type": my_file.mime_type}
+    ]
+)
+print(interaction.output_text)
+ +

8.5 Exemplo — inline Base64

+
import base64
+with open('small.jpg', 'rb') as f:
+    image_bytes = f.read()
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Caption this image."},
+        {"type": "image", "data": base64.b64encode(image_bytes).decode('utf-8'),
+         "mime_type": "image/jpeg"}
+    ]
+)
+ +

8.6 Múltiplas imagens

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "What is different between these two images?"},
+        {"type": "image", "uri": "https://example.com/image1.jpg", "mime_type": "image/jpeg"},
+        {"type": "image", "uri": "https://example.com/image2.jpg", "mime_type": "image/jpeg"}
+    ]
+)
+ +

8.7 Detecção de objetos (bounding boxes)

+

Coordenadas no formato [ymin, xmin, ymax, xmax], normalizadas 0–1000. Redimensione para o tamanho real da imagem.

+
from pydantic import BaseModel, Field
+from typing import List
+
+class BoundingBox(BaseModel):
+    box_2d: List[int] = Field(description="[ymin, xmin, ymax, xmax] normalized 0-1000.")
+    mask: List[List[int]] = Field(description="Segmentation mask as polygon of [x,y].")
+    label: str
+
+class BoundingBoxes(BaseModel):
+    boxes: List[BoundingBox]
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Detect all prominent items. box_2d normalized 0-1000."},
+        {"type": "image", "uri": "https://example.com/image.png", "mime_type": "image/png"}
+    ],
+    response_format={
+        "type": "text",
+        "mime_type": "application/json",
+        "schema": BoundingBoxes.model_json_schema()
+    }
+)
+detected = BoundingBoxes.model_validate_json(interaction.output_text)
+ +

8.8 Segmentação

+

A máscara é um PNG codificado em base64 com valores 0–255. Recomenda-se thinking_level: "minimal" para melhores resultados.

+
Exceção de modelo: a segmentação de imagem não é suportada na família Gemini 3.x via Interactions API. Para esse workload, use o modelo dedicado gemini-robotics-er-1.6-preview (embodied reasoning).
+ + +
+ +
+

9. Áudio — compreensão & geração (TTS)

+ +

9.1 Capacidades

+

Descrição, resumo, transcrição, tradução voz-texto, diarização de locutor, detecção de emoções, análise por timestamp (formato MM:SS).

+ +
Qual modelo usar: não há modelo STT dedicado — a transcrição é compreensão de áudio em qualquer modelo multimodal 3.x. Use gemini-3.5-flash para qualidade máxima, ou gemini-3.1-flash-lite (multimodal, aceita áudio) como opção mais barata e rápida para transcrição em volume — a doc oficial o recomenda explicitamente. Não existe um modelo gemini-3.1-flash "puro". Para transcrição em tempo real, use a Live API (gemini-3.1-flash-live-preview) ou o Google Cloud Speech-to-Text.
+ +

9.2 Especificações técnicas

+
+ + + + + + + + + + +
ParâmetroValor
Tokens por segundo32 tokens/s
1 minuto de áudio1.920 tokens
Duração máxima9,5 horas
Resolução16 Kbps
CanaisMulticanal combinado em mono
Tamanho máximo inline20 MB (total)
+
+ +

9.3 Formatos suportados

+
    +
  • audio/wav, audio/mp3, audio/aiff, audio/aac, audio/ogg, audio/flac, audio/mpeg, audio/m4a, audio/l16, audio/opus, audio/alaw, audio/mulaw.
  • +
+ +

9.4 Upload via Files API

+
from google import genai
+client = genai.Client()
+
+uploaded_file = client.files.upload(file="path/to/sample.mp3")
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Describe this audio clip"},
+        {"type": "audio", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
+    ]
+)
+print(interaction.output_text)
+ +

9.5 Transcrição com diarização e emoção

+
response_schema = {
+    "type": "object",
+    "properties": {
+        "summary": {"type": "string"},
+        "segments": {
+            "type": "array",
+            "items": {
+                "type": "object",
+                "properties": {
+                    "speaker": {"type": "string"},
+                    "timestamp": {"type": "string"},
+                    "content": {"type": "string"},
+                    "language": {"type": "string"},
+                    "emotion": {"type": "string",
+                                "enum": ["happy", "sad", "angry", "neutral"]}
+                },
+                "required": ["speaker", "timestamp", "content", "emotion"]
+            }
+        }
+    }
+}
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "audio", "uri": uploaded_file.uri, "mime_type": "audio/mp3"},
+        {"type": "text", "text": "Transcribe with diarization, language, emotion."}
+    ],
+    response_format={"type": "text", "mime_type": "application/json",
+                     "schema": response_schema},
+)
+print(interaction.output_text)
+ +

9.6 Consulta por timestamps

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Provide a transcript from 02:30 to 03:29."},
+        {"type": "audio", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
+    ]
+)
+ + + +

9.7 Geração de áudio (TTS)

+

A Interactions API também gera áudio a partir de texto. Defina response_modalities=["audio"] e passe generation_config.speech_config; o modelo TTS atual é gemini-3.1-flash-tts-preview (Preview). Estilo, sotaque, ritmo e tom são controláveis por linguagem natural no próprio prompt. O áudio sai em interaction.output_audio.data (base64; PCM 24 kHz, 16-bit, mono).

+

Single-speaker — Python

+
from google import genai
+import base64, wave
+
+client = genai.Client()
+
+interaction = client.interactions.create(
+    model="gemini-3.1-flash-tts-preview",
+    input="Say cheerfully: Have a wonderful day!",
+    response_modalities=["audio"],
+    generation_config={"speech_config": [{"voice": "Kore"}]},
+)
+
+pcm = base64.b64decode(interaction.output_audio.data)
+with wave.open("out.wav", "wb") as wf:
+    wf.setnchannels(1); wf.setsampwidth(2); wf.setframerate(24000)
+    wf.writeframes(pcm)
+

REST

+
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{
+    "model": "gemini-3.1-flash-tts-preview",
+    "input": "Say cheerfully: Have a wonderful day!",
+    "response_modalities": ["audio"],
+    "generation_config": {"speech_config": [{"voice": "Kore"}]}
+  }'
+ +

9.8 Multi-speaker (até 2 locutores)

+

Para diálogos, configure um item de speech_config por locutor (máximo 2), cada um com speaker (o nome usado no prompt) e voice.

+
prompt = """TTS the following conversation between Joe and Jane:
+         Joe: How's it going today Jane?
+         Jane: Not too bad, how about you?"""
+
+interaction = client.interactions.create(
+    model="gemini-3.1-flash-tts-preview",
+    input=prompt,
+    response_modalities=["audio"],
+    generation_config={"speech_config": [
+        {"speaker": "Joe", "voice": "Kore"},
+        {"speaker": "Jane", "voice": "Puck"},
+    ]},
+)
+pcm = base64.b64decode(interaction.output_audio.data)
+ +

9.9 Vozes, idiomas & limites

+
    +
  • 30 vozes pré-construídas no campo voice — ex.: Zephyr (bright), Puck (upbeat), Charon (informative), Kore (firm), Fenrir (excitable), Leda (youthful), Aoede (breezy), Achird (friendly), Sulafat (warm)… (lista completa na doc oficial).
  • +
  • Idioma automático: o modelo detecta o idioma da entrada; ~70 idiomas suportados (en, pt, es, fr, de, it, hi, ja, ko, ar, cmn…).
  • +
  • Saída: PCM 24 kHz, 16-bit, mono — recuperada via interaction.output_audio.data (base64).
  • +
+
Limitações do TTS: entrada somente texto, saída somente áudio; janela de contexto de 32k tokens; não suporta streaming; ocasionalmente o modelo retorna tokens de texto e o servidor falha com 500 (implemente retry automático); prompts vagos podem ser rejeitados (PROHIBITED_CONTENT) — adicione um preâmbulo claro instruindo a sintetizar fala e marque onde começa o texto a ser falado. A qualidade pode degradar após alguns minutos — divida transcrições longas.
+ +
+ +
+

10. Compreensão de vídeo

+ +

10.1 Métodos de entrada

+
+ + + + + + + + +
MétodoTamanho máx.Uso
Files API20 GB (pago) / 2 GB (free)Vídeos > 100 MB, longos (>10 min), reutilizáveis
Cloud Storage2 GB / arquivo, sem limite totalGrandes, persistentes
Inline (Base64)< 100 MBCurtos, uso único
URLs YouTube—Vídeos públicos
+
+ +

10.2 Formatos suportados

+

video/mp4, video/mpeg, video/mov, video/avi, video/x-flv, video/mpg, video/webm, video/wmv, video/3gpp.

+ +

10.3 Especificações técnicas

+
+ + + + + + + + + + +
AspectoValor
Janela 1M tokens1 h (resolução padrão) ou 3 h (resolução baixa)
Amostragem visual1 FPS
Áudio (Files API)1 Kbps, mono
Tokens — padrão~300 tokens/s (258 frame + 32 áudio + metadados)
Tokens — baixa~100 tokens/s (66 frame + 32 áudio + metadados)
Formato timestampMM:SS
+
+ +

10.4 Upload & espera por ACTIVE

+
from google import genai
+import time, base64
+client = genai.Client()
+
+myfile = client.files.upload(file="path/to/sample.mp4")
+while not myfile.state or myfile.state.name != "ACTIVE":
+    print("Processing video...")
+    time.sleep(5)
+    myfile = client.files.get(name=myfile.name)
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "video", "uri": myfile.uri, "mime_type": myfile.mime_type},
+        {"type": "text", "text": "Summarize this video. Then create a quiz with key."}
+    ]
+)
+print(interaction.steps[-1].content[0].text)
+ +

10.5 YouTube URL

+
interaction = client.interactions.create(
+    model='gemini-3.5-flash',
+    input=[
+        {"type": "text", "text": "Summarize the video in 3 sentences."},
+        {"type": "video", "uri": "https://www.youtube.com/watch?v=9hE5-98ZeCg"}
+    ]
+)
+
    +
  • Gratuito: até 8 h/dia.
  • +
  • Pago: sem limite.
  • +
  • Os modelos Gemini 3.x aceitam até 10 vídeos por requisição.
  • +
  • Apenas vídeos públicos.
  • +
+ +

10.6 Inline (vídeos pequenos)

+
video_bytes = open("video.mp4", 'rb').read()
+interaction = client.interactions.create(
+    model='gemini-3.5-flash',
+    input=[
+        {"type": "text", "text": "Please summarize the video in 3 sentences."},
+        {"type": "video", "data": base64.b64encode(video_bytes).decode('utf-8'),
+         "mime_type": "video/mp4"}
+    ]
+)
+ +

10.7 Timestamps e descrição multimodal

+
prompt = "Describe key events with audio and visual details. Include timestamps."
+# ou: "What are the examples given at 00:05 and 00:10 supposed to show us?"
+ +
+ Limitação na Interactions API: o campo video_metadata (intervalos de corte, FPS customizado) presente em generateContent ainda não está disponível em Interactions. +
+ + +
+ +
+

11. Processamento de documentos (PDF)

+ +

11.1 Capacidades

+

PDFs são processados com visão nativa: leitura de texto, imagens, diagramas, gráficos, tabelas, preservação de layout. Outros formatos (HTML, Markdown, CSV, etc.) são tratados como texto puro.

+ +

11.2 Limites técnicos

+
+ + + + + + + + + + +
ParâmetroValor
Tamanho máximo50 MB (inline)
Páginas máximas1.000
Tokens por página258
Resolução máx.3072 × 3072 px
Resolução mín.768 × 768 px
Files API retention48 horas
+
+ +

11.3 Inline Base64

+
import base64
+with open('path/to/document.pdf', 'rb') as f:
+    pdf_bytes = f.read()
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "document",
+         "data": base64.b64encode(pdf_bytes).decode('utf-8'),
+         "mime_type": "application/pdf"},
+        {"type": "text", "text": "Summarize this document"}
+    ]
+)
+print(interaction.output_text)
+ +

11.4 Files API (PDFs grandes)

+
import httpx, io
+doc_io = io.BytesIO(httpx.get("https://arxiv.org/pdf/2312.11805").content)
+sample_doc = client.files.upload(file=doc_io, config={'mime_type': 'application/pdf'})
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "document", "uri": sample_doc.uri, "mime_type": sample_doc.mime_type},
+        {"type": "text", "text": "Summarize this document"}
+    ]
+)
+ +

11.5 Múltiplos PDFs

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "document", "uri": sample_pdf_1.uri, "mime_type": "application/pdf"},
+        {"type": "document", "uri": sample_pdf_2.uri, "mime_type": "application/pdf"},
+        {"type": "text", "text": "Compare main benchmarks between these papers. Output as table."}
+    ]
+)
+ +

11.6 Gemini 3 — media_resolution & texto nativo

+
    +
  • media_resolution: unspecified (default), low, medium, high, ultra_high (só por item de conteúdo).
  • +
  • Texto nativo do PDF: agora extraído diretamente e fornecido ao modelo.
  • +
  • Faturamento: tokens de texto nativo não são cobrados; páginas processadas como imagem entram na modalidade IMAGE.
  • +
  • Por item de conteúdo (só Gemini 3): defina resolution dentro de cada bloco image/video/document para misturar resoluções no mesmo request.
  • +
+ +

Tokens por valor de media_resolution (modelos Gemini 3) — fonte: ai.google.dev/gemini-api/docs/interactions/media-resolution:

+
+ + + + + + + + + +
MediaResolutionImagemVídeoPDF
unspecified (default)112070560
low28070280 + texto nativo
medium56070560 + texto nativo
high11202801120 + texto nativo
ultra_high2240N/AN/A
+
+

Recomendado: imagens high (1120); PDFs medium (560 — a qualidade satura aí para documentos comuns); vídeo geral low/medium (70/frame, tratados igual); vídeo com texto denso high (280/frame). ultra_high existe só por item de conteúdo e é voltado a Computer Use.

+ + +
+ +
+

12. Files API & métodos de entrada

+ +

12.1 Quando usar cada método

+
+ + + + + + + + +
MétodoTamanho máx.PersistênciaIdeal para
Inline (Base64)100 MB / 50 MB PDFsNenhumaTestes, arquivos pequenos, tempo real
Files API2 GB / arquivo, 20 GB / projeto48 horasArquivos grandes, reuso
GCS URI (gs://)2 GB / arquivo, sem limite totalRegistro: acesso por até 30 dias (não armazena; buscado por requisição)Já no Cloud Storage
URLs externas100 MB / payloadBuscado por requisiçãoDados públicos, S3 pré-assinado, SAS Azure
+
+ +

12.2 Upload & uso

+
myfile = client.files.upload(file="path/to/sample.mp3")
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "audio", "uri": myfile.uri, "mime_type": myfile.mime_type},
+        {"type": "text", "text": "Describe this audio clip"}
+    ]
+)
+ +

12.3 Listar / obter / excluir

+
for f in client.files.list(): print(f.name)
+client.files.get(name=file_name)
+client.files.delete(name=file_name)
+ +

12.4 Registrar arquivos do GCS

+
from google.oauth2.service_account import Credentials
+GCS_READ_SCOPES = [
+  'https://www.googleapis.com/auth/devstorage.read_only',
+  'https://www.googleapis.com/auth/cloud-platform'
+]
+credentials = Credentials.from_service_account_file('service-account.json',
+                                                   scopes=GCS_READ_SCOPES)
+
+registered = client.files.register_files(
+    uris=["gs://my_bucket/some_object.pdf"],
+    auth=credentials
+)
+for f in registered.files:
+    response = client.interactions.create(
+        model="gemini-3.5-flash",
+        input=[
+            {"type": "document", "uri": f.uri, "mime_type": f.mime_type},
+            {"type": "text", "text": "Summarize this file."}
+        ]
+    )
+ +
+ A Interactions API não aceita URLs externas (S3/SAS) como fonte de mídia — use upload inline ou a Files API. Arquivos na Files API expiram em 48 h. PDFs inline têm limite separado de 50 MB. +
+ + +
+ +
+

13. Function calling

+ +

Function calling conecta o modelo a ferramentas/APIs externas. Em vez de produzir só texto, o modelo decide quando emitir uma step function_call com id, name e arguments. Seu app executa a função e devolve o resultado num step function_result.

+ +

13.1 Esquema da declaração de função

+
+ + + + + + + + + +
CampoTipoObrigatórioDescrição
typestringSimSempre "function" (no nível superior de tools).
namestringSimsnake_case ou camelCase.
descriptionstringSimExplicação clara da finalidade.
parametersobjectSimJSON Schema (subset OpenAPI).
parameters.requiredstring[]NãoLista de parâmetros obrigatórios.
+
+ +

13.2 Fluxo completo (4 etapas)

+
    +
  1. Definir a declaração
  2. +
  3. Chamar o modelo com tools=[...]
  4. +
  5. Executar a função no cliente (lendo step.name e step.arguments)
  6. +
  7. Enviar function_result referenciando call_id
  8. +
+ +

13.3 Exemplo — set_light_values

+

Python

+
set_light_values_declaration = {
+    "type": "function",
+    "name": "set_light_values",
+    "description": "Sets the brightness and color temperature of a light.",
+    "parameters": {
+        "type": "object",
+        "properties": {
+            "brightness": {"type": "integer", "description": "0–100"},
+            "color_temp": {"type": "string",
+                           "enum": ["daylight", "cool", "warm"]},
+        },
+        "required": ["brightness", "color_temp"],
+    },
+}
+
+def set_light_values(brightness, color_temp):
+    return {"brightness": brightness, "colorTemperature": color_temp}
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Turn the lights down to a romantic level",
+    tools=[set_light_values_declaration],
+)
+
+fc_step = next(s for s in interaction.steps if s.type == "function_call")
+result = set_light_values(**fc_step.arguments)
+
+final = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[{
+        "type": "function_result",
+        "name": fc_step.name,
+        "call_id": fc_step.id,
+        "result": [{"type": "text", "text": str(result)}],
+    }],
+    tools=[set_light_values_declaration],
+    previous_interaction_id=interaction.id,
+)
+print(final.output_text)
+ +

JavaScript

+
const setLightValuesTool = {
+  type: 'function',
+  name: 'set_light_values',
+  description: 'Sets the brightness and color temperature of a light.',
+  parameters: {
+    type: 'object',
+    properties: {
+      brightness: { type: 'number' },
+      color_temp: { type: 'string', enum: ['daylight', 'cool', 'warm'] },
+    },
+    required: ['brightness', 'color_temp'],
+  },
+};
+
+const interaction = await client.interactions.create({
+  model: 'gemini-3.5-flash',
+  input: 'Turn the lights down to a romantic level',
+  tools: [setLightValuesTool],
+});
+
+const fcStep = interaction.steps.find(s => s.type === 'function_call');
+const result = setLightValues(fcStep.arguments.brightness,
+                              fcStep.arguments.color_temp);
+
+const final = await client.interactions.create({
+  model: 'gemini-3.5-flash',
+  input: [{
+    type: 'function_result',
+    name: fcStep.name,
+    call_id: fcStep.id,
+    result: [{ type: 'text', text: JSON.stringify(result) }]
+  }],
+  tools: [setLightValuesTool],
+  previous_interaction_id: interaction.id,
+});
+console.log(final.output_text);
+ +

13.4 Modos de tool_choice

+
+ + + + + + + + +
ModoComportamento
auto (padrão)Modelo decide se chama função ou responde direto.
anyModelo é forçado a chamar alguma função.
noneModelo não pode chamar funções.
validated (preview)Garante aderência ao schema.
+
+
generation_config = {
+    "tool_choice": {
+        "allowed_tools": {
+            "mode": "any",
+            "tools": ["get_current_temperature"]
+        }
+    }
+}
+ +

13.5 Chamadas paralelas

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Turn this place into a party!",
+    tools=[power_disco_ball, start_music, dim_lights],
+    generation_config={"tool_choice": "any"},
+)
+for step in interaction.steps:
+    if step.type == "function_call":
+        print(f"{step.name}({step.arguments})")
+ +

13.6 Chamadas composicionais

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="If it's warmer than 20°C in London, set the thermostat to 20°C, otherwise 18°C.",
+    tools=[get_weather_forecast_declaration,
+           set_thermostat_temperature_declaration],
+)
+ +

13.7 Function result multimodal (Gemini 3)

+
base64_image_data = base64.b64encode(image_bytes).decode("utf-8")
+final = client.interactions.create(
+    model="gemini-3.5-flash",
+    previous_interaction_id=interaction.id,
+    input=[{
+        "type": "function_result",
+        "name": tool_call.name,
+        "call_id": tool_call.id,
+        "result": [
+            {"type": "text",  "text": "instrument.jpg"},
+            {"type": "image", "mime_type": "image/jpeg", "data": base64_image_data},
+        ],
+    }],
+)
+ +

13.8 MCP Server tools (HTTP Streaming)

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Check the status of my last server deployment.",
+    tools=[{
+        "type": "mcp_server",
+        "name": "deployment_tracker",
+        "url": "https://mcp.example.com/mcp",
+        "headers": {"Authorization": "Bearer my-token"},
+    }]
+)
+
+ Restrições do MCP remoto: apenas HTTP streaming (não SSE). Gemini 3 ainda não suporta MCP remoto. Nomes de servidor não podem conter - (use snake_case). +
+ +

13.9 Streaming de function calling — acumular arguments_delta

+
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="What is the weather in Paris?",
+    tools=[weather_tool],
+    stream=True
+)
+current_calls = {}
+for event in stream:
+    if event.event_type == "step.start" and event.step.type == "function_call":
+        current_calls[event.index] = {"id": event.step.id, "name": event.step.name, "arguments": ""}
+    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
+        current_calls[event.index]["arguments"] += event.delta.arguments
+ +

13.10 Limitações

+
    +
  • Apenas subset OpenAPI suportado para parameters.
  • +
  • Em modo any, esquemas muito grandes podem ser rejeitados.
  • +
  • Recomendação: manter ≤ 10–20 ferramentas ativas.
  • +
  • Gemini 3 ainda não suporta MCP remoto.
  • +
+ + +
+ +
+

14. Saída estruturada

+ +

Configure response_format com type: "text", mime_type: "application/json" e um schema (JSON Schema, Pydantic ou Zod) para forçar resposta estruturada.

+ +

14.1 Exemplo — extrator de receitas

+

Python (Pydantic)

+
from pydantic import BaseModel, Field
+from typing import List, Optional
+
+class Ingredient(BaseModel):
+    name: str = Field(description="Name of the ingredient.")
+    quantity: str = Field(description="Quantity with units.")
+
+class Recipe(BaseModel):
+    recipe_name: str
+    prep_time_minutes: Optional[int]
+    ingredients: List[Ingredient]
+    instructions: List[str]
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Extract this recipe: ...",
+    response_format={
+        "type": "text",
+        "mime_type": "application/json",
+        "schema": Recipe.model_json_schema()
+    },
+)
+recipe = Recipe.model_validate_json(interaction.output_text)
+ +

JavaScript (Zod)

+
import * as z from "zod";
+
+const recipeJsonSchema = {
+  type: "object",
+  properties: {
+    recipe_name: { type: "string" },
+    ingredients: {
+      type: "array",
+      items: { type: "object", properties: {
+        name: { type: "string" },
+        quantity: { type: "string" }
+      }, required: ["name", "quantity"] }
+    },
+    instructions: { type: "array", items: { type: "string" } }
+  },
+  required: ["recipe_name", "ingredients", "instructions"]
+};
+
+const interaction = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  input: "Extract this recipe: ...",
+  response_format: {
+    type: 'text',
+    mime_type: 'application/json',
+    schema: recipeJsonSchema
+  },
+});
+const recipeSchema = z.fromJSONSchema(recipeJsonSchema);
+const recipe = recipeSchema.parse(JSON.parse(interaction.output_text));
+ +

14.2 Streaming de saída estruturada

+
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="The new UI is intuitive. Long summary please!",
+    response_format={"type": "text", "mime_type": "application/json",
+                     "schema": Feedback.model_json_schema()},
+    stream=True
+)
+for event in stream:
+    if event.event_type == "step.delta" and event.delta.text:
+        print(event.delta.text, end="")
+ +

14.3 Saída estruturada + ferramentas (Preview · Gemini 3)

+
interaction = client.interactions.create(
+    model="gemini-3.1-pro-preview",
+    input="Search for all details for the latest Euro.",
+    tools=[{"type": "google_search"}, {"type": "url_context"}],
+    response_format={
+        "type": "text",
+        "mime_type": "application/json",
+        "schema": MatchResult.model_json_schema()
+    },
+)
+

Ferramentas compatíveis: google_search, url_context, code_execution, file_search e function calling. Apenas modelos Gemini 3.

+ +

14.4 Tipos JSON Schema aceitos

+
    +
  • string, number, integer, boolean, object, array.
  • +
  • Nullable: {"type": ["string", "null"]}.
  • +
  • enum, format (date-time, date, time) em strings.
  • +
  • minimum, maximum em números.
  • +
  • items, prefixItems, minItems, maxItems em arrays.
  • +
  • properties, required, additionalProperties em objetos.
  • +
+ + +
+ +
+

15. Thinking & assinaturas de pensamento

+ +

Os modelos Gemini 3.x usam raciocínio em múltiplas etapas, expostos como steps thought em interaction.steps. Cada step contém signature (representação criptografada do estado interno) e opcionalmente summary (resumo em texto/imagem).

+ +

15.1 Modelos & níveis de thinking

+
+ + + + + + + + +
ModeloThinking padrãoNíveis
gemini-3.1-pro-previewAtivado (alto)low, medium, high
gemini-3-flash-previewAtivado (alto)low, medium, high
gemini-3.5-flashAtivado (médio, padrão)minimal, low, medium, high
gemini-3.1-flash-liteminimal (padrão)minimal, low, medium, high
+
+

O minimal não garante que o thinking esteja desligado; gemini-3.5-flash e gemini-3.1-flash-lite não suportam thinking-off completo (verificado 2026-06-03 na doc de thinking).

+ +

15.2 Controlar nível

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Provide a list of 3 famous physicists and their key contributions",
+    generation_config={"thinking_level": "low"}
+)
+ +

15.3 Resumos de pensamento (thinking_summaries)

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="What is the sum of the first 50 prime numbers?",
+    generation_config={"thinking_summaries": "auto"}
+)
+for step in interaction.steps:
+    if step.type == "thought":
+        for block in step.summary or []:
+            if block.type == "text":
+                print("Thought:", block.text)
+    elif step.type == "model_output":
+        for block in step.content:
+            if block.type == "text":
+                print("Answer:", block.text)
+ +

15.4 Streaming com raciocínio (dois tipos de delta)

+
+ + + + + + +
delta.typeCargaQuando
thought_summarycontent (texto/imagem)Resumos incrementais.
thought_signaturesignatureÚltimo delta antes de step.stop.
+
+
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Alice, Bob, Carol live in red/green/blue houses. ...",
+    generation_config={"thinking_summaries": "auto"},
+    stream=True
+)
+for event in stream:
+    if event.event_type == "step.delta":
+        if event.delta.type == "thought_summary":
+            print(f"[Thought] {event.delta.content.text}", end="")
+        elif event.delta.type == "text":
+            print(event.delta.text, end="")
+ +

15.5 Assinaturas de pensamento (signature)

+

São representações criptografadas do estado de raciocínio interno. Regra: se você receber uma assinatura em uma resposta, transmita-a exatamente como recebida ao enviar o histórico na próxima chamada. Em Gemini 3 isso é obrigatório em chamadas de função — omissão gera erro 400.

+ +
+ + + + + + +
ModoComportamento
store=true (server-side)SDK e servidor gerenciam assinaturas automaticamente. Nenhuma ação manual.
store=false (stateless)Você precisa reenviar todos os blocos thought com signature exatamente como recebidos. Mudar ou pular = erro 400 em FC.
+
+ +

15.6 Preço & tokens de raciocínio

+

Custo = tokens de saída + tokens de raciocínio. O campo interaction.usage.total_thought_tokens expõe o total gerado. Apenas o resumo é exposto ao desenvolvedor — o conteúdo completo de raciocínio fica interno.

+ +

15.7 Recomendações de nível

+
+ + + + + + + +
CenárioNível
Fatos diretos, classificação trivialminimal
Comparações, raciocínio criativoPadrão (medium)
Programação avançada, matemática difícil, AIMEhigh
+
+ + +
+ +
+

16. Caching (implícito)

+ +

A Interactions API suporta apenas cache implícito. Cache explícito (criação manual de objetos de cache) não está disponível na Interactions; para isso continue usando generateContent com client.caches.create(...).

+ +

16.1 Como funciona

+
    +
  • Ativado por padrão nos modelos Gemini 3.x.
  • +
  • Economia de custo aplicada automaticamente em cache hits.
  • +
  • Reutilização via previous_interaction_id dispara o cache.
  • +
+ +

16.2 Limites mínimos por modelo

+
+ + + + + + + +
ModeloTokens mínimos para cache
Gemini 3.5 Flash1024
Gemini 3.1 Flash-Lite1024
Gemini 3.1 Pro Preview4096
+

Fonte oficial (caching, 2026-06-03): a tabela publicada lista os mínimos por nome de preview — Gemini 3 Flash Preview = 1024, Gemini 3 Pro Preview = 4096, Gemini 2.5 Flash = 1024, Gemini 2.5 Pro = 4096. O mínimo por ID GA não é publicado (o gemini-3.1-flash-lite não tem linha própria); os valores acima seguem o padrão por tier (Flash = 1024, Pro = 4096). [UNVERIFIED: mapeamento exato por ID GA]

+
+ +

16.3 Maximizar cache hits

+
    +
  • Coloque grandes conteúdos comuns no início do prompt.
  • +
  • Envie requisições com prefixos semelhantes em curto intervalo.
  • +
  • Use previous_interaction_id para reutilizar histórico.
  • +
+ +

16.4 Verificar tokens em cache

+

Disponível em interaction.usage.total_cached_tokens (na Interactions API o objeto é usage; usage_metadata/usageMetadata é a nomenclatura do generateContent).

+ + +
+ +
+

17. Ferramentas server-side

+ +

Além de function calling (cliente), a Interactions API integra diversas ferramentas executadas pelo servidor do Google. Habilite com tools=[{"type": "<tool_name>"}] e elas aparecem como steps na timeline.

+ +

17.1 Catálogo de ferramentas server-side

+
+ + + + + + + + + + + +
TooltypeCasos de uso
Google Searchgoogle_searchEventos atuais, verificação de fatos, citações
Google Mapsgoogle_mapsAssistentes com localização, itinerários, lugares
Code Executioncode_executionCálculos precisos em Python sandbox
URL Contexturl_contextLeitura/comparação de páginas/PDFs/JSON
Computer Use (preview)computer_useAgentes que veem tela e clicam
File Searchfile_searchRAG sobre file_search_stores
MCP Servermcp_serverFerramentas externas via HTTP streaming
+
+
+ + + +
+

17.2 Google Maps (grounding)

+ +
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="What are the best Italian restaurants within a 15-minute walk from here?",
+    tools=[{
+        "type": "google_maps",
+        "enable_widget": True,
+        "latitude": 34.050481,
+        "longitude": -118.248526
+    }]
+)
+for step in interaction.steps:
+    if step.type == "google_maps_result":
+        for place in step.result.places:
+            print(f"- {place.name} ({place.url})")
+        if step.result.widget_context_token:
+            print(f"<gmp-place-contextual context-token='{step.result.widget_context_token}'></gmp-place-contextual>")
+ +

Preços & cota

+
    +
  • Preço: US$ 25 / 1.000 prompts fundamentados.
  • +
  • Nível gratuito: 500 requisições/dia.
  • +
  • Cobrado apenas quando retorna ≥ 1 lugar.
  • +
+ + +
+ +
+

17.3 Code Execution

+ +

O modelo gera e executa Python em sandbox seguro. Steps code_execution_call trazem o código, e code_execution_result traz a saída.

+ +
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="What is the sum of the first 50 prime numbers? Generate and run code.",
+    tools=[{"type": "code_execution"}],
+)
+for step in interaction.steps:
+    if step.type == "code_execution_call":
+        print("CODE:\n", step.arguments.code)
+    elif step.type == "code_execution_result":
+        print("OUTPUT:", step.result)
+ +

Limites

+
    +
  • Tempo máximo de execução: 30 s.
  • +
  • Entrada máxima: ~1 M tokens (~2 MB texto).
  • +
  • Até 5 retentativas em erro.
  • +
  • Sandbox apenas com bibliotecas pré-instaladas; não é possível instalar próprias.
  • +
  • Apenas gráficos gerados com matplotlib são renderizados como imagem inline no resultado.
  • +
+ +

Bibliotecas disponíveis (extrato)

+

matplotlib, numpy, pandas, scipy, scikit-learn, tensorflow, sympy, pillow, opencv-python, geopandas, pyPDF2, python-docx, python-pptx, openpyxl, xlrd, reportlab, fpdf, pylatex, jinja2, seaborn, chess, imageio, tabulate, jsonschema, ...

+ +
Superfície (Developer API vs Vertex): como toda a Interactions API, este code_execution é documentado e exemplificado na Developer API. Na Vertex / Gemini Enterprise Agent Platform o CodeExecution consta apenas no schema (sem exemplo prático) e a execução de código é documentada via generateContent; em teste, code_execution via Interactions não funcionou sob auth Vertex. Em Vertex, use generateContent + code_execution. Detalhes no guia de code tools. (2026-06-19)
+ + +
+ +
+

17.4 URL Context

+ +
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Compare ingredients of these recipes: https://... and https://...",
+    tools=[{"type": "url_context"}]
+)
+for step in interaction.steps:
+    if step.type == "url_context_result":
+        print(step.result.url, "→", step.result.status)
+ +

Limites & aceitação

+
    +
  • Até 20 URLs por requisição.
  • +
  • Até 34 MB por URL.
  • +
  • Aceita PDF, HTML, JSON, CSS, JS, CSV, RTF, PNG/JPEG/BMP/WebP.
  • +
  • Não aceita: paywalls, vídeos do YouTube, Google Workspace, áudio/vídeo, localhost/redes privadas/ngrok/pinggy.
  • +
+ +

Status (url_retrieval_status)

+

URL_RETRIEVAL_STATUS_SUCCESS, URL_RETRIEVAL_STATUS_UNSAFE.

+ + +
+ +
+

17.5 Computer Use (preview)

+ +

Agentes que "veem" tela via screenshots e "agem" via ações de UI (cliques, digitação, scroll). Modelos suportados (usar outro modelo gera erro):

+
    +
  • gemini-3-flash-preview — suporte nativo a Computer Use (não precisa de modelo separado para acessar a ferramenta).
  • +
  • gemini-2.5-computer-use-preview-10-2025 — modelo dedicado de Computer Use.
  • +
+
gemini-3.5-flash ainda não suporta Computer Use; use gemini-3-flash-preview (mais recente com suporte nativo).
+ +

Ações disponíveis (resumo)

+

open_web_browser, navigate(url), click_at(x,y), type_text_at(x,y,text,press_enter), hover_at, scroll_at, scroll_document(direction), drag_and_drop, key_combination(keys), go_back, go_forward, wait_5_seconds, search.

+
+ Coordenadas em escala 0–999; converta para pixels reais antes de executar. +
+ +

Habilitar (Interactions API)

+
interaction = client.interactions.create(
+    model="gemini-3-flash-preview",  # suporte nativo a Computer Use
+    input="Find a flight to Tokyo",
+    tools=[{
+        "type": "computer_use",
+        "environment": "browser",
+        "excluded_predefined_functions": ["drag_and_drop"],
+    }],
+)
+ +

Segurança

+
    +
  • Algumas respostas trazem safety_decision: require_confirmation — implemente HITL.
  • +
  • Use sandbox (VM/Docker), allowlist de URLs e logs detalhados.
  • +
  • Não use para decisões críticas sem supervisão humana.
  • +
+ + +
+ + + +
+

17.7 MCP Server tools

+ +

Conecte agentes a servidores MCP externos via HTTP streaming.

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Check status of latest deploy",
+    tools=[{
+        "type": "mcp_server",
+        "name": "deployment_tracker",
+        "url": "https://mcp.example.com/mcp",
+        "headers": {"Authorization": "Bearer token"},
+        "allowed_tools": {"mode": "auto", "tools": ["check_deploy"]}
+    }]
+)
+
+ Restrições: apenas HTTP streaming (não SSE). Gemini 3 ainda não suporta MCP remoto. Nomes não podem conter -. +
+
+ +
+

17.8 Combinando ferramentas (Preview · Gemini 3)

+ +
+

✅ Sim: Gemini 3.x combina built-in tools + function calling no mesmo turno. Não é workaround — é uma feature Preview oficial da série Gemini 3, baseada em tool context circulation. O modelo pode, por exemplo, se ancorar em dados frescos da web (Google Search) antes de chamar a sua lógica de negócio (custom function) em uma única geração. Funciona tanto em client.models.generate_content(...) quanto aqui na Interactions API. [doc]

+
+ +

Como ligar: declare os built-in tools junto com as custom functions e ligue o flag include_server_side_tool_invocations=true. A cada turno, devolva todos os parts retornados (id, tool_type, thought_signature) exatamente como recebidos — omitir o thought_signature faz o modelo dar erro. O combo opera em modo VALIDATED (o AUTO não é suportado com o flag ligado).

+ +
# Forma generate_content (clássica) — built-in (google_search) + custom (getWeather) no mesmo turno
+from google import genai
+from google.genai import types
+
+client = genai.Client()
+getWeather = {
+    "name": "getWeather",
+    "description": "Gets the weather for a requested city.",
+    "parameters": {"type": "object",
+                   "properties": {"city": {"type": "string"}},
+                   "required": ["city"]},
+}
+response = client.models.generate_content(
+    model="gemini-3-flash-preview",
+    contents="Qual a cidade mais ao norte dos EUA? Como está o tempo lá hoje?",
+    config=types.GenerateContentConfig(
+        tools=[types.Tool(
+            google_search=types.ToolGoogleSearch(),   # built-in (server-side)
+            function_declarations=[getWeather],        # custom (client-side)
+        )],
+        include_server_side_tool_invocations=True,     # liga a circulação de contexto
+    ),
+)
+# A resposta traz toolCall/toolResponse (built-in) + functionCall (custom) para você executar.
+# No próximo turno reenvie TODOS os parts (com thought_signature) + o functionResponse com o mesmo id.
+ +
Na Interactions API: declare as tools como dicts ({"type":"google_search"}, {"type":"code_execution"}, …) ao lado das suas function tools; a circulação de contexto e o thought_signature são carregados automaticamente entre turnos quando você encadeia via previous_interaction_id. Para o caso vision-grounded (Code Execution + imagem), veja 17.9 Agentic Vision. Endpoint dedicado para bash + custom tools: gemini-3.1-pro-preview-customtools.
+ +

Matriz de compatibilidade

+
+ + + + + + + + + + + +
FerramentaLadoSuporte à circulação de contexto
Google SearchServidorSim
Google MapsServidorSim
URL ContextServidorSim
File SearchServidorSim
Code ExecutionServidorSim (executableCode+codeExecutionResult)
Computer UseClienteSim (functionCall/functionResponse)
Funções personalizadasClienteSim
+
+ + +
+ +
+

17.9 Agentic Vision com gemini-3.5-flash (Code Execution + imagem)

+ +
+

✅ Oficialmente suportado em Gemini 3 Flash. O modelo escreve e executa Python sobre a própria imagem (crop, zoom, threshold, edge detection, contagem, anotação) em vez de "chutar olhando o thumbnail". A doc oficial chama isso de Code Execution with images e lista três usos: zoom & inspect (detecta detalhe pequeno e re-examina em alta resolução), visual math (cálculo multi-passo por código) e image annotation (desenha setas/caixas para responder). Ativa-se habilitando Code Execution + Thinking. [doc]

+

✅ Já funciona com gemini-3.5-flash — e pela Interactions API. Validamos este contrato em produção: agentic vision (Code Execution sobre a própria imagem) roda com gemini-3.5-flash via client.interactions.create — testado e funcionando, multi-turn inclusive. A doc oficial demonstra o recurso pelo generate_content; aqui é a mesma capacidade exposta pela Interactions API.

+
+ +
+

⚠️ Escopo do recurso — família Flash. (A capacidade já está confirmada com gemini-3.5-flash pela Interactions API, acima; aqui é só a delimitação de escopo.)

+
    +
  • É um recurso da família Flash — não dos modelos Pro. A doc oficial documenta Code Execution with images apenas na linha Gemini 3 Flash; os exemplos oficiais usam o ID gemini-3-flash-preview.
  • +
  • Este guia usa gemini-3.5-flash — escolha validada por teste, não inferência. Rodamos o contrato com code_execution + thinking_level (testado até high) em benchmark de produção (n=198 derma 128 px; ~$0,005/caso em medium; p50 ~6 s) e funcionou. O gemini-3-flash-preview é apenas o ID dos exemplos da doc; o gemini-3.5-flash é o Flash estável atual da mesma família.
  • +
+

Reverificado na fonte oficial em 2026-06-04.

+
+ +

Diferenças entre as APIs (este guia × exemplo oficial)

+
+

Atenção ao copiar código. A doc oficial demonstra Code Execution with images via client.models.generate_content; este guia usa a Interactions API (client.interactions.create), que tem nomes de campo e envelope diferentes. O recurso e o comportamento são os mesmos — muda só o formato da requisição/resposta.

+
+
+ + + + + + + + + + + + +
Aspectogenerate_content (doc oficial)interactions.create (este guia)
Modelo dos exemplosgemini-3-flash-previewgemini-3.5-flash (validado por teste)
Imagem na entradacontents=[Part.from_bytes(data, mime_type), "prompt"]input=[{"type":"image","data":b64,"mime_type":…}, …]
Resolução da imagemmedia_resolution = enum MEDIA_RESOLUTION_* (per-part é v1alpha/experimental)campo resolution no bloco de imagem (standard/high/ultra_high)
Ativar Code Executionconfig.tools=[Tool(code_execution=ToolCodeExecution)]tools=[{"type":"code_execution"}]
Thinkinghabilitar Thinking no configgeneration_config={"thinking_level":"minimal|low|medium|high"}
Saída estruturada (JSON)response_mime_type="application/json" + response_schemaresponse_format={"type":"text","mime_type":"application/json","schema":…}
Multi-turn / estadoclient.chats (history) ou reenviar id+thought_signature manualmente (REST)previous_interaction_id (o SDK reidrata a signature)
Imagem anotada (saída)part.as_image().image_bytes nos partsresp.output_image.data
Trace do códigopart.executable_code / part.code_execution_resultresp.steps (ModelOutputStep / code_execution_call)
+ +

Esta seção descreve o contrato de agentic vision usado para delegar uma investigação visual a gemini-3.5-flash via client.interactions.create. A ideia central: Code Execution é o instrumento de medição do modelo, e a Interactions API dá memória multi-turn (raciocínio + traços de tool + thought_signature) através de previous_interaction_id.

+ +

O loop, em uma figura

+
Orquestrador                                   gemini-3.5-flash
+   │  turn 1: payload + imagem + prompt            │
+   ├───────────────────────────────────────────────►│ THINK  (planeja a hipótese e a região)
+   │                                                 │ ACT    ──► code_execution (crop/zoom/threshold/medir)
+   │                                                 │ OBSERVE ◄── lê o crop transformado; itera se preciso
+   │                                                 │ FINAL: plt.show(imagem anotada)
+   │  {analysis, findings, measurements, boxes[]}    │
+   │  + annotated_png (emitido pelo modelo)          │
+   │  + interaction_id (para o próximo turno)        │
+   │◄───────────────────────────────────────────────┤
+   │  turn 2 (opcional): MESMOS bytes (audita SHA256!)│
+   │            + previous_interaction_id + nova pergunta
+   ├───────────────────────────────────────────────►│ retoma com thinking_signature + contexto de code_execution
+ +

Invariantes obrigatórias (todo turno, sem exceção)

+
    +
  1. A imagem vai em TODO turno. previous_interaction_id carrega raciocínio + assinatura + traços de tool, não os bytes da imagem. Reenvie os bytes e audite por sha256(png)[:16].
  2. +
  3. Assinatura de pensamento preservada verbatim. Ela é opaca e vive dentro dos step/content blocks da interaction — não há acessor top-level resp.thinking_signature no SDK google-genai atual. O SDK reidrata sozinho quando você define previous_interaction_id = resp.id; nunca reconstrua nem injete a assinatura à mão.
  4. +
  5. Schema fixo = AGENTIC_SCHEMA (abaixo), com additionalProperties: false e os quatro campos sempre exigidos.
  6. +
  7. Tool list = exatamente [{"type":"code_execution"}] no turno de vision. Quer multi-tool? Embrulhe o flash dentro de um agente maior que roda seu próprio loop e delega só a visão.
  8. +
  9. Trust framing no system prompt (o modelo é a fonte de verdade; o código é o instrumento). Autonomy framing ("decida se usa a tool") degradou calibração ~8,9 pp nos experimentos.
  10. +
+ +

System prompt (trust framing — núcleo)

+
Você é o especialista de AGENTIC-VISION. Você É a fonte de verdade sobre esta
+imagem — o orquestrador confia na sua leitura. O code execution é o SEU
+INSTRUMENTO para fundamentar essa leitura; use-o liberalmente em vez de chutar
+a partir de um thumbnail.
+
+Opere em um loop explícito THINK → ACT → OBSERVE:
+  • THINK   — em 1–3 frases, planeje qual região e qual medida resolvem a questão.
+  • ACT     — carregue a imagem e rode código: crop/zoom; realce de contraste
+              (CLAHE/equalização); threshold (HSV costuma ser mais estável que RGB);
+              edge detection (Canny/Sobel) ou blob analysis. DESCARREGUE qualquer
+              contagem/área/distância para o Python. NÃO meça "no olho".
+  • OBSERVE — leia o crop transformado; se não for decisivo, itere outro passo.
+
+PASSO FINAL — OBRIGATÓRIO: como última chamada de código, DESENHE sua(s) caixa(s)
+e rótulo(s) sobre a imagem (cv2.rectangle / patches.Rectangle) e exiba com
+plt.imshow(...); plt.show() para capturar a imagem anotada — é a sua trilha de auditoria.
+
+DISCIPLINA DE SAÍDA: preencha apenas analysis, findings_summary, measurements e
+boxes (coordenadas em pixels da imagem ORIGINAL). Não emita diagnóstico final fora
+do schema — o diagnóstico é responsabilidade do agente principal.
+ +

Chamada (Interactions API)

+
import hashlib, base64, json
+from google import genai
+client = genai.Client()
+
+def sha16(b): return hashlib.sha256(b).hexdigest()[:16]
+
+def consult_flash(*, png_bytes, expected_hash, prompt, prior_id=None,
+                  thinking_level="medium"):
+    assert sha16(png_bytes) == expected_hash, "image drift antes do envio"
+    payload = dict(
+        model="gemini-3.5-flash",
+        generation_config={"thinking_level": thinking_level},  # minimal|low|medium|high
+        input=[
+            {"type": "text",  "text": "Fonte da modalidade / caption"},
+            {"type": "image", "data": base64.b64encode(png_bytes).decode(),
+                              "mime_type": "image/png",
+                              "resolution": "ultra_high"},     # crítico p/ lesão pequena
+            {"type": "text",  "text": prompt},
+        ],
+        tools=[{"type": "code_execution"}],                    # SÓ isto no turno de vision
+        response_format={"type": "text", "mime_type": "application/json",
+                         "schema": AGENTIC_SCHEMA},
+    )
+    if prior_id:
+        payload["previous_interaction_id"] = prior_id          # única diferença no multi-turn
+    resp = client.interactions.create(**payload)
+    parsed  = json.loads(resp.output_text) if resp.output_text else {}
+    steps   = [type(s).__name__ for s in (resp.steps or [])]
+    code_n  = sum(1 for s in steps if "CodeExecutionCall" in s)
+    out_img = getattr(getattr(resp, "output_image", None), "data", None)
+    return {
+        "interaction_id": resp.id,
+        "analysis": parsed.get("analysis", ""),
+        "findings_summary": parsed.get("findings_summary", ""),
+        "measurements": parsed.get("measurements", "none"),
+        "boxes": parsed.get("boxes", []),
+        "n_code_calls": code_n,
+        "used_agentic": code_n > 0,        # 0 chamadas = modelo "fugiu" da tool
+        "annotated_b64": out_img,          # PNG anotado emitido pelo próprio modelo
+        "image_hash": expected_hash,
+    }
+ +

Schema autoritativo

+
AGENTIC_SCHEMA = {
+    "type": "object",
+    "properties": {
+        "analysis":         {"type": "string"},
+        "findings_summary": {"type": "string"},
+        "measurements":     {"type": "string"},   # números concretos ou "none"
+        "boxes": {
+            "type": "array",
+            "items": {
+                "type": "object",
+                "properties": {
+                    "x0": {"type": "integer"}, "y0": {"type": "integer"},
+                    "x1": {"type": "integer"}, "y1": {"type": "integer"},
+                    "label": {"type": "string"},
+                },
+                "required": ["x0", "y0", "x1", "y1", "label"],
+                "additionalProperties": False,
+            },
+        },
+    },
+    "required": ["analysis", "findings_summary", "measurements", "boxes"],
+    "additionalProperties": False,
+}
+

boxes em pixels da imagem original (nunca normalizados). measurements é string (conjunto aberto: área px², razão de assimetria, diâmetro mm…). additionalProperties: false em todo lugar — sem isso o flash inventa campos que o orquestrador descarta em silêncio.

+ +

Multi-turn: o que você NÃO faz numa continuação

+
    +
  1. Não remova a imagem do novo turno — mesmo com previous_interaction_id, os bytes precisam estar no payload.
  2. +
  3. Não reconstrua o system prompt inteiro num mega-prompt; envie só a instrução incremental — o contexto anterior vem pelo id.
  4. +
  5. Não levante/re-injete a "thinking signature" manualmente; setar previous_interaction_id = resp.id é o mecanismo suportado.
  6. +
+

Encadeie (previous_interaction_id) para aprofundar na MESMA imagem; comece do zero para outra imagem ou quando a pergunta muda de eixo (continuação serve para deepening, não para redirecionar). Se sha256 diverge entre turnos, aborte — é bug de drift de ground-truth.

+ +

Tuning

+
+ + + + + + +
thinking_levelQuando
minimal / lowTriagem em volume, passes de sanidade, consultas de rotina.
mediumDefault para vision diagnóstico. medium → high não deu ganho de acurácia detectável no benchmark, mas ~80% mais caro.
highCasos difíceis (lesão pequena, camadas OCT ambíguas); raramente necessário.
+

resolution: "ultra_high" é não-negociável para imagens diagnósticas ≤ 512 px (dermoscopia etc.); o default subamostra e perde o gradiente que dirige a decisão. Distribuição empírica: mediana de 3 passos de código por caso; se o flash emite < 2 chamadas de rotina, suba o thinking_level ou torne o THINK obrigatório no prompt.

+

Campo na Interactions API: a resolução vai no próprio bloco de imagem do input, no campo resolution (string). Valores validados em produção:

+
+ + + + + + +
resolutionQuando usar
standardImagens macroscópicas grandes (ex.: raio-X de tórax).
highOCT, ultrassom.
ultra_highDermoscopia e qualquer imagem ≤ 512 px (preserva o gradiente de pigmentação que o default subamostra).
+

Equivalência no generate_content: o parâmetro é media_resolution com o enum MEDIA_RESOLUTION_{LOW,MEDIUM,HIGH,ULTRA_HIGH}. O ULTRA_HIGH é per-part, experimental (v1alpha), ~2240 tokens/imagem; a doc oficial recomenda HIGH para a maioria dos casos e ULTRA_HIGH só quando o teste mostra ganho claro sobre HIGH (ex.: computer use ou detalhe diagnóstico minúsculo). [doc]

+ +

Anti-padrões (não faça)

+
    +
  • Adicionar google_search ao turno de vision. Misturar busca introduz confound (regressão de ~10 pp medida em gemini-3.5-flash em derma). Mantenha o turno de visão só visão; busca é outra tool, orquestrada à parte.
  • +
  • Re-renderizar as boxes quando output_image existe — o PNG anotado pelo próprio modelo é melhor que o render por coordenadas (ele "viu" as medidas do código).
  • +
  • Pedir veredito diagnóstico final ao flash. Ele é instrumento de visão; o diagnóstico é do agente principal. Misturar os papéis infla a confiança dele nas próprias caixas.
  • +
  • Usar gemini-3.1-flash-image para isto — essa variante é de geração de imagem, não de raciocínio vision-grounded. Use o gemini-3.5-flash normal.
  • +
  • Reaproveitar previous_interaction_id entre imagens diferentes "para economizar tokens" — o flash conflaciona os casos. Imagem nova = interaction nova.
  • +
+ +
+

Leitura honesta do ganho. No benchmark de referência (n=198, derma 128px), o ganho marginal de agentic vision em cima do trust framing é quase-zero: a melhora observada vem do framing, não da tool. Trate agentic vision como instrumento de explicabilidade/auditoria (caixas + medidas que mostram por que o modelo decidiu), não como alavanca de acurácia por si só. Detecte "tool-dodge": n_code_calls == 0 + boxes == [] + measurements == "none" ⇒ rebaixe a contribuição do flash, não trate como negativo confiante.

+
+ + +
+ +
+

18. Agentes: Deep Research & Antigravity

+ +

A Interactions API expõe agentes gerenciados via parâmetro agent (no lugar de model): os agentes Deep Research (§18.1–18.8), o agente de propósito geral Antigravity (§18.9) e agentes custom construídos sobre ele — todos executando server-side. Deep Research é um agente assíncrono que pesquisa, planeja, lê, sintetiza e produz relatórios longos. Disponível apenas via Interactions API.

+ +

18.1 Agentes Deep Research

+
+ + + + + + +
IdentificadorDescrição
deep-research-preview-04-2026Deep Research — planeja e executa pesquisa multi-etapa com relatórios citados
deep-research-max-preview-04-2026Deep Research Max — máxima abrangência de coleta e síntese entre centenas de fontes
+
+ +

18.2 Como invocar

+
import time
+interaction = client.interactions.create(
+    input="Research the history of Google TPUs.",
+    agent="deep-research-preview-04-2026",
+    background=True,
+)
+
+while True:
+    interaction = client.interactions.get(interaction.id)
+    if interaction.status == "completed":
+        print(interaction.output_text); break
+    elif interaction.status == "failed":
+        print("Failed:", interaction.error); break
+    time.sleep(10)
+ +

18.3 agent_config

+
+ + + + + + + + +
CampoTipoPadrãoDescrição
typestringobrigatórioSempre "deep-research"
thinking_summariesstring"none""auto" habilita raciocínio intermediário no stream
visualizationstring"auto""auto" gera tabelas/gráficos; "off" desativa
collaborative_planningbooleanfalseAtiva revisão do plano antes de executar
+
+ +

18.4 Planejamento colaborativo (3 etapas)

+
    +
  1. Solicitar plano (collaborative_planning: true).
  2. +
  3. Refinar plano (mesmo collaborative_planning: true, com previous_interaction_id).
  4. +
  5. Aprovar e executar (collaborative_planning: false).
  6. +
+ +

18.5 Ferramentas suportadas

+

Ativadas por padrão: google_search, url_context, code_execution. Opcionalmente: mcp_server, file_search.

+ +

18.6 Reconexão de stream

+
# Salve last_event_id e reconecte com:
+stream = client.interactions.get(
+    id=interaction_id, stream=True, last_event_id=last_event_id
+)
+ +

18.7 Custos & limites

+
Estimativas de preview (sujeitas a mudança): custos e nº de consultas abaixo são aproximados (~) e baseados em preview rates — a doc oficial avisa que podem mudar. Tempo máximo de pesquisa: 60 min (maioria das tarefas em ~20 min).
+
+ + + + + + +
VersãoConsultasTokens entradaTokens saídaCusto estimado
deep-research-preview-04-2026~80~250k (50–70% cache)~60kUS$ 1,00–3,00 / tarefa
deep-research-max-preview-04-2026~160~900k (50–70% cache)~80kUS$ 3,00–7,00 / tarefa
+
+
    +
  • Tempo máximo: 60 minutos por tarefa (maioria conclui em ~20 min).
  • +
  • background=true exige store=true.
  • +
  • Function calling personalizado não é suportado (use MCP).
  • +
  • Saída estruturada não é suportada atualmente.
  • +
+ +

18.8 Follow-up sobre relatório

+
followup = client.interactions.create(
+    input="Can you elaborate on the second point?",
+    model="gemini-3.1-pro-preview",
+    previous_interaction_id="COMPLETED_INTERACTION_ID"
+)
+ +

18.9 Antigravity agent (preview) — agente gerenciado de propósito geral

+

O Antigravity (antigravity-preview-05-2026) é um agente gerenciado de propósito geral movido por gemini-3.5-flash: uma única chamada dispara um loop autônomo de raciocínio, execução de código, gestão de arquivos e navegação web dentro de um sandbox Linux hospedado (ver §18.10). Disponível via Interactions API e Google AI Studio.

+
interaction = client.interactions.create(
+    agent="antigravity-preview-05-2026",
+    input="Analyze this CSV and produce a summary report.",
+    environment="remote",   # sandbox novo com defaults
+)
+print(interaction.output_text)
+print(interaction.environment_id)  # reutilize para continuar com os mesmos arquivos/estado
+

O parâmetro environment aceita três formas:

+
+ + + + + + + +
FormaComportamento
"remote"Cria um sandbox novo com configurações padrão.
"env_abc123"Reutiliza um environment existente pelo ID — arquivos e estado preservados.
{...} (EnvironmentConfig)Configuração completa: fontes Git/GCS/inline e regras de rede (allowlist).
+
+

Capacidades: execução de código (Bash, Python, Node.js — instala pacotes, roda testes), gestão de arquivos persistente entre interações, acesso web (Google Search + URL Context) e compactação automática de contexto (disparada em ~135k tokens). Ferramentas tipadas suportadas: code_execution, google_search e url_context (todas ativas por padrão — restrinja passando só o necessário em tools); o filesystem é habilitado automaticamente pelo environment.

+

Customização: passe um AGENTS.md com instruções, monte skills em .agents/skills/ no sandbox ou configure inline na interação; o resultado pode ser salvo como agente gerenciado (custom agent).

+
Limitações (preview): entrada apenas text e image (base64 inline) — sem áudio, vídeo ou documentos; os parâmetros temperature, top_p, top_k, stop_sequences e max_output_tokens retornam 400; sem saída estruturada; sem file_search, computer_use, google_maps, function calling custom ou MCP; background=true não é suportado e store=true é obrigatório. Schemas podem mudar.
+
Custos (estimativas de preview, pay-as-you-go): tarefas típicas usam 100k–500k tokens de entrada (50–70% em cache) e 10k–50k de saída — US$ 0,25–1,30 por tarefa; processamento de dados pode chegar a 300k–3M de entrada (US$ 0,70–3,25) e workflows complexos a 3–5M tokens (~US$ 5/interação). A computação do sandbox não é cobrada durante o preview.
+ +

18.10 Environments (sandboxes de agente)

+

Cada agente gerenciado roda em uma VM Linux isolada (Ubuntu, Python 3.12, Node.js 22) onde raciocina, executa código, gerencia arquivos e navega na web. Rede de saída liberada por padrão (configurável via allowlist). A VM hiberna por inatividade e restaura o estado na próxima requisição (cold start); é deletada permanentemente após 7 dias de inatividade. Limite: 1.000 agentes gerenciados. Agentes custom são construídos sobre a base do Antigravity — ver custom-agents e o quickstart de managed agents nas fontes abaixo.

+ + +
+ +
+

19. Background & webhooks

+ +

Para operações longas (Deep Research, Deep Think), defina background=true. A interação fica em estado in_progress até concluir, e você pode:

+
    +
  • Fazer polling via GET /interactions/{id}.
  • +
  • Receber notificação via webhook_config.
  • +
+ +

19.1 Polling

+
while True:
+    res = client.interactions.get(interaction_id)
+    if res.status == "completed": break
+    time.sleep(10)
+ +

19.2 Webhook dinâmico (por requisição)

+
interaction = client.interactions.create(
+    agent="deep-research-preview-04-2026",
+    input="Research the latest in quantum computing.",
+    background=True,
+    webhook_config={
+        "uris": ["https://my-api.com/gemini-webhook"],
+        "user_metadata": {"job_id": "abc-123"}
+    }
+)
+ +

19.3 Webhook estático (criar no projeto)

+
webhook = client.webhooks.create(
+    name="MyWebhook",
+    subscribed_events=["interaction.completed", "interaction.failed",
+                       "interaction.requires_action", "interaction.cancelled"],
+    uri="https://my-api.com/gemini-callback",
+)
+# webhook.new_signing_secret é retornado APENAS UMA VEZ
+ +

19.4 Eventos suportados (Interactions)

+
+ + + + + + + + +
typeDispara quando
interaction.completedLRO concluído
interaction.failedLRO falhou (error_code, error_message em data)
interaction.requires_actionFunção do cliente pendente
interaction.cancelledCancelado pelo usuário
+
+ +

19.5 Verificação de assinatura (webhooks dinâmicos)

+
    +
  • Header: Webhook-Signature (JWT, RS256).
  • +
  • Endpoint JWKS público: https://generativelanguage.googleapis.com/.well-known/jwks.json.
  • +
  • Use o kid do header JWT para encontrar a chave pública.
  • +
+ +

19.6 Boas práticas

+
    +
  • Responda 2xx em segundos; processe assincronamente.
  • +
  • Retentativas automáticas por 24 horas com backoff exponencial.
  • +
  • Header webhook-timestamp: rejeite se > 5 min de skew (anti-replay).
  • +
  • Header webhook-id para deduplicação (entrega at-least-once).
  • +
  • Rotate signing secret com revocation_behavior: "REVOKE_PREVIOUS_SECRETS_AFTER_H24".
  • +
+ + +
+ +
+

20. Flex & Priority Inference

+ +

20.1 Comparativo de tiers

+
+ + + + + + + + +
RecursoPriorityStandardFlexBatch
Preço+75–100% vs StandardPreço cheio−50%−50%
LatênciaSegundosSegundos–minutos1–15 min (alvo)Até 24h
ConfiabilidadeAlta (não descartável)Alta/Média-altaMelhor esforço (descartável)Alta (throughput)
InterfaceSíncronaSíncronaSíncronaAssíncrona
+
+ +

20.2 Habilitar Flex

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Analyze this dataset for trends...",
+    service_tier='flex'
+)
+ +

20.3 Habilitar Priority

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Triage this critical support ticket immediately.",
+    service_tier='priority'
+)
+ +

20.4 Retry com backoff (Flex)

+
import time
+def call_with_retry(max_retries=3, base_delay=5):
+    for attempt in range(max_retries):
+        try:
+            return client.interactions.create(
+                model="gemini-3.5-flash", input="...", service_tier="flex")
+        except Exception as e:
+            if attempt < max_retries - 1:
+                time.sleep(base_delay * (2 ** attempt))
+            else:
+                return client.interactions.create(
+                    model="gemini-3.5-flash", input="...")  # fallback
+ +

20.5 Códigos de erro Flex

+
    +
  • 503 Service Unavailable — capacidade no limite.
  • +
  • 429 Too Many Requests — limite excedido.
  • +
+ +

20.6 Soft downgrade (Priority)

+

Em picos, Priority faz soft downgrade automático para Standard (cobrado à taxa Standard). Monitore via header x-gemini-service-tier.

+ + +
+ +
+

21. Armazenamento & retenção de dados

+ +

21.1 Padrão server-side

+
    +
  • Padrão: store=true. Servidor armazena steps por: +
      +
    • Tier pago: 55 dias.
    • +
    • Tier free: 1 dia.
    • +
    +
  • +
  • Use previous_interaction_id para continuar histórico (e habilita cache implícito).
  • +
+ +

21.2 Modo sem estado (store=false)

+
    +
  • Servidor não armazena nada.
  • +
  • Você precisa enviar histórico completo (com signature de thought) em cada turno.
  • +
  • Incompatível com background=true.
  • +
  • Impede uso da interação como previous_interaction_id.
  • +
+ +

21.3 Excluir / cancelar manualmente

+
curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/interactions/INT_ID" \
+  -H "x-goog-api-key: $GEMINI_API_KEY"
+
+curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions/INT_ID/cancel" \
+  -H "x-goog-api-key: $GEMINI_API_KEY"
+
+ +
+

22. Limitações

+ +

Recursos ainda ausentes ou em desenvolvimento na Interactions API:

+
    +
  • Batch API assíncrona — siga usando generateContent com :batchGenerateContent.
  • +
  • Cache explícito — disponível apenas via generateContent.
  • +
  • video_metadata (cortes, FPS customizado) — disponível apenas em generateContent.
  • +
  • Chamada automática de função em Python — disponível apenas em generateContent.
  • +
  • MCP remoto com Gemini 3.x — ainda não suportado (em breve, segundo a doc oficial). Quando suportado, apenas servidores Streamable HTTP (não SSE).
  • +
  • Deep Research: function calling personalizado não suportado (use MCP); saída estruturada não suportada.
  • +
  • File Search: sem áudio/vídeo; não disponível na Live API.
  • +
  • Computer Use: suportado em gemini-3-flash-preview (nativo) e no modelo dedicado gemini-2.5-computer-use-preview-10-2025; gemini-3.5-flash não é compatível. Recurso em preview.
  • +
+ +

22.1 Configurações de segurança

+

O filtro de segurança clássico — safety_settings com HarmCategory (ex.: HARM_CATEGORY_HATE_SPEECH) e HarmBlockThreshold (ex.: BLOCK_LOW_AND_ABOVE) — é documentado para o generateContent (via types.GenerateContentConfig) e não consta no schema de request da Interactions API nesta revisão. Para ações agênticas, a Interactions API expõe um mecanismo distinto: o campo safety_decision (ex.: require_confirmation) em ferramentas como Computer Use — implemente HITL conforme a §17.5.

+ +
+ +
+

23. Práticas recomendadas

+ +
    +
  • Use previous_interaction_id em vez de reenviar histórico — ativa cache implícito e reduz custo.
  • +
  • Para Deep Research, combine com modelo padrão depois: faça polling até completed e use previous_interaction_id num Gemini Flash para resumir.
  • +
  • Coloque conteúdos grandes (PDF, documento) no início do prompt para maximizar cache hits.
  • +
  • Para multimodal de uma imagem ou PDF curto, posicione o prompt de texto depois da mídia.
  • +
  • Em streaming de function calling, acumule arguments_delta e só faça JSON.parse após step.stop.
  • +
  • Em modo store=false, NUNCA modifique blocos thought ou suas signature — reenvie exatamente como recebido.
  • +
  • Implemente retry com backoff em service_tier: flex; cache de Priority via header x-gemini-service-tier.
  • +
  • Em webhooks, valide webhook-timestamp (≤5 min) e use webhook-id para deduplicação.
  • +
  • Trate eventos SSE desconhecidos com log + skip, não como erro.
  • +
+
+ +
+

Parte B — Referência REST completa

+

Schema canônico da Interactions API verificado contra ai.google.dev/api/interactions-api. Todos os nomes de campo, enums e exemplos são preservados literalmente (a API usa snake_case no wire; os SDKs expõem camelCase em JS).

+
+ +
+

B1. Endpoints

+

Base: https://generativelanguage.googleapis.com. Versão atual: v1beta (não existe /v1beta2 — todas as páginas oficiais usam /v1beta).

+
+ + + + + + + + +
Método & caminhoOperaçãoDescrição
POST /v1beta/interactionscreateCria uma nova Interaction (modelo ou agente). Aceita stream, store, background.
GET /v1beta/interactions/{id}getRecupera o estado completo de uma interação armazenada. Aceita stream, last_event_id, include_input.
DELETE /v1beta/interactions/{id}deleteExclui uma interação armazenada por ID.
POST /v1beta/interactions/{id}/cancelcancelCancela uma interação background ainda em execução.
+
+ +
+ +
+

B2. Autenticação & Headers

+
+ + + + + + + +
HeaderObrigatórioValor
x-goog-api-keySimSua chave de API ($GEMINI_API_KEY). Alternativa: query ?key=.
Content-TypeSim (POST)application/json
Api-RevisionNão (ignorado)Histórico da transição de Maio/2026: 2026-05-20 controlou o opt-in (até 26/05/2026) e 2026-05-07 o rollback (até 08/06/2026). Desde 08/06/2026 o header é ignorado e pode ser omitido.
+
+
+ SSE: para respostas em streaming, defina "stream": true no corpo (ou query ?stream=true no GET). O servidor responde text/event-stream com eventos event_type (ver B18). +
+ +
+ +
+

B3. POST /v1beta/interactions — criar

+

Cria uma nova interação. Exatamente um de model ou agent é obrigatório.

+ +

Corpo da requisição

+
+ + + + + + + + + + + + + + + + + + + + + +
CampoTipoDescrição
modelModelOptionNome do modelo. Obrigatório se agent ausente. Ver B19.
agentAgentOptionNome do agente. Obrigatório se model ausente. Ver B20.
inputContent | array(Content) | array(Step) | string(Obrigatório) Entradas da interação. Aceita string simples, blocos de conteúdo ou steps tipados.
system_instructionstringInstrução de sistema. Interaction-scoped (reenvie a cada turno).
toolsarray(Tool)Declarações de ferramentas. Interaction-scoped. Ver B17.
response_formatResponseFormat | ResponseFormatListFormato de saída (text/JSON, image, audio). Substitui response_mime_type + image_config.
response_mime_typestringlegado MIME da resposta. No novo schema use mime_type dentro de response_format.
streambooleanInput only. Streaming SSE.
storebooleanInput only. Armazenar para recuperação posterior. Default true.
backgroundbooleanInput only. Executar em background (tarefas longas). Incompatível com store=false.
generation_configGenerationConfigConfiguração do modelo. Alternativa a agent_config. Só com model. Ver B10.
agent_configDeepResearchAgentConfig | DynamicAgentConfigConfiguração do agente. Só com agent. Ver B11.
environmentEnvironmentConfig | stringAmbiente remoto (sources GCS/repo/inline, allowlist de rede) ou ID de ambiente existente.
previous_interaction_idstringID da interação anterior — ativa estado server-side e cache implícito.
response_modalitiesarray(ResponseModality)Modalidades desejadas: text, image, audio, video, document.
service_tierServiceTierflex | standard | priority.
webhook_configWebhookConfigURIs de webhook + user_metadata para notificações. Ver B12.
+
+ +

Exemplo mínimo

+
+
+ + + +
+
+
from google import genai
+
+client = genai.Client()
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Hello, how are you?",
+)
+print(interaction.output_text)
+
+
+
import {GoogleGenAI} from '@google/genai';
+
+const ai = new GoogleGenAI({});
+const interaction = await ai.interactions.create({
+    model: 'gemini-3.5-flash',
+    input: 'Hello, how are you?',
+});
+console.log(interaction.output_text);
+
+
+
curl -X POST https://generativelanguage.googleapis.com/v1beta/interactions \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{
+    "model": "gemini-3.5-flash",
+    "input": "Hello, how are you?"
+  }'
+
+
+ +
+ Resposta JSON (200) — status: completed +
+
{
+  "created": "2025-11-26T12:25:15Z",
+  "id": "v1_ChdPU0F4YWFtNkFwS2kxZThQZ05lbXdROBIX...",
+  "model": "gemini-3.5-flash",
+  "object": "interaction",
+  "steps": [
+    {
+      "type": "model_output",
+      "content": [
+        { "type": "text", "text": "Hello! I'm functioning perfectly..." }
+      ]
+    }
+  ],
+  "status": "completed",
+  "updated": "2025-11-26T12:25:15Z",
+  "usage": {
+    "input_tokens_by_modality": [ { "modality": "text", "tokens": 7 } ],
+    "total_cached_tokens": 0,
+    "total_input_tokens": 7,
+    "total_output_tokens": 20,
+    "total_thought_tokens": 22,
+    "total_tokens": 49,
+    "total_tool_use_tokens": 0
+  }
+}
+
+
+
+ Function calling: quando o modelo decide chamar uma ferramenta, o status retorna requires_action e o último step é function_call (com id, name, arguments). Responda com um step function_result reaproveitando call_id = id. +
+ +
+ +
+

B4. GET /v1beta/interactions/{id} — recuperar

+

Recupera os detalhes completos de uma interação armazenada (store=true). O recurso retornado pelo GET inclui também o step user_input (a resposta do create retorna apenas steps gerados pelo modelo).

+
+ + + + + + + + + +
ParâmetroTipoDescrição
idstring(Obrigatório) Identificador da interação.
streambooleanSe true, transmite incrementalmente (SSE). Default false.
last_event_idstringRetoma o stream a partir do próximo chunk após o evento indicado. Só com stream=true.
include_inputbooleanInclui o input na resposta. Default false.
api_versionstringVersão da API a usar.
+
+
+
+ + + +
+
+
interaction = client.interactions.get(id=created.id)
+print(interaction.status)
+
+
+
const interaction = await ai.interactions.get(created.id);
+console.log(interaction.status);
+
+
+
curl -X GET "https://generativelanguage.googleapis.com/v1beta/interactions/$INTERACTION_ID" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Api-Revision: 2026-05-20"
+
+
+
Polling de background: para background=true, faça get repetido até status sair de in_progress para completed/failed/cancelled.
+ +
+ +
+

B5. DELETE /v1beta/interactions/{id} — excluir

+

Exclui a interação por ID. Requer apenas id (e api_version opcional). Resposta vazia em caso de sucesso.

+
+
+ + + +
+
+
client.interactions.delete(id=created.id)
+print("Interaction deleted successfully.")
+
+
+
await ai.interactions.delete(created.id);
+console.log('Interaction deleted successfully.');
+
+
+
curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/interactions/$INTERACTION_ID" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Api-Revision: 2026-05-20"
+
+
+
+ +
+

B6. POST /v1beta/interactions/{id}/cancel — cancelar

+

Cancela uma interação. Aplica-se apenas a interações background ainda em execução. Retorna o recurso Interaction com status: cancelled.

+
+
+ + +
+
+
created = client.interactions.create(
+    model="gemini-3-flash-preview",
+    input="Write a long essay about the history of computing.",
+    tools=[{"type": "computer_use"}],
+    background=True,
+)
+interaction = client.interactions.cancel(id=created.id)
+print(interaction.status)  # cancelled
+
+
+
const created = await ai.interactions.create({
+    model: 'gemini-3-flash-preview',
+    input: 'Write a long essay about the history of computing.',
+    tools: [{ type: 'computer_use' }],
+    background: true,
+});
+const interaction = await ai.interactions.cancel(created.id);
+console.log(interaction.status); // cancelled
+
+
+
+ +
+

B7. Recurso Interaction

+

Objeto central. Campos Output only são preenchidos pelo servidor.

+
+ + + + + + + + + + + + + + + + +
PropriedadeTipoNotas
idstring(Obrigatório, output) Identificador único.
objectstringSempre "interaction".
model / agentenumModelo ou agente usado.
statusenum(Obrigatório, output) Ver B8.
stepsarray(Step)(Obrigatório, output) Timeline da interação. Ver B15.
created / updatedstring(Obrigatório, output) ISO 8601 (YYYY-MM-DDThh:mm:ssZ).
inputpoliformeEntrada (presente no GET com include_input).
previous_interaction_idstringEncadeamento server-side.
rolestringOutput only.
environment_idstringOutput only. Só se environment foi configurado.
usageUsageOutput only. Ver B9.
response_format, response_modalities, service_tier, system_instruction, tools, generation_config, agent_config, webhook_config, environment—Espelham os campos do request.
+
+
+ +
+

B8. InteractionStatus (enum)

+
+ + + + + + + + + + + +
ValorSignificado
in_progressEm execução (streaming/background).
requires_actionAguardando ação do cliente — tipicamente um function_result para um function_call.
completedConcluída com sucesso.
failedErro durante a geração.
cancelledCancelada via endpoint de cancel.
incompleteInterrompida antes de concluir (ex.: limite de tokens).
budget_exceededOrçamento (ex.: Deep Research) excedido.
+
+
+ +
+

B9. Usage & modalidades

+

Estatísticas de tokens. Os totais são acompanhados por breakdowns por modalidade (ModalityTokens: { modality, tokens }).

+
+ + + + + + + + + + + + + + + +
CampoDescrição
total_input_tokensTokens do prompt (contexto).
total_output_tokensTokens gerados em todas as respostas.
total_thought_tokensTokens de raciocínio (modelos thinking).
total_cached_tokensTokens servidos do cache implícito.
total_tool_use_tokensTokens de prompts de uso de ferramentas.
total_tokensTotal (prompt + respostas + internos).
input_tokens_by_modalityBreakdown de entrada por modalidade.
output_tokens_by_modalityBreakdown de saída por modalidade.
cached_tokens_by_modalityBreakdown de cache por modalidade.
tool_use_tokens_by_modalityBreakdown de uso de ferramentas por modalidade.
grounding_tool_countarray de { type, count } — type ∈ google_search | google_maps | retrieval.
+
+
+ +
+

B10. GenerationConfig

+

Configuração do modelo (alternativa a agent_config; só com model).

+
+ + + + + + + + + + + + + + +
CampoTipoNotas
thinking_levelenumminimal | low | medium | high. Substitui thinking_budget.
thinking_summariesenumauto | none.
max_output_tokensintegerMáximo de tokens na resposta.
temperaturenumbernão recomendado em Gemini 3.x
top_pnumbernão recomendado em Gemini 3.x
seedintegerReprodutibilidade na decodificação.
stop_sequencesarray(string)Sequências que interrompem a saída.
tool_choiceToolChoiceConfig | ToolChoiceTypeauto | any | none | validated.
image_configImageConfigaspect_ratio (1:1…21:9, 1:8, 8:1, 1:4, 4:1) e image_size (0.5K, 1K, 2K, 4K). legado — no novo schema, prefira response_format tipo image.
speech_configarray(SpeechConfig){ language, speaker, voice } para TTS multi-speaker.
+
+
+ +
+

B11. AgentConfig & EnvironmentConfig

+

Discriminado por type. Só com agent.

+

DeepResearchAgentConfig — type: "deep-research"

+
+ + + + + + + + +
CampoTipoNotas
typeconst(Obrigatório) "deep-research".
collaborative_planningbooleanHuman-in-the-loop: o agente devolve um plano e só prossegue após confirmação no próximo turno.
thinking_summariesenumauto | none.
visualizationenumoff | auto — incluir visualizações na resposta.
+
+

DynamicAgentConfig — type: "dynamic"

+

Configuração para agentes dinâmicos. Campo obrigatório: type: "dynamic".

+ +

EnvironmentConfig — ambiente remoto (Computer Use / Antigravity)

+

Passado no campo top-level environment (objeto) ou como string com o ID de um ambiente já criado. Discriminador type: "remote".

+
+ + + + + + + +
CampoTipoNotas
typeconst(Obrigatório) "remote".
networkEnvironmentNetworkEgressAllowlist | enumEgress allowlist de rede: allowlist[].domain + allowlist[].transform (transformação/proxy de credenciais).
sourcesarray(Source)Arquivos/dados montados no ambiente (campos abaixo).
+
+

Cada Source:

+
+ + + + + + + + + +
CampoTipoNotas
typeenumrepository | gcs | inline (a doc oficial de agents-environments lista esses três tipos).
sourcestringOrigem (caminho GCS, caminho do GitHub etc.).
targetstringOnde o conteúdo deve aparecer no ambiente.
contentstringConteúdo inline (quando type: "inline").
encodingstringEncoding opcional do inline (ex.: base64).
+
+
+ +
+

B12. WebhookConfig

+
+ + + + + + +
CampoTipoNotas
urisarray(string)Se definido, usa estes URIs em vez dos webhooks registrados.
user_metadataobjectMetadados retornados em cada emissão de evento ao webhook.
+
+
Segurança de webhook: valide o header webhook-timestamp (rejeite > 5 min) e use webhook-id para deduplicação. Verifique a assinatura antes de processar o payload.
+
+ +
+

B13. ResponseFormat · ResponseModality / ServiceTier / MediaResolution

+

response_format aceita um objeto ResponseFormat ou um array (ResponseFormatList, ex.: [{"type":"text"}, {"type":"image"}] para saída intercalada). Discriminado por type. Substitui o legado response_mime_type + image_config.

+
+ + + + + + + +
Variante (type)Campos
text
(TextResponseFormat)
mime_type (application/json | text/plain); schema (JSON Schema — só com application/json).
image
(ImageResponseFormat)
aspect_ratio (1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:8, 8:1, 1:4, 4:1); image_size (512 | 1K | 2K | 4K); delivery (inline | uri); mime_type (image/jpeg).
audio
(AudioResponseFormat)
mime_type (audio/mp3 | audio/ogg_opus | audio/l16 | audio/wav | audio/alaw | audio/mulaw); sample_rate (Hz); bit_rate (bps — só formatos comprimidos); delivery (inline | uri).
+
+
+ + + + + + + + + + +
EnumValores
ResponseModalitytext · image · audio · video · document
ServiceTierflex · standard · priority
MediaResolutionlow · medium · high · ultra_high
ThinkingLevelminimal · low · medium · high
ThinkingSummariesauto · none
ToolChoiceTypeauto · any · none · validated
+
+
+ +
+

B14. Content blocks (poliforme por type)

+

Blocos de conteúdo dentro de content[] de um step. Discriminador: type.

+
+ + + + + + + + + +
typeCamposEnums relevantes
texttext (obrig.), annotations[]—
imagedata (base64) | uri, mime_type, resolutionimage/png|jpeg|webp|heic|heif|gif|bmp|tiff
audiodata | uri, mime_type, sample_rate, channelsaudio/wav|mp3|aiff|aac|ogg|flac|mpeg|m4a|l16|opus|alaw|mulaw
documentdata | uri, mime_typeapplication/pdf
videodata | uri, mime_type, resolutionvideo/mp4|mpeg|mpg|mov|avi|x-flv|webm|wmv|3gpp · uri aceita YouTube
+
+
Vídeo via URL: { "type": "video", "uri": "https://www.youtube.com/watch?v=..." } dispensa upload.
+
+ +
+

B15. Step types (poliforme por type)

+

A timeline steps[] é a substituta de candidates/outputs. Cada step tem um type. Steps de chamada de ferramenta vêm em pares call → result, ligados por id ↔ call_id. Muitos steps trazem signature (hash para validação backend — nunca modifique).

+ +

Steps de conversa

+
+ + + + + + + +
typeCamposDescrição
user_inputcontent[]Entrada do usuário (presente no GET).
model_outputcontent[]Saída do modelo (texto/imagem/áudio).
thoughtsummary[], signatureRaciocínio. summary é array de ThoughtSummaryContent.
+
+ +

Steps de chamada de ferramenta (call)

+
+ + + + + + + + + + + +
typeCampos-chave
function_callid, name, arguments (object), signature
code_execution_callid, arguments.code, arguments.language (python), signature
url_context_callid, arguments.urls[], signature
google_search_callid, arguments.queries[], search_type (web_search|image_search|enterprise_web_search), signature
google_maps_callid, arguments.queries[], signature
file_search_callid, signature
mcp_server_tool_callid, name, server_name, arguments, signature
+
+ +

Steps de resultado de ferramenta (result)

+
+ + + + + + + + + + + +
typeCampos-chave
function_resultcall_id (obrig.), name, result (string | array de subconteúdo), is_error, signature
code_execution_resultcall_id, result (string), is_error, signature
url_context_resultcall_id, result[] com url + status (success|error|paywall|unsafe), is_error
google_search_resultcall_id, result[], search_suggestions (substitui rendered_content), is_error
google_maps_resultcall_id, result[].places[] (name, place_id, review_snippets[], url), widget_context_token
file_search_resultcall_id, signature
mcp_server_tool_resultcall_id, name, server_name, result
+
+ +
+ Exemplo: par function_call → function_result +
+
// step gerado pelo modelo (status: requires_action)
+{ "type": "function_call", "id": "call_98231", "name": "get_weather",
+  "arguments": { "location": "Boston, MA" } }
+
+// step que você envia de volta no próximo create
+{ "type": "function_result", "call_id": "call_98231", "name": "get_weather",
+  "result": { "temperature": "72F", "conditions": "Partly Cloudy" } }
+
+
+ +
+ +
+

B16. Annotation (citações)

+

Anexadas a blocos text via annotations[]. No novo schema, a citação é tipada como url_citation.

+
+ + + + + + + + +
CampoTipoNotas
typeconst"url_citation" (novo schema).
urlstringURL da fonte.
titlestringTítulo da fonte.
start_index / end_indexintegerIntervalo de caracteres do texto citado.
+
+
Mudança: o schema legado usava { start_index, end_index, source }. O novo usa { type: "url_citation", url, title, start_index, end_index }.
+
+ +
+

B17. Tool schemas (poliforme por type)

+
+ + + + + + + + + + + + + +
typeCamposNotas
functionname, description, parameters (JSON Schema)Função personalizada (client-side).
google_searchsearch_types[]web_search | image_search | enterprise_web_search.
google_mapslatitude, longitude, enable_widgetGrounding geográfico + widget token.
code_execution—Sandbox Python.
url_context—Busca e lê URLs do prompt.
computer_useenvironment (browser), excluded_predefined_functions[]Preview. Suportado em gemini-3-flash-preview (nativo) e gemini-2.5-computer-use-preview-10-2025; gemini-3.5-flash não suporta.
file_searchfile_search_store_names[], metadata_filter, top_kRAG gerenciado.
mcp_servername, url, headers, allowed_tools ({ mode, tools[] })MCP remoto. mode ∈ auto|any|none|validated.
retrievalretrieval_types[] (vertex_ai_search), vertex_ai_search_config (datastores[], engine)Vertex AI Search.
+
+
+ Exemplo: declaração de function + google_search combinadas +
+
"tools": [
+  { "type": "google_search" },
+  { "type": "function", "name": "get_weather",
+    "description": "Get the current weather in a given location",
+    "parameters": {
+      "type": "object",
+      "properties": { "location": { "type": "string" } },
+      "required": ["location"]
+    }
+  }
+]
+
+
+ +
+ +
+

B18. InteractionSseEvent (streaming)

+

Com stream=true, o servidor emite eventos text/event-stream, discriminados por event_type. Todo evento traz event_id (use com last_event_id para retomar).

+
+ + + + + + + + + + + + +
event_typePayloadQuando
interaction.createdinteraction, event_idInício — interação criada (status: in_progress).
interaction.in_progressinteraction_id, status, event_idProgresso da interação (schema novo; substitui o legado interaction.status_update).
interaction.requires_actioninteraction_id, status, event_idAguarda ação do cliente (ex.: function_result pendente).
step.startindex, step, event_idNovo step inicia (ex.: { "type": "model_output" }).
step.deltaindex, delta, event_idFragmento incremental — ex.: { "type": "text", "text": "Hello" }.
step.stopindex, event_idStep finalizado.
interaction.completedinteraction, event_idFim — interaction com outputs vazios (use os deltas anteriores).
errorerror (code, message), event_idFalha no stream.
+
+
+ Renomeações (schema legado → novo): interaction.start→interaction.created, content.start→step.start, content.delta→step.delta, content.stop→step.stop, interaction.complete→interaction.completed, interaction.status_update→interaction.in_progress/interaction.requires_action (o status_update legado foi removido em 08/06/2026). Acumule arguments_delta de function calls e só faça JSON.parse após step.stop. +
+
+ Exemplo: sequência de eventos para "Hello" +
+
{"event_type":"interaction.created","interaction":{"id":"v1_...","status":"in_progress"},"event_id":"evt_1"}
+{"event_type":"step.start","index":0,"step":{"type":"model_output"},"event_id":"evt_2"}
+{"event_type":"step.delta","index":0,"delta":{"type":"text","text":"Hello"},"event_id":"evt_3"}
+{"event_type":"step.stop","index":0,"event_id":"evt_4"}
+{"event_type":"interaction.completed","interaction":{"id":"v1_...","status":"completed"},"event_id":"evt_5"}
+
+
+ +
+ +
+

B19. ModelOption

+

Conjunto de modelos atuais recomendados para a Interactions API (verificado em 2026-06-10). A enum aceita outros valores, mas este guia foca exclusivamente nos modelos atuais — para reasoning/multimodal avançado use gemini-3.1-pro-preview.

+
+ + + + + + + + + + + + +
Model IDUso
gemini-3.5-flashTexto/chat, agêntico e código em escala (GA — padrão recomendado).
gemini-3.1-pro-previewPro — SOTA em raciocínio e multimodal.
gemini-3.1-flash-liteCusto-eficiente, alto volume, agêntico simples.
gemini-3.1-flash-imageNano Banana 2 — geração/edição de imagem.
gemini-3.1-flash-tts-previewTTS (text-to-speech) de baixa latência.
gemini-3.1-flash-live-previewLive API — diálogo de voz em tempo real (áudio-para-áudio).
gemini-3-flash-previewComputer Use com suporte nativo (modelo mais recente com CU embutido).
gemini-2.5-computer-use-preview-10-2025Computer Use — modelo dedicado (única exceção 2.5, pois não há equivalente 3.x).
+
+
STT / transcrição: não há modelo STT dedicado — a transcrição é feita por compreensão de áudio em qualquer modelo multimodal 3.x. Use gemini-3.5-flash (mais capaz) ou gemini-3.1-flash-lite (mais barato; a doc o recomenda explicitamente para transcrição em volume). Para transcrição em tempo real, use a Live API (gemini-3.1-flash-live-preview).
+
+ +
+

B20. AgentOption

+
+ + + + + + + +
Agent IDDescrição
deep-research-preview-04-2026Gemini Deep Research Agent — planeja e executa pesquisa multi-etapa com relatórios citados.
deep-research-max-preview-04-2026Gemini Deep Research Max Agent — máxima abrangência entre centenas de fontes.
antigravity-preview-05-2026Antigravity Agent — agente gerenciado de propósito geral (Gemini 3.5 Flash) com sandbox Linux: código, arquivos e web. Ver §18.9.
+
+
Limitações Deep Research: não suporta function calling personalizado (use MCP) nem saída estruturada. Recomenda-se background=true + polling, ou webhook.
+
Limitações Antigravity: entrada só text/image; sem saída estruturada, function calling custom ou MCP; background=true não suportado, store=true obrigatório; temperature/top_p/top_k/stop_sequences/max_output_tokens retornam 400.
+
+ +
+

B21. Erros

+

Erros seguem o formato { "error": { "code": "...", "message": "..." } }. Em SSE, chegam como evento error. code é um identificador textual (ex.: not_found).

+
+ + + + + + + + + +
HTTPCausa comumAção
400Schema inválido; response_format sem mime_type; mismatch de function_result (id/name/contagem).Corrija o corpo; alinhe call_id/name/contagem.
401 / 403Chave ausente/ inválida; sem acesso ao modelo/agente.Verifique x-goog-api-key e permissões.
404 (not_found)previous_interaction_id expirado/excluído; ID inexistente.Recrie a conversa; cheque retenção (55d pago / 1d free).
429Rate limit / quota.Backoff exponencial; considere service_tier: priority.
5xxErro do servidor.Retry idempotente com backoff.
+
+
+ +
+

Parte C — Migração de generateContent → Interactions API

+

Cada cenário mostra o código antes (generateContent / models.generate_content) e depois (interactions.create), lado a lado. Use isto como receita de transição. generateContent permanece totalmente suportado — migre por escolha, não por obrigação (exceto onde recursos novos só existem na Interactions API).

+
+ +
+

C1. Visão geral da migração

+

A Interactions API é o novo primitivo recomendado para projetos novos e agênticos. Diferenças conceituais centrais:

+
+ + + + + + + + + + + +
DimensãogenerateContentInteractions API
Métodoclient.models.generate_content()client.interactions.create()
Entradacontents (array de Content com parts)input (string, blocos ou steps tipados)
Saídacandidates[].content.parts[]steps[] (timeline tipada) + output_text
EstadoStateless — você reenvia todo o históricoServer-side via previous_interaction_id (ou stateless com store=false)
Configconfig / generation_configgeneration_config (interaction-scoped)
Tarefas longasNão nativobackground=true + polling/webhook
Agentes—Deep Research, Antigravity, managed agents (custom)
+
+
Quando NÃO migrar ainda: se você depende de Batch API, cache explícito, video_metadata ou chamada automática de função (Python), permaneça em generateContent até esses recursos chegarem à Interactions API.
+ +
+ +
+

C2. Breaking changes — Maio 2026

+
+

✅ Status em 2026-06-10 — transição concluída. Desde 08/06/2026 o schema novo (steps + response_format polimórfico) é o único aceito: o schema legado (outputs) foi removido permanentemente, o header Api-Revision passou a ser ignorado e a janela de rollback com Api-Revision: 2026-05-07 fechou em 08/06/2026 — não há mais como voltar. SDKs google-genai/@google/genai 1.x estão quebrados para Interactions; se algo ainda lê outputs ou envia response_mime_type, está falhando em produção — atualize para v2.0.0+ e o schema steps imediatamente. [guia oficial de migração]

+
+

A versão de Maio/2026 do schema da Interactions API (SDK google-genai v2.0.0+; último PyPI 2.10.0, verificado em 2026-06-25) introduziu mudanças incompatíveis. Durante a transição o header Api-Revision controlava o opt-in e depois o rollback; desde 08/06/2026 ele é ignorado e não há rollback (ver status acima).

+ +

Mudanças de formato

+
+
+
Antes — schema legado
+
{
+  "outputs": [
+    { "type": "text", "text": "Hello!" }
+  ]
+}
+
+
+
Depois — novo schema
+
{
+  "steps": [
+    { "type": "model_output",
+      "content": [ { "type": "text", "text": "Hello!" } ] }
+  ]
+}
+
+
+ +
+
+
Antes — response_mime_type + image_config
+
{
+  "response_mime_type": "application/json",
+  "generation_config": {
+    "image_config": { "aspect_ratio": "1:1", "image_size": "1K" }
+  }
+}
+
+
+
Depois — response_format unificado
+
{
+  "response_format": [
+    { "type": "text", "mime_type": "application/json", "schema": { } },
+    { "type": "image", "mime_type": "image/jpeg",
+      "aspect_ratio": "1:1", "image_size": "1K" }
+  ]
+}
+
+
+ +

Renomeação de eventos SSE

+
+ + + + + + + + + +
LegadoNovo
interaction.startinteraction.created
content.startstep.start
content.deltastep.delta
content.stopstep.stop
interaction.completeinteraction.completed
+
+ +

Outras quebras

+
    +
  • function_call agora vive dentro de steps[] (não em outputs), com id, name, arguments.
  • +
  • Step thought ganha summary[] + signature.
  • +
  • Grounding: result.rendered_content → result.search_suggestions; google_search_call/google_search_result migram para steps e ganham signature.
  • +
  • Annotations: { start_index, end_index, source } → { type: "url_citation", url, title, start_index, end_index }.
  • +
  • O GET agora prefixa um step user_input na timeline.
  • +
+
+ SDK 1.x falha desde 08/06/2026: conforme anunciado ("As versões do SDK Python 1.x.x e JS 1.x.x vão falhar nas chamadas da API Interactions"), as chamadas em SDK 1.x agora falham. Atualize para google-genai v2.0.0+ / @google/genai v2.0.0+. +
+ +
+ +
+

C3. Texto simples

+
+
+
Antes — generateContent
+
from google import genai
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents="How does AI work?",
+)
+print(response.text)
+
+
+
Depois — Interactions API
+
from google import genai
+
+client = genai.Client()
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="How does AI work?",
+)
+print(interaction.output_text)
+
+
+
    +
  • models.generate_content → interactions.create
  • +
  • contents → input · response.text → interaction.output_text
  • +
+
+ +
+

C4. Chat multi-turno

+

A maior mudança: você não reenvia o histórico — encadeia via previous_interaction_id.

+
+
+
Antes — histórico manual
+
history = [
+    {"role": "user", "parts": [{"text": "Hello!"}]},
+    {"role": "model", "parts": [{"text": "Hi! How can I help?"}]},
+    {"role": "user", "parts": [{"text": "Capital of France?"}]},
+]
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=history,
+)
+print(response.text)
+
+
+
Depois — estado server-side
+
i1 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Hello!",
+)
+i2 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Capital of France?",
+    previous_interaction_id=i1.id,
+)
+print(i2.output_text)
+
+
+
Cache implícito: encadear com previous_interaction_id permite ao servidor reaproveitar o histórico em cache — mais barato e rápido que reenviar tudo.
+
Interaction-scoped: tools, system_instruction e generation_config NÃO são herdados pelo previous_interaction_id — reespecifique-os a cada turno.
+
+ +
+

C5. Streaming

+
+
+
Antes — generate_content_stream
+
stream = client.models.generate_content_stream(
+    model="gemini-3.5-flash",
+    contents="Write a poem.",
+)
+for chunk in stream:
+    print(chunk.text, end="")
+
+
+
Depois — stream de steps
+
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Write a poem.",
+    stream=True,
+)
+for event in stream:
+    if event.type == "step.delta" and event.delta.type == "text":
+        print(event.delta.text, end="")
+
+
+
    +
  • O stream agora emite eventos tipados (interaction.created, step.start/delta/stop, interaction.completed) em vez de chunks de texto homogêneos.
  • +
  • Filtre step.delta com delta.type == "text" para a saída textual; outros deltas carregam thoughts, imagens ou argumentos de função.
  • +
+
+ +
+

C6. Multimodal (imagem / áudio / vídeo / PDF)

+

Em vez de types.Part.from_bytes, use blocos de conteúdo tipados no input.

+
+
+
Antes — Part.from_bytes
+
from google.genai import types
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        types.Part.from_bytes(
+            data=img_bytes, mime_type="image/png"),
+        "What is in this picture?",
+    ],
+)
+print(response.text)
+
+
+
Depois — blocos tipados
+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        { "type": "text", "text": "What is in this picture?" },
+        { "type": "image", "data": base64_img,
+          "mime_type": "image/png" },
+    ],
+)
+print(interaction.output_text)
+
+
+
    +
  • Tipos de bloco: text, image, audio, document (PDF), video (aceita uri do YouTube).
  • +
  • Posicione mídias grandes (PDF/documento) no início do input para maximizar cache; para uma única imagem/PDF curto, coloque o texto depois da mídia.
  • +
  • ainda só em generateContent video_metadata (cortes, FPS customizado).
  • +
+
+ +
+

C7. Geração de imagem

+
+
+
Antes — response_modalities + image_config
+
response = client.models.generate_content(
+    model="gemini-3.1-flash-image",
+    contents="A robot holding a red skateboard",
+    config=types.GenerateContentConfig(
+        response_modalities=["IMAGE"],
+        image_config=types.ImageConfig(aspect_ratio="16:9"),
+    ),
+)
+
+
+
Depois — response_format tipo image
+
interaction = client.interactions.create(
+    model="gemini-3.1-flash-image",
+    input="A robot holding a red skateboard",
+    response_format={
+        "type": "image",
+        "mime_type": "image/jpeg",
+        "aspect_ratio": "16:9",
+        "image_size": "1K",
+    },
+)
+img = interaction.output_image
+
+
+
    +
  • image_config (dentro de generation_config) → entrada image em response_format.
  • +
  • Acesse a imagem por interaction.output_image; para histórias intercaladas texto+imagem, itere steps.
  • +
  • Edição: encadeie com previous_interaction_id e peça a alteração (ex.: trocar idioma do gráfico).
  • +
+
+ +
+

C8. Function calling

+

O loop muda de "monte contents com functionResponse" para "envie um step function_result com call_id".

+
+
+
Antes — functionResponse em contents
+
resp = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=contents,
+    config=types.GenerateContentConfig(tools=[tool]),
+)
+fc = resp.candidates[0].content.parts[0].function_call
+# ... executa ...
+contents.append({"role": "user", "parts": [{
+    "function_response": {
+        "name": fc.name,
+        "response": {"result": result},
+    }}]})
+final = client.models.generate_content(
+    model="gemini-3.5-flash", contents=contents,
+    config=types.GenerateContentConfig(tools=[tool]))
+
+
+
Depois — step function_result
+
i = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Weather in Boston?",
+    tools=[tool],
+)
+fc = i.steps[-1]  # type == "function_call"
+# ... executa ...
+final = client.interactions.create(
+    model="gemini-3.5-flash",
+    previous_interaction_id=i.id,
+    tools=[tool],
+    input=[{
+        "type": "function_result",
+        "name": fc.name,
+        "call_id": fc.id,
+        "result": [{"type": "text", "text": json.dumps(result)}],
+    }],
+)
+print(final.output_text)
+
+
+
+ Correspondência estrita (Gemini 3.x): todo function_result deve incluir o call_id (= id do call) e o name correspondente, e haver exatamente um resultado por chamada. A Interactions API retorna erro em mismatch (generateContent apenas degrada silenciosamente). +
+
    +
  • Status intermediário: requires_action enquanto aguarda o function_result.
  • +
  • Respostas multimodais: inclua imagem/áudio dentro do result, não como parte separada.
  • +
  • Instruções extras: anexe ao final do texto do resultado, separadas por duas quebras de linha.
  • +
  • só em generateContent chamada automática de função (Python).
  • +
+
+ +
+

C9. Structured Output (JSON)

+
+
+
Antes — response_schema
+
resp = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents="List 3 cookie recipes",
+    config=types.GenerateContentConfig(
+        response_mime_type="application/json",
+        response_schema=Recipe,
+    ),
+)
+print(resp.text)
+
+
+
Depois — response_format tipo text
+
i = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="List 3 cookie recipes",
+    response_format={
+        "type": "text",
+        "mime_type": "application/json",
+        "schema": {
+            "type": "object",
+            "properties": {
+                "recipe_name": {"type": "string"},
+                "ingredients": {
+                    "type": "array",
+                    "items": {"type": "string"}},
+            },
+            "required": ["recipe_name", "ingredients"],
+        },
+    },
+)
+print(i.output_text)
+
+
+
    +
  • response_mime_type + response_schema → um único response_format tipo text com mime_type: "application/json" e schema.
  • +
  • Pode combinar JSON com ferramentas (Search, URL context, code execution, function calling) na mesma requisição em Gemini 3.x.
  • +
+
+ +
+

C10. Thinking

+
+
+
Antes — thinking_budget
+
resp = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents="Prove sqrt(2) is irrational.",
+    config=types.GenerateContentConfig(
+        thinking_config=types.ThinkingConfig(
+            thinking_budget=7500,
+        ),
+    ),
+)
+
+
+
Depois — thinking_level
+
i = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Prove sqrt(2) is irrational.",
+    generation_config={"thinking_level": "high"},
+)
+# thoughts aparecem como steps type=="thought"
+for s in i.steps:
+    if s.type == "thought":
+        print(s.summary)
+
+
+
    +
  • thinking_budget (numérico) → thinking_level (minimal|low|medium|high). Default em Gemini 3.5 Flash: medium.
  • +
  • Na Interactions API o raciocínio é exposto como steps thought com summary + signature, em ordem cronológica.
  • +
  • Preservação automática: o contexto de raciocínio é mantido entre turnos automaticamente (em generateContent é implícito, exigindo reenviar o histórico com signatures).
  • +
+
Nunca modifique blocos thought nem suas signature. Em modo store=false, reenvie-os exatamente como recebidos.
+
+ +
+

C11. Caching

+
+
+
Antes — cache explícito
+
cache = client.caches.create(
+    model="gemini-3.5-flash",
+    config=types.CreateCachedContentConfig(
+        contents=[big_document],
+        ttl="3600s",
+    ),
+)
+resp = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents="Summarize it",
+    config=types.GenerateContentConfig(
+        cached_content=cache.name),
+)
+
+
+
Depois — cache implícito
+
# 1º turno com o documento grande no início
+i1 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+      {"type": "document", "data": pdf_b64,
+       "mime_type": "application/pdf"},
+      {"type": "text", "text": "Read this."},
+    ],
+)
+# turnos seguintes reaproveitam o cache automaticamente
+i2 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Summarize it",
+    previous_interaction_id=i1.id,
+)
+
+
+
    +
  • Cache explícito (caches.create / cached_content) ainda é exclusivo de generateContent.
  • +
  • Na Interactions API, o cache é implícito: encadeie com previous_interaction_id e mantenha conteúdo estável no início do prompt.
  • +
  • Acompanhe o aproveitamento por usage.total_cached_tokens.
  • +
+
+ + + +
+

C13. Streaming + Tools (acúmulo de argumentos)

+

Em streaming com function calling, os argumentos chegam fragmentados. Acumule e só faça parse no fim do step.

+
buffers = {}  # index -> string de argumentos
+stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Weather in Boston and Paris?",
+    tools=[weather_tool],
+    stream=True,
+)
+for event in stream:
+    if event.event_type == "step.start" and event.step.type == "function_call":
+        buffers[event.index] = ""
+    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
+        buffers[event.index] += event.delta.arguments
+    elif event.event_type == "step.stop" and event.index in buffers:
+        args = json.loads(buffers[event.index])  # parse só agora
+        # ... despacha a função ...
+
Regra de ouro: nunca faça JSON.parse/json.loads em arguments_delta parcial — espere o step.stop do índice correspondente.
+
+ +
+

C14. Tabela completa de mapeamento

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
generateContentInteractions APIObservação
client.models.generate_content()client.interactions.create()Método principal.
generate_content_stream()create(..., stream=True)Streaming.
contentsinputString, blocos ou steps tipados.
Content.parts[]content[] (blocos tipados)text/image/audio/document/video.
role: "user"/"model"step user_input/model_outputPapéis viram tipos de step.
config / GenerateContentConfiggeneration_configInteraction-scoped.
system_instructionsystem_instructionReenviar a cada turno.
response.textinteraction.output_textConveniência.
imagem em partsinteraction.output_imageConveniência.
candidates[]steps[]Timeline tipada.
candidate.content.parts[]step.content[]—
finish_reasoninteraction.statuscompleted/requires_action/…
response_mime_type + response_schemaresponse_format (tipo text)mime_type + schema.
response_modalities + image_configresponse_format (tipo image) ou arrayModalidades unificadas.
thinking_config.thinking_budgetgeneration_config.thinking_levelEnum em vez de número.
function_call (part)step function_call (id,name,arguments)—
function_response (part)step function_result (call_id,name,result)Match estrito.
tools=[Tool(google_search=...)]tools=[{"type":"google_search"}]Schema textual.
grounding_metadatasteps *_call/*_result + annotationsurl_citation.
caches.create + cached_contentprevious_interaction_id (cache implícito)Explícito ainda só em generateContent.
histórico manual em contentsprevious_interaction_id (store=true)ou stateless com store=false.
—background=true + cancel + webhooksTarefas longas / Deep Research.
+
+
+ +
+

C15. Checklist de migração

+
    +
  • ☐ Atualizar SDK: google-genai >= 2.0.0 (Python) / @google/genai equivalente — obrigatório desde 08/06/2026 (SDKs 1.x falham).
  • +
  • ☐ Trocar models.generate_content → interactions.create.
  • +
  • ☐ contents → input; response.text → output_text.
  • +
  • ☐ Adotar previous_interaction_id para chat (ou manter store=false se gerencia histórico no cliente).
  • +
  • ☐ Migrar leitura de saída: candidates → steps; tratar status == requires_action.
  • +
  • ☐ Function calling: enviar function_result com call_id + name casados (1:1).
  • +
  • ☐ response_mime_type/response_schema/image_config → response_format.
  • +
  • ☐ thinking_budget → thinking_level; remover temperature/top_p/top_k (Gemini 3.x).
  • +
  • ☐ Atualizar nomes de eventos SSE (content.* → step.*, etc.).
  • +
  • ☐ Atualizar annotations para url_citation e grounding para search_suggestions.
  • +
  • ☐ Reduzir tool calls excessivos via thinking_level menor + instrução de orçamento de ferramentas.
  • +
  • ☐ Verificar recursos ausentes (Batch, cache explícito, video_metadata, auto-function-calling) — manter em generateContent se necessário.
  • +
+
Automação: agentes de código com skills (ex.: Antigravity) podem instalar a skill Gemini Interactions API e rodar /gemini-interactions-api migrate my app to Gemini 3.5 Flash.
+
+ +
+

C16. Histórico sem estado (store=false)

+

Se você prefere gerenciar o histórico no cliente (sem persistência server-side), use store=false e reenvie a timeline completa como input (array de steps).

+
i = client.interactions.create(
+    model="gemini-3.5-flash",
+    store=False,
+    input=[
+        {"type": "user_input",
+         "content": [{"type": "text", "text": "Hello!"}]},
+        {"type": "model_output",
+         "content": [{"type": "text", "text": "Hi! How can I help?"}]},
+        {"type": "user_input",
+         "content": [{"type": "text", "text": "Capital of France?"}]},
+    ],
+)
+print(i.output_text)
+
Restrições do store=false: incompatível com background=true e impede usar previous_interaction_id nos turnos seguintes. Reenvie blocos thought/signature intactos.
+
+ +
+

C17. Datas críticas & estratégia

+
+ + + + + + + + +
DataEventoAção
30/11/2025Bibliotecas legadas descontinuadas (google-generativeai etc.).Migrar para google-genai / @google/genai.
07/05/2026Novo schema disponível para opt-in.Envie Api-Revision: 2026-05-20 para testar.
26/05/2026Novo schema virou padrão.Opt-out temporário era possível com Api-Revision: 2026-05-07 (janela encerrada).
08/06/2026Schema legado removido (consumado); SDK 1.x falha.Estar em SDK v2.0.0+ e novo schema. Header Api-Revision é ignorado desde então.
+
+
Janela encerrada: a remoção do schema legado foi consumada em 08/06/2026 — não há rollback e o header Api-Revision é ignorado. Chamadas em SDK 1.x ou no schema legado falham; se ainda não migrou, atualize para google-genai/@google/genai v2.0.0+ e o schema steps imediatamente.
+ +
+ +
+

Apêndice

+
+ +
+

Ap1. Cookbook (notebooks oficiais)

+

Notebooks do repositório google-gemini/cookbook que usam a Interactions API (client.interactions.*), verificados em 2026-05-24.

+
+ + + + + + + + +
NotebookO que demonstra
quickstarts/Get_started_interactions_api.ipynbGuia inicial da Interactions API: interface unificada modelo+agente, estado server-side, orquestração de ferramentas, texto, multi-turn e tool use.
quickstarts/Get_started_Deep_Research.ipynbAgente Deep Research via Interactions API: criar interação long-running e fazer polling do status até concluir.
quickstarts/Get_started_managed_agents.ipynbAgentes gerenciados/custom em VMs isoladas; continuação multi-turn via environment_id + previous_interaction_id.
quickstarts/Webhooks.ipynbWebhooks para notificação de conclusão de operações assíncronas (inclui Interactions), evitando polling.
+
+
+ Ainda em generate_content (não migrados): Function_calling.ipynb, Streaming.ipynb, Caching.ipynb, JSON_mode.ipynb, Enum.ipynb e Get_started.ipynb usam a API legada — não os trate como exemplos de Interactions API. O quickstarts/README.md ainda não tem seção dedicada à Interactions API. +
+
+ +
+

Ap2. Glossário

+
+ + + + + + + + + + + + + + + +
TermoDefinição
InteractionRecurso central — uma rodada completa de execução (entradas, raciocínio, tool calls, saída) como timeline de steps.
stepItem tipado da timeline (user_input, model_output, thought, *_call, *_result). Substitui candidates/outputs.
previous_interaction_idID encadeado que ativa estado server-side e cache implícito do histórico.
storePersistência da interação (default true; false = stateless).
backgroundExecução assíncrona para tarefas longas; combinada com polling ou webhook.
signatureHash de validação backend anexado a steps (thought, tool calls). Nunca modificar.
thinking_levelEsforço de raciocínio: minimal|low|medium|high. Substitui thinking_budget.
response_formatFormato de saída unificado (text/JSON, image, audio). Absorve response_mime_type + image_config.
Api-RevisionHeader de versionamento do schema durante a transição de Maio/2026. Ignorado desde 08/06/2026 — o schema steps é o único aceito.
Cache implícitoReaproveitamento automático do histórico quando se usa previous_interaction_id.
Deep ResearchAgentes (deep-research-*) para pesquisa longa; sem function calling custom (use MCP) nem saída estruturada.
+
+
+ +
+

Ap3. Histórico deste guia

+
    +
  • 2026-05-24 — Versão completa: Parte A (23 capítulos de conceitos/guias), Parte B (referência REST: endpoints, recursos, steps, tools, SSE, modelos/agentes, erros) e Parte C (17 cenários de migração antes/depois + breaking changes Maio/2026 + checklist + datas). Apêndice com cookbook verificado e glossário.
  • +
  • 2026-05-24 (revisão de modelos) — Padronização para apenas os modelos atuais: gemini-3.5-flash, gemini-3.1-pro-preview, gemini-3.1-flash-lite, gemini-3.1-flash-image (Nano Banana 2), TTS gemini-3.1-flash-tts-preview e Live gemini-3.1-flash-live-preview. Exceção: Computer Use usa gemini-3-flash-preview (suporte nativo) e gemini-2.5-computer-use-preview-10-2025 (dedicado), pois não há equivalente 3.5/3.1.
  • +
  • 2026-06-10 — Varredura de atualização: remoção do schema legado tratada como fato consumado em 08/06/2026 — steps[] é o único schema, header Api-Revision ignorado, janela de rollback fechada e SDKs google-genai/@google/genai 1.x quebrados para Interactions (mínimo agora: 2.0.0; último PyPI/npm: 2.8.0). Prosa de transição convertida para o passado (Sobre, TL;DR, §1.4, §2.2, §6, B2, B18, C2, C15, C17, glossário). Nuance adicionada: a página oficial migrate-to-interactions agora descreve a Interactions API como "the standard interface for building with Gemini" e a recomenda para todo desenvolvimento novo; a overview mantém Beta + generateContent para produção estável. Datas de verificação re-stampadas para 2026-06-10.
  • +
  • 2026-06-11 — Reorganização da doc oficial absorvida: a Interactions API ganhou seção própria (/docs/interactions/*) com novo quickstart (interactions/quickstart) e overview (interactions/interactions-overview); URLs de ferramentas/guias atualizadas para os caminhos canônicos /interactions/... (google-search, maps-grounding, code-execution, url-context, computer-use, file-search, tool-combination, webhooks, files, file-input-methods, media-resolution). Nova cobertura de agentes gerenciados: Antigravity agent (antigravity-preview-05-2026, §18.9), environments/sandboxes (§18.10), parâmetro environment/environment_id (§3.1) e AgentOption (B20). §18 renomeada para "Agentes: Deep Research & Antigravity". Reconfirmado na página de breaking changes: header Api-Revision ignorado e schema legado removido desde 08/06/2026 (exemplos oficiais ainda incluem o header; é no-op).
  • +
  • 2026-06-19 — Micro-sweep de superfície e versões. Adicionado caveat Developer API (Beta) vs Vertex / Gemini Enterprise Agent Platform (experimental) no topo (§1) e em §17.3: a Interactions API existe nas duas superfícies, mas code_execution dentro de Interactions é documentado/exemplificado só na Developer API; na Vertex a execução de código é documentada via generateContent e, em teste, code_execution via Interactions não funcionou sob auth Vertex (observação, não limitação oficial). Completada a limitação de MCP remoto (apenas Streamable HTTP; SSE não suportado; name sem hífen) em §1.5 e §22. Versões de SDK atualizadas para google-genai/@google/genai 2.9.0 — a 2.9.0 reimplementou a Interactions internamente mantendo a API pública compatível.
  • +
+

Fontes primárias: ai.google.dev/gemini-api/docs/interactions/interactions-overview, interactions/quickstart, ai.google.dev/api/interactions-api, interactions-breaking-changes-may-2026, migrate-to-interactions, docs/agents/antigravity-agent/agent-environment e github.com/google-gemini/cookbook; superfície Vertex em docs.cloud.google.com/gemini-enterprise-agent-platform/reference/models/interactions-api e .../models/tools/code-execution. Verificado em 2026-06-19 — para fatos perecíveis (modelos, datas, limites), consulte sempre a fonte oficial.

+
+ + +
+
+ + + + + + diff --git a/references/agents_tools_best_guides/guia_langgraph.html b/references/agents_tools_best_guides/guia_langgraph.html new file mode 100644 index 0000000..90d3904 --- /dev/null +++ b/references/agents_tools_best_guides/guia_langgraph.html @@ -0,0 +1,3987 @@ + + + + + +Guia LangGraph — Referência completa (Python) + + + + + + + + +
+
+
Guia LangGraph Python — Referência completa
+
+ Verificado em 2026-06-25 + langgraph + Python + +
+
+
+ +
+ + +
+ +
+

Guia LangGraph — Referência completa (Python)

+

+ Documentação técnica exaustiva do LangGraph em Python, o runtime + de orquestração de baixo nível usado pelo LangChain e pelo Deep Agents para + construir agentes stateful, durables e de longa duração. + Cobre StateGraph, Send, Command, + persistência (checkpointers SQLite/Postgres/Redis), human-in-the-loop, + streaming v2, memória curta e longa, multi-agent (supervisor/swarm), time + travel, durable execution e a Functional API. +

+
+ langgraph + Python 3.10+ + SOTA · 2026-06-25 +
+
+ +
+

Sobre este guia

+

+ Este guia é uma conversão fiel da documentação oficial pública + do LangGraph em + docs.langchain.com/oss/python/langgraph, + complementada pelos pacotes prebuilt langgraph-supervisor e + langgraph-swarm e pela referência de API em + reference.langchain.com/python/langgraph. +

+

+ A Parte A apresenta os conceitos em 26 capítulos, na ordem de + leitura recomendada. A Parte B é a referência técnica de cada + classe pública: assinatura, parâmetros em tabela, métodos relevantes e exemplos. + Todos os exemplos estão em Python — a porta oficial em JavaScript existe em + langchain-ai/langgraphjs + mas tem APIs próprias e não é coberta aqui. +

+
+ Como ler: a Parte A ensina os padrões e a + mecânica de execução. A Parte B é consulta rápida: cada classe + traz sua assinatura, atributos em tabela e métodos em blocos + <details> expansíveis (clique no ▸ para abrir). +
+
+ Notas de versão: alguns recursos são recentes — node timeouts + (TimeoutPolicy) e graceful drain (RunControl/ + GraphDrained) exigem langgraph >= 1.2; + DeltaChannel (otimização de armazenamento) também é 1.2+; + add_sequence exige >= 0.2.46; + context_schema substituiu config_schema em + >= 0.6.0. O default da recursion_limit passou a ser + 1000 em >= 1.0.6. +
Atualização 2026-06-19: último PyPI langgraph 1.2.6 (deps: langchain-core >=1.4,<2, langgraph-checkpoint >=4.1,<5, langgraph-prebuilt >=1.1,<1.2). Novidades 1.2.x além das acima: error_handler= por nó (recebe NodeError, retorna Command para compensação/reroteamento — padrão Saga; Python-only), interrupt_mode + predicado when no HumanInTheLoopMiddleware, e event streaming v2/v3 (beta, projeções tipadas por canal). Todos opt-in e retrocompatíveis. Resumo 1.2.2→1.2.4: fix de IDs estáveis para checkpoints com DeltaChannel (1.2.2); streaming v3 no RemoteGraph e rename ProtocolEvent.eventId → event_id (1.2.3 — relevante para quem consome eventos do protocolo beta v3); ensure_config agora faz merge de callbacks/tags/metadata (1.2.3); fix de compatibilidade _on_started (1.2.4); merge de lc_versions nos metadados de config e fix de updateState/DeltaChannel em thread vazia (1.2.5 — só bugfix); nested-subgraph herda checkpoint_ns do pai (regressão da 1.2.3), cancelamento de subgraphs em abort de stream v3 e Tornado→6.5.6 (1.2.6 — só bugfix). Sem mudanças nas superfícies públicas de StateGraph/interrupt/Command. +
+
+ +
+

Fontes oficiais

+ +

+ Última verificação contra estas fontes: 2026-06-10. + Sempre que houver divergência entre este guia e a documentação oficial em + produção, a documentação oficial é a fonte autoritativa. +

+
+ +
+

Parte A — Conceitos

+

Vinte e seis capítulos cobrindo o LangGraph na ordem de leitura recomendada da documentação oficial.

+
+ +
+

1. Visão geral

+

+ O LangGraph é definido pela documentação oficial como + "a low-level orchestration framework and runtime for building, managing, and + deploying long-running, stateful agents". É inspirado em Pregel, Apache Beam + e NetworkX, e modela um workflow como um grafo direcionado com três componentes: +

+
    +
  1. State — um snapshot compartilhado, definido como + TypedDict, dataclass ou Pydantic BaseModel.
  2. +
  3. Nodes — funções Python que codificam a lógica.
  4. +
  5. Edges — funções (ou edges estáticos) que determinam a + próxima execução.
  6. +
+

+ A execução acontece em super-steps discretos via passagem de mensagens: + nós começam inactive, ficam active ao receber mensagens e a + execução termina quando todos os nós estão inativos e não há mensagens em + trânsito. Nós que rodam em paralelo compartilham o mesmo super-step; sequenciais + ocupam super-steps distintos. +

+

Benefícios principais

+
+ + + + + + + + + +
BenefícioDescrição
Durable executionAgentes persistem por falhas e retomam de checkpoints.
Human-in-the-loopInspeção e modificação do estado do agente em qualquer ponto.
Memória abrangenteWorking memory por thread + memória de longo prazo cross-session.
DebuggingLangSmith provê visualização de traces e métricas de runtime.
DeploymentInfra escalável para workflows stateful de longa duração.
+
+

Posição no ecossistema

+
+ + + + + + + + + + +
ProdutoPapel
Deep AgentsHarness do agente: planning, subagents, FS, gerenciamento de contexto.
LangChainFramework de agente: abstrações de modelo/tool e o agent loop.
LangGraphRuntime de orquestração: durable execution, streaming, HITL.
LangSmithTracing, evaluations, prompts, deployment.
LangSmith EngineDetecta issues em traces de produção e propõe correções/PRs automaticamente.
LangSmith FleetConstrutor no-code de agentes.
+
+ +
+ +
+

2. Instalação

+
pip install -U langgraph
+# ou
+uv add langgraph
+

+ Pacotes complementares conforme o uso: +

+
+ + + + + + + + + + + +
PacotePropósito
langgraphNúcleo (StateGraph, runtime, in-memory checkpointer).
langgraph-checkpoint-sqliteSqliteSaver / AsyncSqliteSaver.
langgraph-checkpoint-postgresPostgresSaver / AsyncPostgresSaver.
langgraph-checkpoint-redisRedisSaver / AsyncRedisSaver (community Redis).
langgraph-supervisorPadrão supervisor multi-agent (create_supervisor).
langgraph-swarmPadrão swarm (create_swarm).
langchain / langchain-openai / langchain-anthropic / langchain-google-genaiModelos e mensagens — opcionais, mas a maior parte dos exemplos depende deles.
+
+

O overview oficial não declara versão mínima de Python; na prática, o pacote suporta Python 3.10+.

+ +

Política de integração de modelos (chat models)

+

+ O LangGraph não fala com provedores diretamente — ele orquestra + chat models do LangChain. Como cada classe roteia para uma API + diferente, vale fixar a política antes dos exemplos: +

+
+ + + + + + + +
ProvedorClasse / pacoteAPI atingida
OpenAIChatOpenAI · langchain-openaiResponses API quando use_responses_api=True; caso contrário, Chat Completions.
AnthropicChatAnthropic · langchain-anthropicMessages API nativa da Anthropic (SDK anthropic) — não é wrapper.
GoogleChatGoogleGenerativeAI · langchain-google-genaiSDK consolidado google-genai (v4.0.0+), via generateContent.
+
+
+ OpenAI — Responses API não é automática com string. Passar uma + string "openai:gpt-5.5" a create_agent/create_react_agent + cai em Chat Completions. Para garantir a Responses API (ex.: ZDR, + threading server-side), instancie ChatOpenAI(model="gpt-5.5", use_responses_api=True) + e passe o objeto como model=. +
+
from langchain_openai import ChatOpenAI
+from langchain_anthropic import ChatAnthropic
+from langchain_google_genai import ChatGoogleGenerativeAI
+
+# OpenAI — Responses API (NUNCA Chat Completions): use a flag explícita.
+openai_llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
+
+# Anthropic — SDK nativo (Messages API):
+anthropic_llm = ChatAnthropic(model="claude-sonnet-4-6")
+
+# Google — SDK google-genai (>= 4.0); em strings provider:model use "google_genai:"
+google_llm = ChatGoogleGenerativeAI(model="gemini-3.5-flash")  # str: "google_genai:gemini-3.5-flash"
+
+# (opcional) threading server-side por response id no OpenAI:
+openai_llm = ChatOpenAI(model="gpt-5.4-mini", use_previous_response_id=True)
+

+ O roteamento para a Responses API também é automático (sem a + flag) quando o modelo usa: (a) built-in tools (web_search, + file_search, image generation, computer use, code interpreter, + remote MCP), (b) o parâmetro reasoning={"effort": ..., "summary": ...}, + ou (c) previous_response_id na invocação. Não existe flag + output_version nem um ID de modelo que "force" Responses — o caminho + é use_responses_api=True ou um desses gatilhos. +

+
# Estes já roteiam para a Responses API automaticamente:
+llm        = ChatOpenAI(model="gpt-5.5", reasoning={"effort": "medium", "summary": "auto"})
+llm_tools  = ChatOpenAI(model="gpt-5.4-mini").bind_tools([{"type": "web_search_preview"}])
+
+ Gemini Interactions API: a Interactions API do Gemini (endpoint + /interactions, stateful/agêntica) não tem integração + nativa com LangChain/LangGraph/Deep Agents (maio/2026). + ChatGoogleGenerativeAI usa generateContent via + google-genai; recursos exclusivos da Interactions API + (histórico server-side via previous_interaction_id, agentes + gerenciados) não são expostos. Não existe + ChatGoogleGenerativeAI(use_interactions_api=...). Para usá-la hoje, + chame o SDK google-genai diretamente — a Interactions API é coberta + no guia dedicado Gemini Interactions API. +
+ +
+ +
+

3. Modelo conceitual

+

Hello-world

+
from langgraph.graph import StateGraph, MessagesState, START, END
+
+def mock_llm(state: MessagesState):
+    return {"messages": [{"role": "ai", "content": "hello world"}]}
+
+graph = StateGraph(MessagesState)
+graph.add_node(mock_llm)
+graph.add_edge(START, "mock_llm")
+graph.add_edge("mock_llm", END)
+graph = graph.compile()
+
+graph.invoke({"messages": [{"role": "user", "content": "hi!"}]})
+

Super-steps

+

+ Cada tick do grafo é um super-step. Para um pipeline sequencial + START → A → B → END, quatro checkpoints são produzidos + (vazio/inicial, após input, após A, após B). Nós com múltiplas arestas de saída + disparam todos os destinos em paralelo no super-step seguinte. +

+

Graph API vs Functional API

+
+ + + + + + + + +
AspectoFunctional APIGraph API
Controle de fluxoPython padrão (if, for, chamadas)Estrutura explícita de grafo/DAG
EstadoEscopo da função; sem state explícitoRequer State + reducers
CheckpointingSalva resultados de @task no checkpoint atualNovo checkpoint após cada super-step
VisualizaçãoNão suportada (dinâmico em runtime)Suportada; útil para debug
+
+ +
+ +
+

4. StateGraph

+

+ StateGraph é o construtor de grafo. Recebe o schema de estado e, + opcionalmente, schemas de contexto, input e output. +

+
from langgraph.graph import StateGraph, START, END
+from typing_extensions import TypedDict
+
+class State(TypedDict):
+    foo: int
+    bar: list[str]
+
+builder = StateGraph(State)
+# ... add_node / add_edge ...
+graph = builder.compile()
+

Schemas de entrada, saída e privados

+

+ O schema principal define o overall state. Schemas opcionais permitem + expor um contrato mais estrito para o cliente: +

+
class InputState(TypedDict):
+    user_input: str
+
+class OutputState(TypedDict):
+    graph_output: str
+
+class OverallState(TypedDict):
+    foo: str
+    user_input: str
+    graph_output: str
+
+class PrivateState(TypedDict):
+    bar: str
+
+def node_1(state: InputState) -> OverallState:
+    return {"foo": state["user_input"] + " name"}
+
+def node_2(state: OverallState) -> PrivateState:
+    return {"bar": state["foo"] + " is"}
+
+def node_3(state: PrivateState) -> OutputState:
+    return {"graph_output": state["bar"] + " Lance"}
+
+builder = StateGraph(OverallState, input_schema=InputState, output_schema=OutputState)
+builder.add_node("node_1", node_1)
+builder.add_node("node_2", node_2)
+builder.add_node("node_3", node_3)
+builder.add_edge(START, "node_1")
+builder.add_edge("node_1", "node_2")
+builder.add_edge("node_2", "node_3")
+builder.add_edge("node_3", END)
+
+graph = builder.compile()
+graph.invoke({"user_input": "My"})
+# {'graph_output': 'My name is Lance'}
+
+ Um nó pode escrever em qualquer chave do estado — não apenas + nas que estão no seu schema de entrada. PrivateState é registrado + automaticamente quando referenciado em assinaturas de nó. +
+ +
+ +
+

5. Schemas de estado

+

+ O estado pode ser declarado de três formas: TypedDict (recomendado + por performance), dataclass ou Pydantic BaseModel (com + validação recursiva, mas mais lento). +

+
from typing_extensions import TypedDict
+
+class State(TypedDict):
+    foo: int
+    bar: list[str]
+
+ Limitações conhecidas do Pydantic como state schema: +
    +
  • A saída não é uma instância Pydantic.
  • +
  • Validação roda apenas nos inputs do primeiro nó.
  • +
  • O traceback não identifica o nó que falhou.
  • +
+
+ +
+ +
+

6. Reducers

+

+ Cada chave do estado tem um reducer independente. Sem reducer, atualizações + sobrescrevem a chave. Para acumular, use Annotated: +

+
from typing import Annotated
+from operator import add
+from typing_extensions import TypedDict
+
+class State(TypedDict):
+    foo: int                        # overwrite
+    bar: Annotated[list[str], add]  # concat
+

Bypass de reducer com Overwrite

+
from langgraph.types import Overwrite
+
+def replace_messages(state: State):
+    return {"messages": Overwrite(["replacement message"])}
+# Forma JSON-compatível:
+# return {"messages": {"__overwrite__": ["replacement message"]}}
+
+ Receber múltiplos Overwrite para a mesma chave em + um único super-step levanta InvalidUpdateError. +
+ +

Canais do Pregel (camada de baixo nível)

+

+ Por baixo de reducers e Annotated, cada chave do estado é um + canal do Pregel. O tipo do canal define a semântica de escrita ao + longo dos super-steps. A maioria dos grafos nunca instancia canais + diretamente — eles são inferidos do schema —, mas conhecê-los ajuda a + entender o comportamento de acumulação e a API Pregel crua. +

+
+ + + + + + + + + +
CanalImportSemântica
LastValuelanggraph.channelsDefault; guarda apenas o último valor escrito (sobrescreve).
Topiclanggraph.channelsPubSub; Topic(str, accumulate=True) acumula todos os valores escritos no run.
BinaryOperatorAggregatelanggraph.channelsAgregado corrente via operador binário (ex.: operator.add).
EphemeralValuelanggraph.channelsValor transitório: existe só durante o super-step; não é persistido entre steps.
DeltaChannel betalanggraph.channelsReducer em bulk com snapshots periódicos (requer langgraph >= 1.2).
+
+
from langgraph.channels import (
+    LastValue, Topic, BinaryOperatorAggregate, EphemeralValue, DeltaChannel,
+)
+import operator
+
+ch: LastValue[int] = LastValue(int)                 # default; sobrescreve valor anterior
+topic: Topic[str] = Topic(str, accumulate=True)     # PubSub; acumula valores no run
+total = BinaryOperatorAggregate(int, operator.add)  # agregado corrente via operador binário
+ +

DeltaChannel — reducer em bulk com snapshots beta · langgraph >= 1.2

+

+ O DeltaChannel usa um bulk reducer: em vez de ser + chamado pairwise (estado atual + uma write por vez), recebe o estado atual mais + uma sequência com todas as writes do super-step numa + única chamada — útil quando o reducer é associativo e se beneficia de processar + o lote inteiro de uma vez. +

+
from typing import Annotated
+from typing_extensions import TypedDict
+from langgraph.channels import DeltaChannel
+
+class State(TypedDict):
+    messages: Annotated[list[str], DeltaChannel(my_reducer, snapshot_frequency=5)]
+
    +
  • snapshot_frequency=K grava um snapshot completo a cada K steps, limitando a latência de leitura a O(K); None (default) = sem snapshots.
  • +
  • API ainda beta — pode mudar entre versões.
  • +
+ +

API Pregel crua

+

+ Para construir grafos sem o açúcar de StateGraph, há a API de + baixo nível com Pregel e NodeBuilder: +

+
from langgraph.channels import EphemeralValue
+from langgraph.pregel import Pregel, NodeBuilder
+ +
+ +
+

7. MessagesState e add_messages

+

+ add_messages é o reducer canônico para listas de mensagens. Por + padrão concatena; quando uma mensagem nova tem o mesmo + id de uma existente, sobrescreve; ainda + desserializa dicts em objetos de mensagem do LangChain. +

+
from langchain.messages import AnyMessage
+from langgraph.graph.message import add_messages
+from typing import Annotated
+from typing_extensions import TypedDict
+
+class GraphState(TypedDict):
+    messages: Annotated[list[AnyMessage], add_messages]
+

Atalho MessagesState

+
from langgraph.graph import MessagesState
+
+class State(MessagesState):
+    documents: list[str]   # estende com campos extras
+

Formato OpenAI

+

+ add_messages(format="langchain-openai") reformata o conteúdo em + blocos text/image_url e converte respostas de + ferramenta em ToolMessage. Requer + langchain-core >= 0.3.11. +

+
+ +
+

8. Nodes

+

+ Um nó é uma função Python cujo primeiro argumento é o estado. Argumentos + opcionais (por nome+tipo): config: RunnableConfig e + runtime: Runtime[ContextT]. +

+
from langgraph.runtime import Runtime
+from dataclasses import dataclass
+from typing_extensions import TypedDict
+from langgraph.graph import StateGraph
+
+class State(TypedDict):
+    input: str
+    results: str
+
+@dataclass
+class Context:
+    user_id: str
+
+builder = StateGraph(State)
+
+def plain_node(state: State):
+    return state
+
+def node_with_runtime(state: State, runtime: Runtime[Context]):
+    print("In node: ", runtime.context.user_id)
+    return {"results": f"Hello, {state['input']}!"}
+
+def node_with_execution_info(state: State, runtime: Runtime):
+    print("Thread:", runtime.execution_info.thread_id)
+    return {"results": f"Hello, {state['input']}!"}
+
+builder.add_node("plain_node", plain_node)
+builder.add_node("node_with_runtime", node_with_runtime)
+builder.add_node("node_with_execution_info", node_with_execution_info)
+

+ Auto-naming: builder.add_node(my_node) registra como + "my_node". +

+
+ +
+

9. Edges

+

Edges normais e condicionais

+
graph.add_edge("node_a", "node_b")
+graph.add_conditional_edges("node_a", routing_function)
+graph.add_conditional_edges("node_a", routing_function, {True: "node_b", False: "node_c"})
+graph.add_edge(START, "node_a")
+graph.add_conditional_edges(START, routing_function)
+graph.add_conditional_edges(START, routing_function, {True: "node_b", False: "node_c"})
+
+ Para cada nó, escolha um mecanismo de roteamento: edges + estáticos para roteamento fixo, ou edges condicionais / Command + para roteamento dinâmico. Nós com múltiplas saídas executam todos os + destinos em paralelo. +
+

Atalho de sequência (langgraph >= 0.2.46)

+
builder = StateGraph(State).add_sequence([step_1, step_2, step_3])
+builder.add_edge(START, "step_1")
+

Fan-out / fan-in, defer

+
builder.add_edge(START, "a")
+builder.add_edge("a", "b")
+builder.add_edge("a", "c")
+builder.add_edge("b", "d")
+builder.add_edge("c", "d")
+builder.add_edge("d", END)
+

+ Quando ramos têm comprimentos diferentes, marque o nó de junção como + deferred: +

+
builder.add_node(d, defer=True)
+
+ +
+

10. Send (map-reduce)

+

+ Send(node_name, state_dict) despacha uma cópia distinta do estado + para o nó nomeado. O uso principal é map-reduce com fan-out paralelo. +

+
from langgraph.types import Send
+
+def continue_to_jokes(state: OverallState):
+    return [Send("generate_joke", {"subject": s}) for s in state['subjects']]
+
+graph.add_conditional_edges("node_a", continue_to_jokes)
+
+ +
+

11. Command (roteamento + atualização de estado)

+

+ Command permite que um nó atualize estado e roteie + dinamicamente, tudo no retorno: +

+
from langgraph.types import Command
+from typing_extensions import Literal
+
+def my_node(state: State) -> Command[Literal["my_other_node"]]:
+    return Command(update={"foo": "bar"}, goto="my_other_node")
+
+ A anotação de retorno Command[Literal[...]] é necessária para que + o LangGraph renderize e valide o grafo. Edges estáticos continuam executando + em paralelo com o roteamento dinâmico do Command. +
+

Command.PARENT — sair de um subgraph

+
def my_node(state: State) -> Command[Literal["my_other_node"]]:
+    return Command(update={"foo": "bar"}, goto="other_subgraph", graph=Command.PARENT)
+

+ O state key do pai deve ter um reducer para que o + update seja aceito. +

+

Resume após interrupt — única forma válida como input

+
result = graph.invoke(Command(resume="yes"), config, version="v2")
+
+ +
+

12. Runtime e context

+

+ context_schema declara o contexto imutável por chamada (ex.: + user_id, conexão de DB). O contexto é injetado em runtime via + Runtime[ContextT]. +

+
from dataclasses import dataclass
+from langgraph.runtime import Runtime
+
+@dataclass
+class ContextSchema:
+    llm_provider: str = "openai"
+
+graph = StateGraph(State, context_schema=ContextSchema)
+graph.invoke(inputs, context={"llm_provider": "anthropic"})
+
+def node_a(state: State, runtime: Runtime[ContextSchema]):
+    llm = get_llm(runtime.context.llm_provider)
+

+ config_schema está depreciado desde a v0.6.0 — use + context_schema. +

+

Acessar metadados do runtime

+

+ runtime.execution_info expõe thread_id, + run_id, checkpoint_id, checkpoint_ns, + task_id, node_attempt, + node_first_attempt_time. Em LangGraph Server, + runtime.server_info traz assistant_id, + graph_id e user. +

+
+ +
+

13. Subgraphs

+

Duas estratégias de comunicação

+
+ + + + + + +
PadrãoQuando usarComo
Schemas diferentesNenhuma chave em comumFunção wrapper dentro de um nó chama subgraph.invoke({...}), traduz entrada/saída
Schema compartilhadoPai e subgraph compartilham chavesPasse o subgraph compilado diretamente para add_node
+
+

Matriz de capacidades por modo de compilação

+
+ + + + + + + + + +
FeaturePer-invocation
checkpointer=None (default)
Per-thread
checkpointer=True
Stateless
checkpointer=False
Interrupts (HITL)SimSimNão
Multi-turn memoryNãoSimNão
Múltiplos subgraphs diferentesSimLimitadoSim
Múltiplas calls do mesmo subgraphSimNãoSim
Inspeção de estadoApenas atualSimNão
+
+
+ Subgraphs per-thread não suportam chamadas paralelas (conflito de + namespace de checkpoint). Para múltiplos subagents do mesmo tipo, embrulhe + cada um em um StateGraph com nome único: +
+
def create_sub_agent(model, *, name, **kwargs):
+    agent = create_agent(model=model, name=name, **kwargs)
+    return (
+        StateGraph(MessagesState)
+        .add_node(name, agent)
+        .add_edge("__start__", name)
+        .compile()
+    )
+

Streaming dentro de subgraphs

+
for chunk in graph.stream(
+    {"foo": "foo"}, subgraphs=True, stream_mode="updates", version="v2"
+):
+    # chunk["ns"] == () para o grafo raiz;
+    # chunk["ns"] == ("node_2:<uuid>",) para um subgraph
+    print(chunk["ns"], chunk["data"])
+
+ +
+

14. Recursion limit e RemainingSteps

+

+ O limite padrão é 1000 supersteps (default desde a v1.0.6). + Ultrapassá-lo levanta GraphRecursionError. + recursion_limit é uma chave de topo em + config (não dentro de configurable): +

+
graph.invoke(inputs, config={"recursion_limit": 5}, context={"llm": "anthropic"})
+

Metadados do passo

+
from langchain_core.runnables import RunnableConfig
+
+def my_node(state: dict, config: RunnableConfig) -> dict:
+    current_step = config["metadata"]["langgraph_step"]
+    return state
+

+ Campos disponíveis: langgraph_step, langgraph_node, + langgraph_triggers, langgraph_path, + langgraph_checkpoint_ns. +

+

Alternativa proativa — RemainingSteps

+
from langgraph.managed import RemainingSteps
+from typing import Annotated, Literal
+
+class State(TypedDict):
+    messages: Annotated[list, lambda x, y: x + y]
+    remaining_steps: RemainingSteps
+
+def reasoning_node(state: State) -> dict:
+    if state["remaining_steps"] <= 2:
+        return {"messages": ["Approaching limit, wrapping up..."]}
+    return {"messages": ["thinking..."]}
+
+ + + + + + +
AbordagemQuando detectaOnde tratarFluxo
Proativa (RemainingSteps)Antes do limiteDentro do grafo, via roteamentoGrafo termina normalmente
Reativa (GraphRecursionError)Depois do limiteFora do grafo, em try/exceptExecução abortada
+
+
+ +
+

15. Cache · Retry · Timeout · Error handlers

+

Caching de nó

+
import time
+from langgraph.cache.memory import InMemoryCache
+from langgraph.types import CachePolicy
+
+def expensive_node(state: State) -> dict[str, int]:
+    time.sleep(2)
+    return {"result": state["x"] * 2}
+
+builder.add_node("expensive_node", expensive_node, cache_policy=CachePolicy(ttl=3))
+graph = builder.compile(cache=InMemoryCache())
+

+ Parâmetros de CachePolicy: key_func (default: pickle + hash do input) e ttl (segundos; sem TTL = nunca expira). Hits + aparecem em streaming com '__metadata__': {'cached': True}. +

+

Retry policy

+
from langgraph.types import RetryPolicy
+import sqlite3
+
+builder.add_node(
+    "query_database",
+    query_database,
+    retry_policy=RetryPolicy(retry_on=sqlite3.OperationalError),
+)
+builder.add_node("model", call_model, retry_policy=RetryPolicy(max_attempts=5))
+

+ O retry_on padrão exclui ValueError, + TypeError, ArithmeticError, + ImportError, LookupError, NameError, + SyntaxError, RuntimeError, + ReferenceError, StopIteration, + StopAsyncIteration, OSError. Para HTTP libs, só 5xx. +

+

Timeouts (langgraph >= 1.2)

+
from langgraph.types import TimeoutPolicy
+
+builder.add_node("call_model", call_model, timeout=1.0)
+builder.add_node(
+    "call_model_complex",
+    call_model,
+    timeout=TimeoutPolicy(run_timeout=120, idle_timeout=30),
+)
+

+ Exceder timeout levanta NodeTimeoutError (subclass de + TimeoutError). Apenas async. +

+

Error handlers

+
from langgraph.errors import NodeError
+from langgraph.types import Command, RetryPolicy
+
+def payment_error_handler(state: State, error: NodeError) -> Command:
+    return Command(
+        update={"status": f"compensated: {error.error}"},
+        goto="finalize",
+    )
+
+builder.add_node(
+    "charge_payment",
+    charge_payment,
+    retry_policy=RetryPolicy(max_attempts=3, retry_on=ConnectionError),
+    error_handler=payment_error_handler,
+)
+ +

Defaults graph-wide com set_node_defaults()

+

+ Em vez de repetir retry_policy/timeout/cache_policy/error_handler + em cada add_node(), aplique-os ao grafo inteiro com + builder.set_node_defaults(...): +

+
from langgraph.types import RetryPolicy, TimeoutPolicy
+
+builder.set_node_defaults(
+    retry_policy=RetryPolicy(max_attempts=3),
+    error_handler=default_error_handler,
+    timeout=TimeoutPolicy(run_timeout=30),
+)
+
+ Precedência: valores passados diretamente em + add_node() sempre vencem os defaults de + set_node_defaults(). Os defaults resolvem em compile-time, + então a ordem das chamadas não importa. +
+
+ O error_handler e o cache_policy default não + se aplicam aos próprios nós error-handler; já retry_policy e + timeout aplicam-se a ambos. +
+ +

Idle timeout, refresh_on e heartbeat

+

+ Além de run_timeout (limite total), o TimeoutPolicy + suporta idle_timeout (limite sem atividade). O campo + refresh_on controla o que reseta o relógio idle: +

+
from langgraph.types import TimeoutPolicy
+
+# "auto" (default): writes de estado, stream output, agendamento de child-task,
+#   chamadas do stream-writer e qualquer callback LangChain resetam o relógio idle.
+timeout = TimeoutPolicy(idle_timeout=30, refresh_on="heartbeat")
+
+# Dentro do nó — só "heartbeat" depende de chamada explícita:
+def long_node(state, runtime):
+    runtime.heartbeat()   # reseta o relógio idle; seguro chamar incondicionalmente
+    ...
+
+ + + + + + +
refresh_onReseta o relógio idle quando…
"auto" (default)Há writes de estado, stream output, agendamento de child-task, chamadas do stream-writer ou qualquer callback LangChain.
"heartbeat"Apenas via runtime.heartbeat() explícito (no-op fora de um attempt idle-timed).
+
+

+ Estourar o limite levanta NodeTimeoutError (subclass de + TimeoutError), com os campos: node: str, + elapsed: float, kind: Literal["idle", "run"], + idle_timeout: float | None, run_timeout: float | None. +

+ +

default_retry_on extensível

+

+ Para construir um retry_on= que estende a lógica padrão (em vez de + substituí-la), importe e reutilize default_retry_on dentro do seu + callable: +

+
from langgraph.types import RetryPolicy, default_retry_on
+
+def retry_on(exc: Exception) -> bool:
+    # mantém o comportamento default e adiciona um caso próprio
+    return default_retry_on(exc) or isinstance(exc, MyTransientError)
+
+builder.add_node("call_api", call_api, retry_policy=RetryPolicy(retry_on=retry_on))
+ +
+ +
+

16. Visualização

+
from IPython.display import Image, display
+
+# PNG via Mermaid.Ink (default)
+display(Image(graph.get_graph().draw_mermaid_png()))
+
+# Mermaid syntax (texto)
+print(app.get_graph().draw_mermaid())
+
+# Customizado via Pyppeteer
+from langchain_core.runnables.graph import CurveStyle, MermaidDrawMethod, NodeStyles
+
+display(Image(app.get_graph().draw_mermaid_png(
+    curve_style=CurveStyle.LINEAR,
+    node_colors=NodeStyles(first="#ffdfba", last="#baffc9", default="#fad7de"),
+    wrap_label_n_words=9,
+    output_file_path=None,
+    draw_method=MermaidDrawMethod.PYPPETEER,
+    background_color="white",
+    padding=10,
+)))
+
+# Graphviz
+display(Image(app.get_graph().draw_png()))
+

+ ASCII também está disponível via graph.get_graph().draw_ascii(). +

+
+ +
+

17. Streaming

+

+ O LangGraph oferece graph.stream(input, stream_mode=..., version="v2", + subgraphs=False, config=None) e .astream(...). No + v2, todo chunk tem o shape: +

+
StreamPart = {"type": str, "ns": tuple, "data": Any}
+

Modos disponíveis

+
+ + + + + + + + + + + +
ModoEmitePayload (chunk["data"])Requer checkpointer
valuesSnapshot completo após cada stepdict (ou modelo tipado)Não
updatesDelta retornado por nó{"node_name": {...}}Não
messagesTokens de LLM(LLM_token_chunk, metadata)Não
customDados emitidos via get_stream_writer ou writerQualquer JSONNão
checkpointsEventos de checkpointShape de get_state()Sim
tasksStart/finish/erro de tasksTask dictSim
debugcheckpoints + tasks + extraComboSim
+
+

Multi-mode

+
for chunk in graph.stream(inputs, stream_mode=["updates", "custom"], version="v2"):
+    if chunk["type"] == "updates": ...
+    elif chunk["type"] == "custom": ...
+

Emitir custom de dentro de um nó

+
from langgraph.config import get_stream_writer
+
+def node(state):
+    writer = get_stream_writer()
+    writer({"status": "thinking..."})
+    return {"answer": "x"}
+

Injeção de StreamWriter (necessário em Python < 3.11 async)

+
from langgraph.types import StreamWriter
+
+async def generate_joke(state: State, writer: StreamWriter):
+    writer({"custom_key": "..."})
+

Filtrar tokens por nó / tag

+
    +
  • metadata["langgraph_node"] — qual nó emitiu.
  • +
  • metadata["tags"] — tags do modelo (via init_chat_model(..., tags=[...])).
  • +
  • Tag ["nostream"] em um modelo exclui seus tokens do modo messages.
  • +
  • init_chat_model(..., streaming=False) ou model.disable_streaming = True.
  • +
+

v1 vs v2 — diferenças de retorno

+
+ + + + + + + +
Itemv1 (default)v2 (>= 1.1)
invoke() retornadictGraphOutput com .value, .interrupts
Payload de interruptresult["__interrupt__"]result.interrupts (tuple)
Eventos de subgraphtuplas (ns, data)StreamPart unificado
+
+ +

Event streaming (stream_events / version="v3") recomendado

+
+ API recomendada para código novo. + graph.stream_events(...) / graph.astream_events(..., version="v3") + substitui o antigo astream_events(..., version="v2") com + projeções tipadas sobre o fluxo de eventos, em vez de um dict + cru por evento. +
+
+ Não confunda esta version="v3" (específica de + stream_events/astream_events) com o version="v2" + de graph.invoke(...)/graph.stream(...), que continua + válido para GraphOutput, interrupts tipados e + resume_map (ver §19 e §18). +
+

+ O objeto retornado expõe o stream cru e várias projeções tipadas + que você itera conforme a necessidade: +

+
# Streaming de mensagens (canônico)
+stream = graph.stream_events(
+    {"messages": [{"role": "user", "content": "What is 42 * 17?"}]},
+    version="v3",
+)
+for message in stream.messages:
+    for token in message.text:
+        print(token, end="", flush=True)
+
+final_state = stream.output       # saída final (awaitable no modo async)
+
+ + + + + + + + + + + + + +
ProjeçãoEmite
streamEventos crus (iterável base).
stream.messagesMensagens/tokens do LLM (com .text, .node).
stream.valuesSnapshots completos de estado após cada step.
stream.outputSaída final do grafo (awaitable em async).
stream.subgraphsEventos originados de subgraphs.
stream.interruptsInterrupts emitidos durante o run.
stream.interruptedbool — se o run pausou em um interrupt.
stream.extensionsProjeções de transformers customizados (stream.extensions["<name>"]).
stream.tool_callsTool calls (quando um ToolCallTransformer está registrado).
+
+

Consumir múltiplas projeções em ordem de chegada

+
for name, item in stream.interleave("values", "messages", "subgraphs"):
+    if name == "values":
+        print(f"[state] keys={list(item)}")
+    elif name == "messages":
+        print(f"[llm] node={item.node}")
+

Transformers customizados (StreamTransformer)

+

+ Transformers implementam o protocolo StreamTransformer com + init(), process(event), finalize() e + fail(err), e declaram os modos Pregel de que precisam via + required_stream_modes (tupla, ex.: ("custom",)). + Projeções customizadas aparecem em stream.extensions["<name>"]. +

+
from langgraph.stream import ProtocolEvent, StreamTransformer
+
+# StreamTransformer é o protocolo (init/process/finalize/fail) implementado
+# por transformers customizados; subclasse-o ou implemente a mesma interface.
+
+class MyTransformer(StreamTransformer):
+    required_stream_modes = ("custom",)
+
+    def init(self):
+        ...
+
+    def process(self, event: ProtocolEvent) -> bool:  # retorne False só p/ suprimir o evento
+        ...
+
+    def finalize(self):
+        ...
+
+    def fail(self, err):
+        ...
+
+# Registro em call-time…
+stream = graph.stream_events(inputs, version="v3", transformers=[MyTransformer()])
+
+# …ou no compile:
+graph = builder.compile(transformers=[MyTransformer()])
+ +
+ +
+

18. Persistência (checkpointers)

+

+ Cada execução persistente é indexada por um thread_id passado em + {"configurable": {"thread_id": "<id>"}}. Mesmo + thread_id ⇒ retoma; novo ⇒ estado fresco. +

+

Catálogo de checkpointers

+
+ + + + + + + + + + + +
ClassePacoteUso
InMemorySaver / MemorySaverlanggraph-checkpoint (bundled)Dev/test; tem variante async
SqliteSaverlanggraph-checkpoint-sqliteLocal sync
AsyncSqliteSaverlanggraph-checkpoint-sqliteLocal async
PostgresSaverlanggraph-checkpoint-postgresProdução sync
AsyncPostgresSaverlanggraph-checkpoint-postgresProdução async
RedisSaver / AsyncRedisSaverlanggraph-checkpoint-redisProdução, opcional vector
CosmosDBSaver(Sync)langchain-azure-cosmosdbAzure
+
+

StateSnapshot — campos

+
+ + + + + + + + + + + +
CampoTipoSignificado
valuesdictValores dos canais
nexttuple[str, ...]Próximos nós; () = completo
configdictTem thread_id, checkpoint_ns, checkpoint_id
metadatadictsource (input/loop/update), writes, step
created_atstrISO 8601
parent_configdict\|NoneConfig do checkpoint anterior
taskstuple[PregelTask, ...]id, name, error, interrupts, state
+
+

Setup de produção com Postgres

+
from langgraph.checkpoint.postgres import PostgresSaver
+from langgraph.store.postgres import PostgresStore
+
+DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"
+
+with (
+    PostgresStore.from_conn_string(DB_URI) as store,
+    PostgresSaver.from_conn_string(DB_URI) as checkpointer,
+):
+    checkpointer.setup()       # idempotente; cria tabelas/índices
+    store.setup()
+    graph = builder.compile(checkpointer=checkpointer, store=store)
+    graph.invoke(inputs, {"configurable": {"thread_id": "1"}})
+

Async Postgres

+
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
+
+DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"
+async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
+    await checkpointer.setup()
+    graph = builder.compile(checkpointer=checkpointer)
+    async for chunk in graph.astream(
+        inputs, {"configurable": {"thread_id": "1"}}, stream_mode="values"
+    ):
+        chunk["messages"][-1].pretty_print()
+

Serialização e criptografia

+

+ O serializador padrão é JsonPlusSerializer (ormsgpack + JSON). + Pickle fallback é opt-in: +

+
from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
+
+graph.compile(
+    checkpointer=InMemorySaver(serde=JsonPlusSerializer(pickle_fallback=True))
+)
+

Criptografia AES (lê LANGGRAPH_AES_KEY):

+
from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
+from langgraph.checkpoint.postgres import PostgresSaver
+
+serde = EncryptedSerializer.from_pycryptodome_aes()
+checkpointer = PostgresSaver.from_conn_string("postgresql://...", serde=serde)
+checkpointer.setup()
+

Custom: implemente CipherProtocol em langgraph.checkpoint.serde.base.

+

Pending writes — recuperação parcial de super-step

+

+ Quando vários nós executam no mesmo super-step e um deles falha, o + checkpointer guarda as writes intermediárias dos nós que já + concluíram (via .put_writes). No resume, esses nós + não reexecutam — apenas o que faltou roda de novo. Essas + writes aparecem como pending_writes no snapshot, permitindo + inspecionar o progresso parcial antes da retomada. +

+
snapshot = graph.get_state(config)
+print(snapshot.tasks)            # tasks pendentes do super-step
+# writes intermediárias persistidas ficam disponíveis como pending_writes
+# e são reaplicadas no resume sem reexecutar os nós já concluídos.
+ +
+ +
+

19. Human-in-the-loop

+

+ interrupt(value) (de langgraph.types) pausa a + execução, persiste o estado, surface o value ao chamador e + aguarda indefinidamente o Command(resume=...). Requer + checkpointer e thread_id. +

+
from langgraph.types import Command, interrupt
+from langgraph.checkpoint.memory import InMemorySaver
+

Gotchas críticos

+
    +
  1. Não envelope interrupt() em try/except Exception + — ele levanta uma exceção especial usada para pausar.
  2. +
  3. A reentrada é indexada por posição: nunca reordene ou + pule condicionalmente chamadas a interrupt() dentro de um nó.
  4. +
  5. Passe apenas valores JSON-serializáveis para interrupt() — + funções e instâncias de classes não.
  6. +
  7. Side effects antes de interrupt() reexecutam no resume — + torne-os idempotentes (upserts, não inserts).
  8. +
  9. Subgraphs chamados como funções: o nó pai e o nó do subgraph reiniciam + do começo no resume.
  10. +
+

Receita 1 — aprovar antes de chamar

+
from typing import Literal, Optional, TypedDict
+from langgraph.checkpoint.memory import InMemorySaver
+from langgraph.graph import END, START, StateGraph
+from langgraph.types import Command, interrupt
+
+class ApprovalState(TypedDict):
+    action_details: str
+    status: Optional[Literal["pending", "approved", "rejected"]]
+
+def approval_node(state: ApprovalState) -> Command[Literal["proceed", "cancel"]]:
+    decision = interrupt({"question": "Approve this action?", "details": state["action_details"]})
+    return Command(goto="proceed" if decision else "cancel")
+
+def proceed_node(state): return {"status": "approved"}
+def cancel_node(state):  return {"status": "rejected"}
+
+builder = StateGraph(ApprovalState)
+builder.add_node("approval", approval_node)
+builder.add_node("proceed", proceed_node)
+builder.add_node("cancel", cancel_node)
+builder.add_edge(START, "approval")
+builder.add_edge("proceed", END)
+builder.add_edge("cancel", END)
+graph = builder.compile(checkpointer=InMemorySaver())
+
+config = {"configurable": {"thread_id": "approval-123"}}
+initial = graph.invoke({"action_details": "Transfer $500", "status": "pending"},
+                       config=config, version="v2")
+print(initial.interrupts)
+resumed = graph.invoke(Command(resume=True), config=config, version="v2")
+print(resumed.value["status"])
+

Receita 2 — editar estado

+
def review_node(state):
+    edited = interrupt({"instruction": "Review and edit", "content": state["generated_text"]})
+    return {"generated_text": edited}
+
+graph.invoke(Command(resume="Improved draft"), config=config, version="v2")
+

Receita 3 — revisar tool call

+
from langchain.tools import tool
+from langgraph.types import interrupt
+
+@tool
+def send_email(to: str, subject: str, body: str):
+    """Send an email to a recipient."""
+    response = interrupt({
+        "action": "send_email", "to": to, "subject": subject, "body": body,
+        "message": "Approve sending this email?",
+    })
+    if response.get("action") == "approve":
+        return f"Email sent to {response.get('to', to)} subj '{response.get('subject', subject)}'"
+    return "Email cancelled by user"
+
+graph.invoke(
+    Command(resume={"action": "approve", "subject": "Updated"}),
+    config=config, version="v2"
+)
+

Receita 4 — validar input humano (loop)

+
def get_age_node(state):
+    prompt = "What is your age?"
+    while True:
+        answer = interrupt(prompt)
+        if isinstance(answer, int) and answer > 0:
+            return {"age": answer}
+        prompt = f"'{answer}' is not a valid age. Please enter a positive number."
+

Static interrupts (apenas debug)

+
graph = builder.compile(interrupt_before=["node_a"], interrupt_after=["node_b"],
+                        checkpointer=cp)
+# ou em runtime
+graph.invoke(inputs, interrupt_before=["node_a"], interrupt_after=["node_b"], config=cfg)
+graph.invoke(None, config=cfg)  # resume até o próximo breakpoint
+

Resumir múltiplos interrupts paralelos com resume_map

+

+ Quando vários nós em paralelo (ex.: fan-out via Send) chamam + interrupt() no mesmo super-step, o resume precisa endereçar cada um + pelo seu id. Em vez de um único Command(resume=valor), + passe um mapa {interrupt_id: valor}. Isto exige o + fluxo tipado de version="v2" (ver §17 e §18): +

+
from langgraph.types import Command
+
+interrupted = graph.invoke({"vals": []}, config, version="v2")
+resume_map = {i.id: f"answer for {i.value}" for i in interrupted.interrupts}
+result = graph.invoke(Command(resume=resume_map), config, version="v2")
+ +
+ +
+

20. Memória curta e longa (Store)

+

+ Curta (short-term) = escopo de thread, persistida pelo + checkpointer (histórico de conversa, arquivos enviados, docs recuperados, + artefatos gerados). Longa (long-term) = cross-thread, com + escopo de namespace, acessada via BaseStore. +

+

Taxonomia de memória

+
+ + + + + + + +
TipoArmazenaPadrão
SemânticaFatosProfile (1 JSON único, regenerado) ou Collection (muitos docs estreitos)
EpisódicaExperiências passadasFew-shot examples no Store ou em LangSmith Dataset
ProceduralRegras/instruçõesSystem prompt versionado persistido no Store
+
+

CRUD do Store

+
from langgraph.store.memory import InMemoryStore
+from langgraph.store.postgres import PostgresStore
+
+store = InMemoryStore()
+store.put(namespace, key, value)
+store.get(namespace, key)            # retorna Item ou None
+store.search(namespace, filter=..., query=..., limit=..., offset=...)
+store.delete(namespace, key)
+store.list_namespaces(prefix=..., max_depth=...)
+
+ Ordenação: PostgresStore / + AsyncPostgresStore ordenam por updated_at desc; + InMemoryStore respeita a ordem de inserção. Ordene no cliente + quando precisar de garantia. +
+

Busca semântica

+
from langchain.embeddings import init_embeddings
+from langgraph.store.memory import InMemoryStore
+
+store = InMemoryStore(index={
+    "embed": init_embeddings("openai:text-embedding-3-small"),
+    "dims": 1536,
+    "fields": ["food_preference", "$"],  # "$" = doc inteiro
+})
+store.put(ns, key,  {"food_preference": "I love Italian"}, index=["food_preference"])
+store.put(ns, key2, {"system_info": "..."},                index=False)
+memories = store.search(ns, query="What does the user like?", limit=3)
+

Acessar Store de dentro de um nó

+
from langgraph.runtime import Runtime
+from dataclasses import dataclass
+import uuid
+
+@dataclass
+class Context:
+    user_id: str
+
+async def update_memory(state, runtime: Runtime[Context]):
+    namespace = (runtime.context.user_id, "memories")
+    await runtime.store.aput(
+        namespace, str(uuid.uuid4()),
+        {"memory": "User prefers concise replies"}
+    )
+

Stores de produção

+

+ Além do PostgresStore / AsyncPostgresStore, há backends + de produção mantidos para MongoDB e Redis. Todos estendem BaseStore; + o InMemoryStore serve apenas para dev/teste. +

+
+ + + + + + + + +
StoreImportUso
PostgresStore / AsyncPostgresStorefrom langgraph.store.postgres import PostgresStoreProdução; ordena search por updated_at desc.
MongoDBStorefrom langgraph.store.mongodb import MongoDBStoreProdução sobre MongoDB.
RedisStore / AsyncRedisStorefrom langgraph.store.redis import RedisStoreProdução sobre Redis (RedisStack para vetor).
InMemoryStorefrom langgraph.store.memory import InMemoryStoreApenas dev/teste.
+
+
+ +
+

21. Time travel — replay e fork

+
+ + + + + + + +
APIO que faz
graph.get_state(config, subgraphs=False)Último StateSnapshot (ou específico via checkpoint_id no config)
graph.get_state_history(config)Iterador reverso de StateSnapshot
graph.update_state(config, values, as_node=None)Cria um novo checkpoint partindo de config
+
+

Replay

+
history = list(graph.get_state_history(config))
+before_joke = next(s for s in history if s.next == ("write_joke",))
+replay_result = graph.invoke(None, before_joke.config)
+

+ No replay, apenas nós após o checkpoint reexecutam. Chamadas a LLM, + APIs e interrupt() disparam de novo. +

+

Fork

+
fork_config = graph.update_state(
+    before_joke.config,
+    values={"topic": "chickens"},
+    as_node="generate_topic",
+)
+fork_result = graph.invoke(None, fork_config)
+

+ as_node é explícito quando: há ramos paralelos, em thread sem + histórico, ou quando você quer que o grafo "ache" que um nó posterior já + rodou. +

+

Subgraphs e time travel

+
    +
  • Default (checkpointer herdado): subgraph é um único super-step do ponto + de vista do pai; não dá pra viajar entre nós internos.
  • +
  • compile(checkpointer=True) no subgraph: checkpoints por step + internamente; acesso via + graph.get_state(config, subgraphs=True).tasks[0].state.config.
  • +
+
+ +
+

22. Durable execution & drain

+

+ Durable execution requer: (a) checkpointer, (b) thread_id, (c) + side effects envolvidos em @task. Modos: +

+
+ + + + + + + +
Modo (durability=)PersisteTrade-off
"exit"Apenas no exit (sucesso, erro, interrupt)Melhor performance; sem recovery no meio
"async"Assíncrono enquanto o próximo step rodaBalanceado; pequena janela de risco
"sync"Síncrono antes do próximo step começarMáxima durabilidade; overhead
+
+

Onde o resume começa

+
+ + + + + + + +
APIResume retoma em
Nó de StateGraphInício do nó onde parou
Subgraph chamado dentro de um nóInício do nó pai + início do nó do subgraph
Functional APIInício do entrypoint (resultados de @task são recarregados, não reexecutados)
+
+

Graceful shutdown (langgraph >= 1.2)

+
import signal
+from langgraph.runtime import RunControl
+from langgraph.errors import GraphDrained
+
+control = RunControl()
+signal.signal(signal.SIGTERM, lambda *_: control.request_drain("sigterm"))
+
+try:
+    result = graph.invoke(inputs, config, control=control)
+except GraphDrained as e:
+    log.info("drained: %s", e.reason)
+
+# Reiniciar em outro processo:
+result = graph.invoke(None, config)
+

Dentro de um nó:

+
from langgraph.runtime import Runtime
+
+async def my_node(state, runtime: Runtime):
+    if runtime.drain_requested:
+        return {"status": "skipped", "reason": runtime.drain_reason}
+    return {"status": await do_work()}
+

+ request_drain() não cancela tasks assíncronas nem mata threads — + deixa o nó atual terminar; políticas de retry rodam até esgotar; se há mais + supersteps, levanta GraphDrained e o checkpoint é salvo. +

+
+ +
+

23. Functional API

+
from langgraph.func import entrypoint, task
+

+ @entrypoint(checkpointer=..., store=...) decora uma função com + UM argumento posicional (use um dict para vários). Retorna um + Pregel com .invoke/.ainvoke/ + .stream/.astream. Inputs e outputs devem ser + JSON-serializáveis. +

+

Parâmetros injetáveis (por nome+tipo)

+
+ + + + + + + + +
NomeTipoPropósito
previousAnyValor de retorno do checkpoint anterior (ou entrypoint.final.save)
storeBaseStoreStore de longo prazo
writerStreamWriterStreaming custom (necessário em Python < 3.11 async)
configRunnableConfigConfig de runtime
+
+

Memória curta via previous

+
@entrypoint(checkpointer=cp)
+def workflow(number: int, *, previous=None) -> int:
+    previous = previous or 0
+    return number + previous
+

entrypoint.final — desacoplar retorno do que persiste

+
@entrypoint(checkpointer=cp)
+def workflow(number, *, previous=None) -> entrypoint.final[int, int]:
+    previous = previous or 0
+    return entrypoint.final(value=previous, save=2 * number)
+

@task — unidade de trabalho com checkpoint

+
from typing import NotRequired
+from typing_extensions import TypedDict
+from langchain_core.utils.uuid import uuid7
+from langgraph.checkpoint.memory import InMemorySaver
+from langgraph.func import task
+from langgraph.graph import StateGraph, START, END
+import requests
+
+class State(TypedDict):
+    urls: list[str]
+    result: NotRequired[list[str]]
+
+@task
+def _make_request(url: str):
+    return requests.get(url).text[:100]
+
+def call_api(state: State):
+    futures = [_make_request(url) for url in state['urls']]
+    results = [f.result() for f in futures]
+    return {"results": results}
+
+builder = StateGraph(State)
+builder.add_node("call_api", call_api)
+builder.add_edge(START, "call_api")
+builder.add_edge("call_api", END)
+
+checkpointer = InMemorySaver()
+graph = builder.compile(checkpointer=checkpointer)
+
+thread_id = str(uuid7())
+config = {"configurable": {"thread_id": thread_id}}
+graph.invoke({"urls": ["https://www.example.com"]}, config)
+

+ @task só pode ser chamada de dentro de + @entrypoint, de outra @task, ou de um nó de grafo. + Outputs precisam ser JSON-serializáveis. No resume, o resultado persistido é + recarregado — não recomputado. +

+
+ +
+

24. Multi-agent (supervisor & swarm)

+

+ LangGraph oferece dois pacotes prebuilt — langgraph-supervisor e + langgraph-swarm — além do primitivo + Command(goto=..., graph=Command.PARENT, update=...) que viabiliza + qualquer padrão custom. +

+

Padrões

+
+ + + + + + + + + +
PadrãoResumo
SupervisorLLM central roteia para subagents especializados via tool calls
SwarmPeer-to-peer; agents transferem controle entre si; sistema lembra o último active agent
NetworkComunicação many-to-many
HierarchicalSupervisores aninhados (multi-team)
Custom workflowStateGraph manual com handoffs via Command
+
+

Handoff tool via Command (padrão canônico)

+
from typing import Annotated
+from langchain_core.tools import tool, InjectedToolCallId
+from langchain_core.messages import ToolMessage
+from langgraph.types import Command
+from langgraph.prebuilt import InjectedState
+
+@tool("transfer_to_bob", description="Hand off to Bob")
+def transfer_to_bob(
+    task_description: Annotated[str, "What Bob should do"],
+    state: Annotated[dict, InjectedState],
+    tool_call_id: Annotated[str, InjectedToolCallId],
+):
+    msg = ToolMessage(content="Transferred to Bob", name="transfer_to_bob",
+                      tool_call_id=tool_call_id)
+    return Command(
+        goto="Bob",
+        graph=Command.PARENT,
+        update={"messages": state["messages"] + [msg], "active_agent": "Bob"},
+    )
+

Supervisor

+
pip install langgraph-supervisor
+
from langchain_openai import ChatOpenAI
+from langgraph_supervisor import create_supervisor, create_handoff_tool
+from langgraph.prebuilt import create_react_agent
+from langgraph.checkpoint.memory import InMemorySaver
+
+model = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
+
+def add(a: float, b: float) -> float: return a + b
+def web_search(q: str) -> str: return "..."
+
+math_agent = create_react_agent(model=model, tools=[add],
+                                name="math_expert", prompt="You are a math expert.")
+research_agent = create_react_agent(model=model, tools=[web_search],
+                                    name="research_expert",
+                                    prompt="You are a world-class researcher.")
+
+workflow = create_supervisor(
+    [research_agent, math_agent],
+    model=model,
+    prompt="You are a team supervisor managing a research expert and a math expert.",
+    tools=[
+        create_handoff_tool(agent_name="math_expert",
+                            name="assign_to_math_expert",
+                            description="Assign task to math expert"),
+        create_handoff_tool(agent_name="research_expert",
+                            name="assign_to_research_expert",
+                            description="Assign task to research expert"),
+    ],
+    output_mode="last_message",
+)
+
+app = workflow.compile(checkpointer=InMemorySaver())
+result = app.invoke({"messages": [{"role": "user", "content": "..."}]},
+                    config={"configurable": {"thread_id": "1"}})
+

+ output_mode: + "full_history" (anexa todas as mensagens do subagent) ou + "last_message" (anexa apenas a resposta final). + Helpers extras: create_forward_message_tool, + METADATA_KEY_HANDOFF_DESTINATION em + langgraph_supervisor.handoff. +

+

Swarm

+
pip install langgraph-swarm
+
from langchain_openai import ChatOpenAI
+from langgraph.checkpoint.memory import InMemorySaver
+from langgraph_swarm import create_handoff_tool, create_swarm
+from langgraph.prebuilt import create_react_agent
+
+model = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
+def add(a: int, b: int) -> int: return a + b
+
+alice = create_react_agent(
+    model,
+    tools=[add, create_handoff_tool(agent_name="Bob", description="Transfer to Bob")],
+    prompt="You are Alice, an addition expert.",
+    name="Alice",
+)
+bob = create_react_agent(
+    model,
+    tools=[create_handoff_tool(agent_name="Alice", description="Transfer to Alice for math")],
+    prompt="You are Bob, you speak like a pirate.",
+    name="Bob",
+)
+
+workflow = create_swarm([alice, bob], default_active_agent="Alice")
+app = workflow.compile(checkpointer=InMemorySaver())
+
+config = {"configurable": {"thread_id": "1"}}
+app.invoke({"messages": [{"role": "user", "content": "I want to talk to Bob"}]}, config)
+app.invoke({"messages": [{"role": "user", "content": "What's 2+2?"}]}, config)
+# Bob devolve para Alice via handoff tool
+
+ Sem checkpointer, o swarm esquece o agent ativo entre invocações — sempre + passe checkpointer= no compile(). +
+
+ +
+

25. Padrões de workflow

+

+ A página workflows-agents documenta seis arquiteturas canônicas + construídas em LangGraph puro. +

+

1. Prompt chaining

+
from typing_extensions import TypedDict
+from langgraph.graph import StateGraph, START, END
+
+class State(TypedDict):
+    topic: str
+    joke: str
+    improved_joke: str
+    final_joke: str
+
+def generate_joke(state: State):
+    msg = llm.invoke(f"Write a short joke about {state['topic']}")
+    return {"joke": msg.content}
+
+def check_punchline(state: State):
+    return "Pass" if "?" in state["joke"] or "!" in state["joke"] else "Fail"
+
+def improve_joke(state: State):
+    msg = llm.invoke(f"Make this joke funnier by adding wordplay: {state['joke']}")
+    return {"improved_joke": msg.content}
+
+def polish_joke(state: State):
+    msg = llm.invoke(f"Add a surprising twist to this joke: {state['improved_joke']}")
+    return {"final_joke": msg.content}
+
+workflow = StateGraph(State)
+workflow.add_node("generate_joke", generate_joke)
+workflow.add_node("improve_joke", improve_joke)
+workflow.add_node("polish_joke", polish_joke)
+workflow.add_edge(START, "generate_joke")
+workflow.add_conditional_edges("generate_joke", check_punchline,
+                               {"Fail": "improve_joke", "Pass": END})
+workflow.add_edge("improve_joke", "polish_joke")
+workflow.add_edge("polish_joke", END)
+chain = workflow.compile()
+state = chain.invoke({"topic": "cats"})
+

2. Parallelization

+
parallel_builder = StateGraph(State)
+parallel_builder.add_node("call_llm_1", call_llm_1)
+parallel_builder.add_node("call_llm_2", call_llm_2)
+parallel_builder.add_node("call_llm_3", call_llm_3)
+parallel_builder.add_node("aggregator", aggregator)
+parallel_builder.add_edge(START, "call_llm_1")
+parallel_builder.add_edge(START, "call_llm_2")
+parallel_builder.add_edge(START, "call_llm_3")
+parallel_builder.add_edge("call_llm_1", "aggregator")
+parallel_builder.add_edge("call_llm_2", "aggregator")
+parallel_builder.add_edge("call_llm_3", "aggregator")
+parallel_builder.add_edge("aggregator", END)
+

3. Routing (com structured output)

+
from typing_extensions import Literal
+from langchain.messages import HumanMessage, SystemMessage
+from pydantic import BaseModel, Field
+
+class Route(BaseModel):
+    step: Literal["poem", "story", "joke"] = Field(None,
+        description="The next step in the routing process")
+
+router = llm.with_structured_output(Route)
+
+def llm_call_router(state: State):
+    decision = router.invoke([
+        SystemMessage(content="Route the input to story, joke, or poem based on the user's request."),
+        HumanMessage(content=state["input"]),
+    ])
+    return {"decision": decision.step}
+
+def route_decision(state: State):
+    return {"story": "llm_call_1", "joke": "llm_call_2", "poem": "llm_call_3"}[state["decision"]]
+
+router_builder = StateGraph(State)
+router_builder.add_node("llm_call_1", llm_call_1)
+router_builder.add_node("llm_call_2", llm_call_2)
+router_builder.add_node("llm_call_3", llm_call_3)
+router_builder.add_node("llm_call_router", llm_call_router)
+router_builder.add_edge(START, "llm_call_router")
+router_builder.add_conditional_edges("llm_call_router", route_decision,
+    {"llm_call_1": "llm_call_1", "llm_call_2": "llm_call_2", "llm_call_3": "llm_call_3"})
+router_builder.add_edge("llm_call_1", END)
+router_builder.add_edge("llm_call_2", END)
+router_builder.add_edge("llm_call_3", END)
+

4. Orchestrator-worker (Send)

+
from typing import Annotated, List
+import operator
+from langgraph.types import Send
+
+class Section(BaseModel):
+    name: str = Field(description="Name for this section of the report.")
+    description: str = Field(description="Brief overview of the section.")
+
+class Sections(BaseModel):
+    sections: List[Section] = Field(description="Sections of the report.")
+
+planner = llm.with_structured_output(Sections)
+
+class State(TypedDict):
+    topic: str
+    sections: list[Section]
+    completed_sections: Annotated[list, operator.add]
+    final_report: str
+
+class WorkerState(TypedDict):
+    section: Section
+    completed_sections: Annotated[list, operator.add]
+
+def orchestrator(state: State):
+    report_sections = planner.invoke([
+        SystemMessage(content="Generate a plan for the report."),
+        HumanMessage(content=f"Here is the report topic: {state['topic']}"),
+    ])
+    return {"sections": report_sections.sections}
+
+def llm_call(state: WorkerState):
+    section = llm.invoke([
+        SystemMessage(content="Write a report section..."),
+        HumanMessage(content=f"name: {state['section'].name}, description: {state['section'].description}"),
+    ])
+    return {"completed_sections": [section.content]}
+
+def synthesizer(state: State):
+    return {"final_report": "\n\n---\n\n".join(state["completed_sections"])}
+
+def assign_workers(state: State):
+    return [Send("llm_call", {"section": s}) for s in state["sections"]]
+
+builder = StateGraph(State)
+builder.add_node("orchestrator", orchestrator)
+builder.add_node("llm_call", llm_call)
+builder.add_node("synthesizer", synthesizer)
+builder.add_edge(START, "orchestrator")
+builder.add_conditional_edges("orchestrator", assign_workers, ["llm_call"])
+builder.add_edge("llm_call", "synthesizer")
+builder.add_edge("synthesizer", END)
+orchestrator_worker = builder.compile()
+

5. Evaluator-optimizer (loop com feedback)

+
class Feedback(BaseModel):
+    grade: Literal["funny", "not funny"] = Field(description="Decide if the joke is funny.")
+    feedback: str = Field(description="Feedback on how to improve.")
+
+evaluator = llm.with_structured_output(Feedback)
+
+def llm_call_generator(state: State):
+    if state.get("feedback"):
+        msg = llm.invoke(f"Write a joke about {state['topic']} considering feedback: {state['feedback']}")
+    else:
+        msg = llm.invoke(f"Write a joke about {state['topic']}")
+    return {"joke": msg.content}
+
+def llm_call_evaluator(state: State):
+    grade = evaluator.invoke(f"Grade the joke {state['joke']}")
+    return {"funny_or_not": grade.grade, "feedback": grade.feedback}
+
+def route_joke(state: State):
+    return "Accepted" if state["funny_or_not"] == "funny" else "Rejected + Feedback"
+
+builder = StateGraph(State)
+builder.add_node("llm_call_generator", llm_call_generator)
+builder.add_node("llm_call_evaluator", llm_call_evaluator)
+builder.add_edge(START, "llm_call_generator")
+builder.add_edge("llm_call_generator", "llm_call_evaluator")
+builder.add_conditional_edges("llm_call_evaluator", route_joke,
+    {"Accepted": END, "Rejected + Feedback": "llm_call_generator"})
+optimizer_workflow = builder.compile()
+

6. Agente ReAct manual

+
from langgraph.graph import MessagesState
+from langchain.messages import SystemMessage, HumanMessage, ToolMessage
+
+def llm_call(state: MessagesState):
+    return {"messages": [llm_with_tools.invoke(
+        [SystemMessage(content="You are a helpful assistant for arithmetic.")]
+        + state["messages"]
+    )]}
+
+def tool_node(state: dict):
+    result = []
+    for tool_call in state["messages"][-1].tool_calls:
+        tool = tools_by_name[tool_call["name"]]
+        observation = tool.invoke(tool_call["args"])
+        result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
+    return {"messages": result}
+
+def should_continue(state: MessagesState) -> Literal["tool_node", END]:
+    last_message = state["messages"][-1]
+    return "tool_node" if last_message.tool_calls else END
+
+agent_builder = StateGraph(MessagesState)
+agent_builder.add_node("llm_call", llm_call)
+agent_builder.add_node("tool_node", tool_node)
+agent_builder.add_edge(START, "llm_call")
+agent_builder.add_conditional_edges("llm_call", should_continue, ["tool_node", END])
+agent_builder.add_edge("tool_node", "llm_call")
+agent = agent_builder.compile()
+ +
+ +
+

26. Migrações de grafo (com checkpointer)

+
+ + + + + + + + + + +
CenárioSuportado
Threads no fim do grafo — mudanças totais de topologiaSim
Threads interrompidas — adicionar/modificar nósSim
Threads interrompidas — renomear/remover nósContate o time
Adicionar/remover chaves de estadoSim (forwards/backwards compat)
Renomear chavesNão (perde estado salvo)
Mudanças incompatíveis de tipoPode causar problemas
+
+ +

Deprecations do LangGraph v1

+

+ O LangGraph v1 deprecou os prebuilts agênticos em favor de + langchain.agents. Os símbolos abaixo continuam funcionando (com + aviso @deprecated), mas código novo deve usar as alternativas: +

+
+ + + + + + + + + + + + + +
DeprecadoAlternativa
create_react_agent (langgraph.prebuilt)from langchain.agents import create_agent — use system_prompt=, não prompt=
MessageGraphStateGraph com a chave messages (como create_agent provê)
ValidationNodeRemovido — tools validam o input automaticamente com create_agent
AgentStatelangchain.agents.AgentState
AgentStatePydanticlangchain.agents.AgentState (sem estado Pydantic)
AgentStateWithStructuredResponselangchain.agents.AgentState
HumanInterruptlangchain.agents.middleware.human_in_the_loop.HITLRequest
HumanInterruptConfiglangchain.agents.middleware.human_in_the_loop.InterruptOnConfig
ActionRequestlangchain.agents.middleware.human_in_the_loop.InterruptOnConfig
+
+
# v1 (novo)
+from langchain.agents import create_agent
+agent = create_agent(model, tools, system_prompt="You are a helpful assistant.")
+
+# v0 (antigo, deprecado)
+from langgraph.prebuilt import create_react_agent
+agent = create_react_agent(model, tools, prompt="You are a helpful assistant.")
+
+ Breaking change: o suporte a Python 3.9 foi removido — todos os + pacotes LangChain agora exigem Python 3.10+ (Python 3.9 chegou + ao fim de vida em out/2025). +
+
+ create_supervisor / create_swarm vêm dos pacotes + separados langgraph-supervisor / + langgraph-swarm e ainda podem usar create_react_agent + internamente. Verifique a versão do pacote antes de trocar cegamente — a + deprecação v1 acima é especificamente sobre + langgraph.prebuilt.create_react_agent. +
+ +
+ +
+

Parte B — Referência de API

+

Referência das classes públicas relevantes do LangGraph e dos pacotes prebuilt. Cada entrada inclui import, assinatura e atributos principais.

+
+ +
+

StateGraph

+
from langgraph.graph import StateGraph
+
+StateGraph(
+    state_schema: type[StateT],
+    context_schema: type[ContextT] | None = None,
+    *,
+    input_schema: type[InputT] | None = None,
+    output_schema: type[OutputT] | None = None,
+)
+
+ + + + + + + + +
ParâmetroTipoDefaultDescrição
state_schematype[StateT]obrigatórioSchema do estado (TypedDict/dataclass/Pydantic)
context_schematype[ContextT] \| NoneNoneSchema de runtime context (substitui o depreciado config_schema)
input_schematype[InputT] \| NoneNoneSchema de entrada
output_schematype[OutputT] \| NoneNoneSchema de saída
+
+

Métodos principais

+
add_node(node, name=None, *, retry_policy=None, cache_policy=None, timeout=None, defer=False, error_handler=None, metadata=None) +
+

Registra um nó. Sem name, usa o nome da função. retry_policy, cache_policy, timeout, defer e error_handler são opcionais e independentes.

+
+
add_edge(start_key, end_key) +

Edge estático.

+
add_conditional_edges(source, path, path_map=None) +

Roteamento dinâmico. path é uma função que recebe o estado e devolve um nome de nó, lista, ou lista de Send; path_map traduz retornos para nomes.

+
add_sequence(nodes) >= 0.2.46 +

Atalho que registra os nós e conecta sequencialmente.

+
set_entry_point(node) · set_finish_point(node) · set_conditional_entry_point(path, path_map=None) +

Açúcar para add_edge(START, node) / add_edge(node, END).

+
compile(checkpointer=None, store=None, cache=None, interrupt_before=None, interrupt_after=None, debug=False, name=None) +
+

Retorna um CompiledStateGraph com invoke, ainvoke, stream, astream, get_state, get_state_history, update_state, get_graph.

+

checkpointer=None usa o do pai (em subgraph) ou nenhum; checkpointer=True habilita per-thread state em subgraph; checkpointer=False torna o subgraph stateless.

+
+
+ +
+

START · END

+
from langgraph.graph import START, END
+

Sentinelas usados em add_edge(START, "node") e add_edge("node", END) ou em maps de edges condicionais.

+
+ +
+

MessagesState

+
from langgraph.graph import MessagesState
+
+class MessagesState(TypedDict):
+    messages: Annotated[list[AnyMessage], add_messages]
+

Extenda subclassando — campos extras coexistem com messages.

+
+ +
+

add_messages

+
from langgraph.graph.message import add_messages
+
+add_messages(
+    left: Messages,
+    right: Messages,
+    *,
+    format: Literal['langchain-openai'] | None = None,
+) -> Messages
+

Reducer canônico para listas de mensagens: append-only com overwrite por id. format="langchain-openai" reescreve content em blocos text/image_url (requer langchain-core >= 0.3.11).

+
+ +
+

Send

+
from langgraph.types import Send
+
+Send(node: str, arg: Any, *, timeout: float | timedelta | TimeoutPolicy | None = None)
+

Retornada (em lista) por uma função de edge condicional para fan-out paralelo com estado distinto por destino.

+
+ +
+

Command

+
from langgraph.types import Command
+
+Command(
+    *,
+    graph: str | None = None,
+    update: Any | None = None,
+    resume: dict | Any | None = None,
+    goto: Send | Sequence[Send | str] | str = (),
+)
+
+ + + + + + + + +
ParamTipoDefaultDescrição
graphstr \| NoneNoneGrafo alvo; None = atual, Command.PARENT = pai mais próximo
updateAny \| NoneNoneAtualização de estado
resumedict \| Any \| NoneNoneValor para retomar após interrupt()
gotostr \| Send \| Sequence()Próximo(s) nó(s)
+
+

Constante: Command.PARENT — referência para o grafo pai imediato.

+
+ +
+

Overwrite

+
from langgraph.types import Overwrite
+
+Overwrite(value: Any)
+

Bypassa o reducer e escreve o valor literalmente. Forma JSON: {"__overwrite__": value}. Múltiplos Overwrite para a mesma chave em um super-step ⇒ InvalidUpdateError.

+
+ +
+

Runtime

+
from langgraph.runtime import Runtime
+
+Runtime(
+    *,
+    context: ContextT = None,
+    store: BaseStore | None = None,
+    stream_writer: StreamWriter = _no_op_stream_writer,
+    heartbeat: Callable[[], None] = _no_op_heartbeat,
+    previous: Any = None,
+    execution_info: ExecutionInfo | None = None,
+    server_info: ServerInfo | None = None,
+    control: RunControl | None = None,
+)
+

Atributos

+
+ + + + + + + + + + + + + +
AtributoDescrição
contextInstância de context_schema
storeBaseStore long-term
stream_writerFunção para emitir custom events
previousRetorno do checkpoint anterior (Functional API)
execution_infoExecutionInfo: thread_id, run_id, checkpoint_id, checkpoint_ns, task_id, node_attempt, node_first_attempt_time
server_infoServerInfo: assistant_id, graph_id, user (None fora do LangGraph Server)
controlRunControl da invocação atual
drain_requestedbool — true quando request_drain foi chamado
drain_reasonstr — motivo
+
+

Adicionado em v0.6.0. ToolRuntime (em langgraph.prebuilt) é subclasse que adiciona config, state, tool_call_id.

+
+ +
+

RunControl

+
from langgraph.runtime import RunControl
+

Métodos: request_drain(reason: str) dispara drenagem cooperativa no próximo boundary de super-step. Não cancela tasks assíncronas. Adicionado em langgraph >= 1.2.

+
+ +
+

RetryPolicy · TimeoutPolicy · CachePolicy

+
from langgraph.types import RetryPolicy, TimeoutPolicy, CachePolicy
+
RetryPolicy(initial_interval=0.5, backoff_factor=2.0, max_interval=128.0, max_attempts=3, jitter=True, retry_on=...) +
+

retry_on: callable ou tupla de tipos. Defaults excluem ValueError, TypeError, ArithmeticError, ImportError, LookupError, NameError, SyntaxError, RuntimeError, ReferenceError, StopIteration, StopAsyncIteration, OSError. HTTP libs só retentam 5xx.

+
+
TimeoutPolicy(run_timeout=..., idle_timeout=...) >= 1.2 +
+

run_timeout = limite total; idle_timeout = limite sem atividade. Apenas em runtime async. Estourar levanta NodeTimeoutError.

+
+
CachePolicy(key_func=None, ttl=None) +

key_func: callable que produz a chave (default: pickle hash do input). ttl em segundos; sem TTL = nunca expira. Combinada com cache=InMemoryCache() ou SqliteCache em compile.

+
+ +
+

RemainingSteps

+
from langgraph.managed import RemainingSteps
+

Managed value type para uma chave do estado. O runtime injeta automaticamente o orçamento restante de supersteps, permitindo encerrar antes de bater no recursion_limit.

+
+ +
+

interrupt

+
from langgraph.types import interrupt
+
+interrupt(value: JSONLike) -> Any
+

Pausa o nó, persiste o estado e devolve o valor passado em Command(resume=...) no resume. Requer checkpointer + thread_id. Payload precisa ser JSON-serializável.

+
+ +
+

entrypoint · task

+
from langgraph.func import entrypoint, task
+
+@entrypoint(checkpointer=..., store=...)
+def workflow(input, *, previous=None, store=None, writer=None, config=None):
+    ...
+
+@task
+def my_task(...):
+    ...
+
+# entrypoint.final[ReturnT, SaveT]
+def workflow(...) -> entrypoint.final[int, int]:
+    return entrypoint.final(value=..., save=...)
+

Decoradores da Functional API. @entrypoint retorna um Pregel; @task retorna future via .result() ou await; resultados são checkpointed e recarregados no resume.

+
+ +
+

Stream parts

+
from langgraph.types import (
+    StreamPart, ValuesStreamPart, UpdatesStreamPart, MessagesStreamPart,
+    CustomStreamPart, CheckpointStreamPart, TasksStreamPart, DebugStreamPart,
+)
+

Tipos do payload v2 — todos no formato {"type": str, "ns": tuple, "data": Any}.

+
+ +
+

StreamWriter · get_stream_writer

+
from langgraph.types import StreamWriter
+from langgraph.config import get_stream_writer
+
+def node(state):
+    writer = get_stream_writer()
+    writer({"phase": "starting"})
+
+async def node_async(state, writer: StreamWriter):  # < Python 3.11
+    writer({"phase": "starting"})
+
+ +
+

BaseCheckpointSaver

+
from langgraph.checkpoint.base import BaseCheckpointSaver
+

Classe-base para checkpointers customizados.

+

Métodos obrigatórios

+
+ + + + + + + + + +
MétodoPropósito
put(config, checkpoint, metadata, new_versions)Armazena um checkpoint
put_writes(config, writes, task_id)Armazena writes pendentes do super-step atual
get_tuple(config) -> CheckpointTupleBusca por thread_id/checkpoint_id
list(config, filter=..., before=..., limit=...)Itera checkpoints
aput, aput_writes, aget_tuple, alistContrapartes async
+
+
+ +
+

InMemorySaver

+
from langgraph.checkpoint.memory import InMemorySaver, MemorySaver
+
+InMemorySaver(serde=None)
+

Para dev/test. serde opcional permite trocar o serializador (ex.: JsonPlusSerializer(pickle_fallback=True)). MemorySaver é alias comum.

+
+ +
+

SqliteSaver · AsyncSqliteSaver

+
from langgraph.checkpoint.sqlite import SqliteSaver
+from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
+
+SqliteSaver.from_conn_string(":memory:")
+# ou
+import sqlite3
+SqliteSaver(sqlite3.connect("file.db"))
+
+# Async
+async with AsyncSqliteSaver.from_conn_string("file.db") as cp:
+    ...
+
+ +
+

PostgresSaver · AsyncPostgresSaver

+
from langgraph.checkpoint.postgres import PostgresSaver
+from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
+
+with PostgresSaver.from_conn_string(uri) as cp:
+    cp.setup()
+    graph = builder.compile(checkpointer=cp)
+
+async with AsyncPostgresSaver.from_conn_string(uri) as cp:
+    await cp.setup()
+    graph = builder.compile(checkpointer=cp)
+

.setup() é idempotente — cria tabelas e índices.

+
+ +
+

RedisSaver · AsyncRedisSaver

+
from langgraph.checkpoint.redis import RedisSaver
+from langgraph.checkpoint.redis.aio import AsyncRedisSaver
+
+cp = RedisSaver.from_conn_string("redis://localhost:6379")
+cp.setup()
+
+async_cp = AsyncRedisSaver.from_conn_string("redis://localhost:6379")
+await async_cp.asetup()
+

Mantido pela community (redis-developer/langgraph-redis). Opcional: indexação vetorial via RedisStack.

+
+ +
+

Serializadores

+
from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
+from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
+from langgraph.checkpoint.serde.base import CipherProtocol
+
+# Pickle fallback opt-in
+JsonPlusSerializer(pickle_fallback=True)
+
+# AES via pycryptodome (lê LANGGRAPH_AES_KEY)
+serde = EncryptedSerializer.from_pycryptodome_aes()
+

O serializador padrão é JsonPlusSerializer (ormsgpack + JSON).

+
+ +
+

BaseStore

+
from langgraph.store.base import BaseStore
+

Interface abstrata. Item tem value, key, namespace, created_at, updated_at.

+

CRUD

+
put(namespace, key, value, *, index=None) +

Cria/atualiza item. index=False desliga embedding; index=["campo"] aplica apenas a campos selecionados.

+
get(namespace, key) -> Item | None

Recupera por chave exata.

+
search(namespace, *, filter=None, query=None, limit=10, offset=0) +

Filtros estruturados e/ou busca semântica. query exige índice de embeddings configurado.

+
delete(namespace, key)

Remove o item.

+
list_namespaces(prefix=None, max_depth=None)

Itera namespaces conhecidos.

+

Versões async: aput, aget, asearch, adelete, alist_namespaces.

+
+ +
+

InMemoryStore

+
from langgraph.store.memory import InMemoryStore
+from langgraph.store.base import IndexConfig
+
+InMemoryStore(index=IndexConfig(embed=embed_fn, dims=1536, fields=["$"]))
+

Para dev/test e cenários em que a memória do processo é suficiente. Não há ordenação implícita por updated_at.

+
+ +
+

PostgresStore

+
from langgraph.store.postgres import PostgresStore
+
+with PostgresStore.from_conn_string(uri) as store:
+    store.setup()
+    # store.put(...), store.search(..., query="...", limit=3)
+

Ordena search por updated_at desc. Há também AsyncPostgresStore em langgraph.store.postgres.aio.

+
+ +
+

create_react_agent (legado) deprecated

+
from langgraph.prebuilt import create_react_agent
+
+def create_react_agent(
+    model: str | LanguageModelLike | Callable[..., BaseChatModel],
+    tools: Sequence[BaseTool | Callable | dict[str, Any]] | ToolNode,
+    *,
+    prompt: Prompt | None = None,
+    response_format: StructuredResponseSchema | tuple[str, StructuredResponseSchema] | None = None,
+    pre_model_hook: RunnableLike | None = None,
+    post_model_hook: RunnableLike | None = None,
+    state_schema: StateSchemaType | None = None,
+    context_schema: type[Any] | None = None,
+    checkpointer: Checkpointer | None = None,
+    store: BaseStore | None = None,
+    interrupt_before: list[str] | None = None,
+    interrupt_after: list[str] | None = None,
+    debug: bool = False,
+    version: Literal["v1", "v2"] = "v2",
+    name: str | None = None,
+) -> CompiledStateGraph
+

+ Função decorada como @deprecated — direciona usuários a + langchain.agents.create_agent (que delega para o LangGraph). + Constrói um agente que chama tools em loop até atingir o stopping condition. +

+
+ Note a mudança de assinatura: create_agent usa + system_prompt= em vez de prompt=. Veja a + tabela completa de deprecations v1 (§26). +
+

+ Quando remaining_steps < 2 e há tool calls, devolve + "Sorry, need more steps to process this request." em vez de + levantar GraphRecursionError. +

+

Versões v1 vs v2

+
+ + + + + + +
VersãoDiferença
v1Processa uma mensagem por vez
v2 (default)Distribui tool calls via Send API (paralelo)
+
+
+ +
+

ToolNode · tools_condition

+
from langchain.tools import tool
+from langgraph.prebuilt import ToolNode, tools_condition
+from langgraph.graph import MessagesState, StateGraph
+
+@tool
+def search(query: str) -> str:
+    """Search for information."""
+    return f"Results for: {query}"
+
+@tool
+def calculator(expression: str) -> str:
+    """Evaluate a math expression."""
+    return str(eval(expression))
+
+builder = StateGraph(MessagesState)
+builder.add_node("tools", ToolNode([search, calculator]))
+# ... tools_condition decide entre "tools" e END
+graph = builder.compile()
+

+ ToolNode executa tool calls em paralelo, lida com erros e + injeção de estado (InjectedState, InjectedToolCallId, + InjectedStore). Atributo público: tools_by_name. +

+

+ tools_condition(state) inspeciona a última mensagem; se tem + tool_calls, retorna "tools"; caso contrário, + END. +

+
+ +
+

langgraph-supervisor

+
from langgraph_supervisor import (
+    create_supervisor, create_handoff_tool,
+)
+from langgraph_supervisor.handoff import (
+    create_forward_message_tool, METADATA_KEY_HANDOFF_DESTINATION,
+)
+

create_supervisor

+
create_supervisor(
+    agents: list,
+    model: BaseChatModel,
+    prompt: str = None,
+    output_mode: Literal["full_history", "last_message"] = "full_history",
+    tools: list = None,
+    add_handoff_messages: bool = True,
+    handoff_tool_prefix: str = "transfer_to",
+    supervisor_name: str = "supervisor",
+) -> StateGraph
+

create_handoff_tool

+
create_handoff_tool(agent_name: str, name: str | None = None, description: str | None = None)
+
+ +
+

langgraph-swarm

+
from langgraph_swarm import (
+    create_swarm, create_handoff_tool, add_active_agent_router,
+)
+

create_swarm

+
create_swarm(
+    agents: list,
+    default_active_agent: str,
+) -> StateGraph
+

add_active_agent_router

+
add_active_agent_router(builder, route_to: list[str], default_active_agent: str)
+

Para builds manuais que querem a mesma semântica de "último agent" do swarm.

+
+ +
+

Exceções

+
from langgraph.errors import (
+    GraphRecursionError, InvalidUpdateError, NodeInterrupt,
+    GraphInterrupt, NodeError, NodeTimeoutError, GraphDrained,
+    GraphBubbleUp, ParentCommand, EmptyInputError, TaskNotFound, ErrorCode,
+)
+
+ + + + + + + + + + + + + +
ExceçãoHerdaSignificado
GraphRecursionErrorRecursionErrorExcedeu recursion_limit (default 1000)
InvalidUpdateErrorExceptionUpdate inválido em um canal (ex.: múltiplos Overwrite)
NodeInterrupt(value, id=None)GraphInterruptDepreciado — use langgraph.types.interrupt
GraphInterrupt—Base de exceções de interrupt
NodeError—Passado ao error_handler após retries esgotarem
NodeTimeoutErrorTimeoutErrorEstourou timeout/TimeoutPolicy (1.2+)
GraphDrained—Levantada após RunControl.request_drain() (1.2+). Tem .reason
EmptyInputError—Input vazio quando não permitido
TaskNotFound—Functional API: task referenciada não existe
+
+
+ +
+

Parte C — Plataforma LangGraph

+

A camada Platform entrega tudo o que está fora do runtime in-process: servidor HTTP com REST + SSE, persistência durável em Postgres, fila por thread, autenticação plugável, Studio, CLI de build/deploy, SDK Python/JS, e integrações (A2A, MCP, RemoteGraph). Esta parte cobre a superfície completa.

+
+ Quando usar a plataforma. O StateGraph compilado roda bem em qualquer processo Python. A camada Platform é necessária quando você precisa de: 1) execução background com retomada após desconexão, 2) threads persistentes acessíveis por múltiplos clientes, 3) Crons, 4) Auth multi-tenant centralizada, 5) Studio (debug/replay/fork), 6) deploy gerenciado. +
+
+ +
+

27. Visão geral e arquitetura

+

O Agent Server é uma aplicação ASGI (FastAPI/Starlette) que expõe seus grafos via REST + SSE. Ele orquestra runs com a garantia de "no máximo 1 run ativo por thread", persiste estado em Postgres via PostgresSaver, faz fan-out de streaming via Redis pubsub e enfileira tarefas para os workers.

+
┌───────────────────────────────────────────────────────────────┐
+│  Clientes (langgraph_sdk, REST, Studio, browser SSE)          │
+└──────────────────┬────────────────────────────────────────────┘
+                   │ HTTPS  (X-Api-Key  /  custom auth)
+┌──────────────────▼────────────────────────────────────────────┐
+│  API Server  (FastAPI/Starlette ASGI)                          │
+│   • REST: /threads /runs /assistants /crons /store             │
+│   • SSE streaming  /stream                                     │
+│   • Auth hooks  (@auth.authenticate, @auth.on...)              │
+└──────────────────┬───────────────────────────┬─────────────────┘
+                   │ enqueue                   │ pubsub
+                   ▼                           ▼
+            ┌─────────────┐            ┌────────────────┐
+            │ Postgres    │            │ Redis pubsub   │
+            │ checkpoints,│◀──ckpt─────│ event bus,     │
+            │ assistants, │            │ stream fanout  │
+            │ threads,    │            └────────────────┘
+            │ runs, crons,│
+            │ store       │
+            └─────▲───────┘
+                  │ lease
+        ┌─────────┴────────────┐
+        │ Queue Workers        │  1 run/thread, N_JOBS_PER_WORKER concorrentes
+        │ (graph executors)    │
+        └──────────────────────┘
+
+ + + + + + + + +
ComponentePapelSubstituível?
API ServerHTTP+SSE, auth, validação de payloadNão (parte do pacote langgraph-api)
PostgresCheckpoints, assistants, threads, runs, crons, storeSim (qualquer Postgres ≥ 14)
RedisPubsub para fan-out de streaming; sem persistênciaSim (qualquer Redis ≥ 6)
WorkersExecutam grafos; cada thread vira 1 worker dedicadoSim (escala horizontal independente)
+
+

Variáveis-chave (self-hosted Standalone): DATABASE_URI, REDIS_URI, LANGGRAPH_CLOUD_LICENSE_KEY (Enterprise). Em modos avançados, queue.enabled: true separa workers dedicados, e o distributed runtime ainda divide API e execução em frota distinta.

+
+ +
+

28. CLI langgraph

+

Instale com:

+
pip install -U "langgraph-cli[inmem]"
+

Todos os comandos leem ./langgraph.json por padrão. Cinco subcomandos cobrem o ciclo completo: dev, build, up, deploy, dockerfile.

+ +

28.1 langgraph dev — servidor local in-memory

+

Dev server leve com hot-reload e estado pickleado em disco — sem Docker.

+
+ + + + + + + + + + + + + + +
FlagDefaultFunção
-c, --config FILElanggraph.jsonCaminho do config
--host TEXT127.0.0.1Bind host
--port INTEGER2024Porta
--no-reloadoffDesliga auto-reload
--n-jobs-per-worker10Runs concorrentes por worker
--debug-port INTEGER—Porta do depurador DAP
--wait-for-clientoffPausa até o depurador conectar
--no-browseroffNão abre Studio automaticamente
--studio-url TEXThttps://smith.langchain.comURL do Studio
--allow-blockingoffSuprime warnings de I/O síncrono
--tunneloffExpõe via Cloudflare tunnel público
+
langgraph dev --port 2024 --no-browser --debug-port 5678
+ +

28.2 langgraph build — imagem Docker

+
langgraph build -t myorg/my-agent:1.0 --platform linux/amd64,linux/arm64
+
+ + + + + + + + +
FlagDefaultFunção
-t, --tag TEXTobrigatórioTag da imagem
--platform TEXThostLista de plataformas alvo
--pull / --no-pull--pullPull da base
--build-command TEXT—JS: comando de build (ex.: yarn run turbo build)
--install-command TEXT—JS: comando de install
+ +

28.3 langgraph up — stack Docker local

+

Sobe API + Postgres + Redis localmente. Compose-style.

+
langgraph up -p 8123 --watch --postgres-uri "postgres://..." --debugger-port 5678
+
+ + + + + + + + + + + + + + + +
FlagDefaultFunção
-p, --port INTEGER8123Porta de host para API
--waitoffEspera healthy (implica --detach)
--watchoffRestart on file change
--base-image TEXTlangchain/langgraph-apiImagem base
--image TEXT—Pré-built; pula o build
--postgres-uri TEXTcontainer internoPostgres externo
-d, --docker-compose FILE—Compose extra para serviços auxiliares
--debugger-port INTEGER—Porta do depurador
--debugger-base-url TEXThttp://127.0.0.1:[PORT]URL pública do depurador
--recreate / --no-recreate--no-recreateForça recriação
--pull / --no-pull--pullPull de imagens
--verboseoffLog estendido
+ +

28.4 langgraph deploy — push para LangSmith

+
langgraph deploy --name my-agent --deployment-type prod --api-key $LANGSMITH_API_KEY
+
+ + + + + + + + + + +
FlagDefaultFunção
--api-key TEXTenvLangSmith API key
--name TEXTcwdNome do deployment
--deployment-id TEXT—Atualiza deployment existente
--deployment-type TEXTdevdev ou prod
--remote / --no-remoteautoForçar build remoto/local
--no-waitoffPula polling pós-push
--verboseoffMostra build/Docker
+

Subcomandos: langgraph deploy list, ... revisions list ID, ... delete ID, ... logs [-f] [-q TEXT] [--type deploy|build] [--deployment-id ID | --name NAME].

+ +

28.5 langgraph dockerfile — gera Dockerfile

+
langgraph dockerfile ./Dockerfile -c langgraph.json
+

Re-execute sempre que langgraph.json mudar — o arquivo não é regenerado automaticamente.

+ +
+ JS/TS: npm create langgraph config escaneia createAgent(), StateGraph.compile() e workflow.compile() e gera langgraph.json. O CLI também expõe langgraph new para scaffold de projetos. +
+
+ +
+

29. langgraph.json — schema completo

+

Schema JSON em https://langgra.ph/schema.json. Use no header:

+
{
+  "$schema": "https://langgra.ph/schema.json",
+  ...
+}
+
+ + + + + + + + + + + + + + + + + + +
CampoTipoDefaultFunção
dependenciesstring[]obrigatórioCaminhos locais (".", "./pkg") + pacotes PyPI/npm
graphs{ name: "path:variable" }obrigatórioMap de IDs de grafo → grafo compilado ou factory function
envstring | object—Caminho do .env ou {KEY: value} inline
python_versionstring"3.11"3.11/3.12/3.13
node_versionstring"20"Versão de Node para projetos JS
pip_config_filestring—Caminho de pip.conf
dockerfile_linesstring[][]Linhas extras anexadas ao Dockerfile
image_distro"debian" | "wolfi" | "bookworm" | "bullseye""debian"Wolfi = menor e mais seguro · CLI ≥ 0.2.11
auth{ path, openapi?, disable_studio_auth? }—Módulo de auth
httpobject (abaixo)—Liga/desliga grupos de rotas built-in
store{ index?, ttl? }—Configura store; index ativa busca semântica
checkpointer{ ttl? }—TTL/retenção dos checkpoints
ui{ name: "path" }—Componentes Generative UI
webhooks{ headers?, url?, env_prefix? }—Política de webhooks de saída
keep_pkg_toolsbool | string[]falseMantém build tools na imagem (deps nativas em runtime)
+ +

Sub-schema http

+

Booleanos para desabilitar grupos: disable_meta, disable_assistants, disable_runs, disable_threads, disable_store, disable_ui, disable_webhooks. /ok liveness fica disponível mesmo com disable_meta: true.

+ +

Sub-schema store.index — busca semântica

+
"store": {
+  "index": {
+    "embed": "openai:text-embedding-3-small",
+    "dims": 1536,
+    "fields": ["$"]
+  }
+}
+ +

Exemplo completo

+
{
+  "$schema": "https://langgra.ph/schema.json",
+  "python_version": "3.12",
+  "image_distro": "wolfi",
+  "dependencies": [".", "langchain_openai", "tavily-python"],
+  "graphs": {
+    "agent": "./src/agent.py:graph",
+    "research": "./src/research.py:make_graph"
+  },
+  "env": "./.env",
+  "auth": {
+    "path": "./src/auth.py:auth",
+    "disable_studio_auth": false
+  },
+  "store": {
+    "index": {
+      "embed": "openai:text-embedding-3-small",
+      "dims": 1536,
+      "fields": ["$"]
+    },
+    "ttl": { "default_ttl": 60, "refresh_on_read": true }
+  },
+  "checkpointer": { "ttl": { "default_ttl": 30, "strategy": "delete" } },
+  "http": { "disable_ui": false, "disable_webhooks": false },
+  "webhooks": {
+    "url": { "allowed_domains": ["*.mycompany.com"], "require_https": true },
+    "headers": { "Authorization": "Bearer ${{ env.LG_WEBHOOK_TOKEN }}" }
+  },
+  "dockerfile_lines": ["RUN apt-get update && apt-get install -y libpq-dev"]
+}
+
+ +
+

30. Threads · Assistants · Runs · Crons

+
+ + + + + + + + + +
ConceitoIdentidadeSignificado
Graphnome em langgraph.jsonBlueprint de código (ex.: ./agent.py:graph)
AssistantUUIDGraph + snapshot de configuração (modelo, prompt, tools); versionado a cada update
ThreadUUIDContainer persistente que segura os checkpoints (estado)
RunUUIDExecução de (assistant_id, thread_id, input); 1 ativo por thread
CronUUIDRun agendado (5-field cron em UTC)
StorenamespaceMemória longa BaseStore-backed, opcional busca semântica
+ +

30.1 Thread — schema

+
+ + + + + + + + + +
CampoTipoNotas
thread_idUUIDPK
created_at / updated_atISO timestamp—
metadataobjectFiltrável: graph_id, assistant_id, langgraph_auth_user_id, cron_id...
statusenumidle | busy | interrupted | error
configobject{ configurable: {...} }
valuesobjectSnapshot atual do estado
+ +

30.2 Status de Run

+

pending · running · success · error · interrupted · timeout. multitask_strategy default em uma thread é "reject" (background) ou "enqueue" dependendo do path do SDK.

+ +

30.3 Grupos de endpoints REST

+
+ Assistants +
    +
  • POST /assistants · GET /assistants/{id} · PATCH /assistants/{id} · DELETE /assistants/{id}
  • +
  • POST /assistants/search · GET /assistants/{id}/versions
  • +
+
+
+ Threads +
    +
  • POST /threads · GET /threads/{id} · PATCH /threads/{id} · DELETE /threads/{id}
  • +
  • POST /threads/search · POST /threads/{id}/copy
  • +
  • GET /threads/{id}/state · POST /threads/{id}/state (update_state) · GET /threads/{id}/history
  • +
+
+
+ Runs em uma thread +
    +
  • POST /threads/{tid}/runs · POST /threads/{tid}/runs/stream · POST /threads/{tid}/runs/wait
  • +
  • GET /threads/{tid}/runs · GET /threads/{tid}/runs/{rid}
  • +
  • POST /threads/{tid}/runs/{rid}/cancel
  • +
  • GET /threads/{tid}/runs/{rid}/join · GET /threads/{tid}/runs/{rid}/stream (join_stream)
  • +
  • GET /threads/{tid}/stream (stream da thread inteira, atravessa runs)
  • +
+
+
+ Stateless runs +
  • POST /runs · POST /runs/stream · POST /runs/wait
+
+
+ Crons +
    +
  • POST /runs/crons · POST /threads/{tid}/runs/crons
  • +
  • POST /runs/crons/search · DELETE /runs/crons/{cid}
  • +
+
+
+ Store +
    +
  • PUT /store/items · GET /store/items · DELETE /store/items
  • +
  • POST /store/items/search · POST /store/namespaces
  • +
+
+ +

30.4 Cron expressions

+

5-field POSIX cron m h dom mon dow, sempre em UTC.

+
+ + + + + + +
ExpressãoSignificado
"*/5 * * * *"A cada 5 minutos
"0 9 * * 1-5"Dias úteis, 09:00 UTC
"27 15 * * *"Diariamente, 15:27 UTC
+

on_run_completed="delete" (default) deleta a thread após cada run stateless do cron; "keep" retém.

+
+ +
+

31. SDK Python (langgraph_sdk)

+

Cliente HTTP+SSE oficial; síncrono ou assíncrono.

+
from langgraph_sdk import get_client, get_sync_client
+
+client = get_client(url="https://my-deployment.langgraph.app", api_key=API_KEY)
+ +

31.1 Threads

+
await client.threads.create(metadata={"user_id": "u1"}, if_exists="raise")
+await client.threads.get(thread_id)
+await client.threads.update(thread_id, metadata={...})
+await client.threads.delete(thread_id)
+await client.threads.search(metadata={"graph_id": "agent"}, limit=20, offset=0)
+await client.threads.copy(thread_id)
+
+# Time travel
+await client.threads.get_state(thread_id, checkpoint={"checkpoint_id": "..."})
+await client.threads.update_state(thread_id, values={...}, as_node="my_node")
+await client.threads.get_history(thread_id, limit=10, before=...)
+ +

31.2 Runs

+
await client.runs.create(
+    thread_id, assistant_id, input=...,
+    config=..., metadata=...,
+    multitask_strategy="enqueue",        # reject | interrupt | rollback
+    webhook="https://...",
+    on_disconnect="cancel",              # ou "continue" (default)
+    after_seconds=0,
+)
+
+async for chunk in client.runs.stream(
+    thread_id, assistant_id, input=...,
+    stream_mode="updates",               # ou ["updates","messages-tuple"] ...
+    stream_subgraphs=False,
+):
+    print(chunk.event, chunk.data)
+
+await client.runs.wait(thread_id, assistant_id, input=...)   # bloqueante
+await client.runs.get(thread_id, run_id)
+await client.runs.list(thread_id)
+await client.runs.cancel(thread_id, run_id, wait=False, action="interrupt")  # ou "rollback"
+await client.runs.join(thread_id, run_id)
+async for c in client.runs.join_stream(thread_id, run_id): ...
+ +

31.3 Assistants

+
await client.assistants.create(
+    graph_id="agent",
+    config={"configurable": {"model_name": "openai"}},
+    metadata={"team": "support"},
+    if_exists="raise",
+)
+await client.assistants.get(assistant_id)
+await client.assistants.update(assistant_id, config=..., metadata=...)
+await client.assistants.delete(assistant_id)
+await client.assistants.search(metadata={"team": "support"}, limit=20)
+await client.assistants.get_versions(assistant_id)
+ +

31.4 Crons

+
await client.crons.create(
+    assistant_id,
+    schedule="27 15 * * *",
+    input=...,
+    on_run_completed="delete",           # ou "keep"
+)
+await client.crons.create_for_thread(thread_id, assistant_id, schedule="0 9 * * 1", input=...)
+await client.crons.search(assistant_id=..., limit=20)
+await client.crons.delete(cron_id)
+ +

31.5 Store (memória longa)

+
await client.store.put_item(namespace=("users", user_id), key="profile", value={...})
+await client.store.get_item(namespace=("users", user_id), key="profile")
+await client.store.search_items(
+    namespace_prefix=("users", user_id),
+    query="prefers vegetarian",
+    limit=10,
+)
+await client.store.delete_item(namespace=("users", user_id), key="profile")
+await client.store.list_namespaces(prefix=("users",), limit=100)
+ +

31.6 Dois assistants em uma thread

+
thread = await client.threads.create()
+
+# Pergunta para o OpenAI
+async for ev in client.runs.stream(
+    thread["thread_id"], openai_assistant["assistant_id"],
+    input={"messages":[{"role":"user","content":"who made you?"}]},
+    stream_mode="updates",
+):
+    print(ev.data)
+
+# Continua a conversa, agora com o Anthropic — mesma thread, contexto preservado
+async for ev in client.runs.stream(
+    thread["thread_id"], anthropic_assistant["assistant_id"],
+    input={"messages":[{"role":"user","content":"and you?"}]},
+    stream_mode="updates",
+):
+    print(ev.data)
+
+ +
+

32. Streaming, join e retomada (Platform)

+

Além dos modos do runtime (values, updates, messages-tuple, debug, custom, events), a Platform adiciona thread streams de longa duração e retomada via SSE Last-Event-ID.

+ +

32.1 Stream em background — join_stream

+

Conecta-se a um run que já está executando. Eventos antes do join não são reproduzidos.

+
async for chunk in client.runs.join_stream(thread_id, run_id):
+    print(chunk)
+ +

32.2 Thread stream — atravessa runs

+

Canal de eventos por thread, persiste enquanto a thread existir.

+
async for chunk in client.threads.join_stream(
+    thread_id,
+    stream_mode=["run_modes", "lifecycle", "state_update"],
+):
+    print(chunk.event, chunk.data)
+ +

32.3 Retomada com last_event_id

+
async for chunk in client.threads.join_stream(
+    thread_id,
+    last_event_id="<id do último chunk recebido>",
+):
+    ...
+

last_event_id="-" reproduz do começo. Em HTTP cru, o mesmo é feito via header Last-Event-ID.

+ +

32.4 Política on_disconnect

+
+ + + + + +
ValorComportamento
"continue" (default)Run continua mesmo se o cliente SSE desconectar
"cancel"Run termina se o cliente SSE sair
+
+ +
+

33. Autenticação personalizada (@auth)

+

Duas fases em cada request: 1) Autenticação (@auth.authenticate devolve o usuário), 2) Autorização (handler mais específico decide; retorna None/True = permite, False = 403, ou um dict filtro restringindo metadata).

+ +
"auth": { "path": "./auth.py:auth", "disable_studio_auth": false }
+ +

33.1 @auth.authenticate

+

Aceita qualquer subconjunto de: request, body, path, method, path_params, query_params, headers, authorization.

+
from langgraph_sdk import Auth
+auth = Auth()
+
+@auth.authenticate
+async def authenticate(authorization: str | None, headers: dict) -> Auth.types.MinimalUserDict:
+    if not authorization or not authorization.startswith("Bearer "):
+        raise Auth.exceptions.HTTPException(status_code=401, detail="Missing token")
+    token = authorization.removeprefix("Bearer ")
+    user = await verify_jwt(token)
+    return {
+        "identity": user["sub"],                       # obrigatório
+        "is_authenticated": True,
+        "permissions": user.get("permissions", []),
+        "display_name": user.get("name"),
+        "org_id": user.get("org_id"),                  # campo custom
+    }
+ +

33.2 Hierarquia de autorização

+

Recursos: threads · assistants · crons · store. Verbos: create · read · update · delete · search (e threads.create_run). Fallback global: @auth.on.

+
@auth.on
+async def reject_unmatched(ctx, value):
+    raise Auth.exceptions.HTTPException(403, detail="Forbidden")
+
+@auth.on.threads.create
+async def on_thread_create(ctx, value: Auth.types.ThreadsCreate):
+    md = value.setdefault("metadata", {})
+    md["owner"] = ctx.user.identity
+    return {"owner": ctx.user.identity}            # filtra leituras futuras
+
+@auth.on.threads.read
+async def on_thread_read(ctx, value):
+    return {"owner": ctx.user.identity}
+
+@auth.on.threads.create_run
+async def on_run_create(ctx, value):
+    value.setdefault("metadata", {})["owner"] = ctx.user.identity
+    return {"owner": ctx.user.identity}
+
+@auth.on.assistants.create
+async def on_assistant_create(ctx, value):
+    if "assistants:create" not in ctx.permissions:
+        raise Auth.exceptions.HTTPException(403, "Missing assistants:create")
+    value.setdefault("metadata", {})["owner"] = ctx.user.identity
+    return {"owner": ctx.user.identity}
+
+@auth.on.store
+async def on_store(ctx, value):
+    # Namespace do store deve começar com o próprio identity
+    if value["namespace"][0] != ctx.user.identity:
+        raise Auth.exceptions.HTTPException(403, "Cross-user store access denied")
+    return True
+ +

33.3 Dialeto de filtros

+
{"owner": user_id}                              # match exato
+{"owner": {"$eq": user_id}}
+{"allowed_users": {"$contains": user_id}}       # lista contém
+{"owner": org_id, "allowed_users": {"$contains": user_id}}   # AND
+ +

AuthContext expõe ctx.user.identity, ctx.user.is_authenticated, ctx.permissions, ctx.path, além de campos custom retornados em authenticate. Dentro de um nó, o usuário aparece em config["configurable"]["langgraph_auth_user"].

+ +
+ Bypass do Studio. Requests do Studio carregam um header especial — handlers podem deixar desenvolvedores passarem irrestritamente. Para forçar auth também no Studio, ative "disable_studio_auth": true. +
+
+ +
+

34. Double-texting (4 estratégias)

+

Quando uma nova mensagem chega numa thread cujo run anterior ainda está rodando, a estratégia multitask_strategy decide o destino do novo run.

+
+ + + + + + + +
EstratégiaComportamentoQuando usar
enqueueNovo run entra na fila, executa após o atualChat onde ordem importa
rejectNovo run rejeitado com HTTP 409Operações caras e não-duplicáveis
interruptRun atual interrompe; novo começa do checkpoint construído até aquiAgente em tempo real — trabalho intermediário é descartável
rollbackRun atual é cancelado e suas escritas são revertidas; novo run começa do estado pré-runReinício totalmente limpo
+ +
# Enqueue
+await client.runs.create(thread_id, aid, input=msg1, multitask_strategy="enqueue")
+await client.runs.create(thread_id, aid, input=msg2, multitask_strategy="enqueue")
+
+# Reject (409 se há run em andamento)
+await client.runs.create(thread_id, aid, input=msg, multitask_strategy="reject")
+
+# Interrupt (preserva progresso parcial; cuidado com tool calls em andamento)
+await client.runs.create(thread_id, aid, input=msg, multitask_strategy="interrupt")
+
+# Rollback (descarta progresso do run atual)
+await client.runs.create(thread_id, aid, input=msg, multitask_strategy="rollback")
+ +
+ Em interrupt, o estado refletirá tudo que foi checkpointado até a interrupção — seus nós devem ser projetados para serem retomáveis em qualquer ponto, inclusive no meio de tool calls. +
+
+ +
+

35. Webhooks

+

Webhooks disparam quando um run alcança status terminal. São aceitos como parâmetro webhook em runs.create, runs.stream, runs.wait e crons.create.

+
await client.runs.stream(
+    thread_id, assistant_id, input=msg,
+    stream_mode="events",
+    webhook="https://my-server.app/hook?token=SECRET",
+)
+ +

35.1 Payload (objeto Run)

+
{
+  "run_id": "1ef6a5b8-...",
+  "thread_id": "5d7a-...",
+  "assistant_id": "agent",
+  "status": "success",
+  "values": { "messages": [{"role":"assistant","content":"Hi"}] },
+  "kwargs": { "input": {...}, "config": {...} },
+  "webhook_sent_at": "2026-05-24T15:01:23Z",
+  "error": null
+}
+

Em falha, error = {"error": "TimeoutError", "message": "Run exceeded max time"}.

+ +

35.2 Segurança

+

Não há HMAC nativo. Duas opções suportadas:

+
    +
  1. Token na query string: https://my-server/hook?token=$SECRET e validação no servidor.
  2. +
  3. Headers estáticos (requer langgraph-api ≥ 0.5.36) declarados em langgraph.json:
  4. +
+
"webhooks": {
+  "headers": { "Authorization": "Bearer ${{ env.LG_WEBHOOK_TOKEN }}" },
+  "url": { "allowed_domains": ["*.mycompany.com"], "require_https": true },
+  "env_prefix": "LG_WEBHOOK_"
+}
+

Só variáveis de ambiente que casam com env_prefix são interpoláveis (default LG_WEBHOOK_). Para desligar webhooks: "http": { "disable_webhooks": true } (langgraph-api ≥ 0.2.78).

+ +
+ Não há política documentada de retry. Trate a entrega como at-most-once; se precisar de garantia, reconcilie via client.runs.get(thread_id, run_id). +
+
+ +
+

36. LangGraph Studio

+

Studio é a aplicação web em smith.langchain.com que conecta a um servidor LangGraph (local ou deployment) para visualizar grafos, percorrer threads, editar estado, refazer steps e iterar prompts.

+ +

36.1 Dois modos de execução

+
+ + + + + +
ModoComo conectarAuth
Locallanggraph dev em :2024; Studio aponta para localhostHandlers recebem contexto Studio-tagged (a menos que disable_studio_auth: true)
CloudLangSmith Deployment publicado via langgraph deployAuth normal; 1-click deploy a partir do Studio é suportado
+ +

36.2 Dois modos de UI

+
    +
  • Graph mode — grafo completo, inspeção de estado, tool calls, datasets, playground.
  • +
  • Chat mode — UI simplificada; exige estado compatível com MessagesState.
  • +
+ +

36.3 Capacidades-chave

+
    +
  • Time travel: slider através do histórico de checkpoints da thread; inspecione qualquer um.
  • +
  • Editar estado em um nó (ícone de lápis) → Fork cria nova branch a partir do checkpoint com a edição.
  • +
  • Re-run from here: repete sem editar estado (útil para trocar assistant ou versão de modelo).
  • +
  • Interrupt coloca breakpoint pré/pós-nó; Continue retoma.
  • +
  • Experiments: roda eval contra datasets direto na UI.
  • +
  • Long-term memory: navega/edita namespaces do Store.
  • +
+
+ +
+

37. Opções de deployment

+
+ + + + + + + +
OpçãoControl planeData planeInfraPlano
CloudLangChainLangChain (AWS/GCP)GerenciadoPlus+
HybridLangChainCliente (K8s)K8s + listenerEnterprise
Self-Hosted Full PlatformClienteClienteK8s + LangSmith self-hosted + CRD langgraphPlatformEnterprise
Self-Hosted Standalone Server—ClienteDocker / Compose / K8sEnterprise
+

Para Standalone, as 3 variáveis decisivas são DATABASE_URI (Postgres), REDIS_URI (Redis) e LANGGRAPH_CLOUD_LICENSE_KEY. Tiers opcionais: queue.enabled: true dedica hosts para workers; o distributed runtime separa orquestração da execução.

+
+ +
+

Parte D — Receituário de padrões

+

Catorze padrões canônicos da documentação oficial LangGraph, condensados em ~30 linhas cada. Os nomes de classes/funções batem com os notebooks oficiais em github.com/langchain-ai/langgraph/tree/main/examples.

+
+ A tabela abaixo resume quando aplicar cada padrão. +
+
+ + + + + + + + + + + + + + + + + +
PadrãoBom paraCusto (calls LLM)
ReAct estruturadoOutput schema garantidobaixo
Plan-and-executeTarefas longas com passos discretosmédio
ReflectionQualidade de escrita/código2–4× ReAct
ReflexionLoops de auto-crítica estruturada3–5× ReAct
Self-DiscoverTarefas novas exigindo "como pensar"3–4 calls extras
ReWOOReduzir LLM calls (planner-once)baixo
SupervisorEspecialistas dedicados, controle centralmédio
NetworkColaboração peer-to-peermédio
HierárquicoTimes de timesalto
CRAGRAG quando retrieval falha às vezes+1 call (grader)
Self-RAGGrounding e utilidade garantidos+3 calls (graders)
Adaptive RAGRoteia entre vectorstore e web+1 call (router)
LATSRaciocínio difícil com busca em árvore5–20× ReAct
STORMArtigos longos com fontesalto
+
+ +
+

R1. ReAct com saída estruturada

+

Ideia. Loop ReAct padrão, mas a resposta final passa por um schema Pydantic via uma tool dedicada WeatherResponse que termina a execução.

+

URL canônica: examples/react-agent-structured-output.ipynb

+
from typing import Literal
+from pydantic import BaseModel
+from langchain_openai import ChatOpenAI
+from langgraph.graph import StateGraph, MessagesState, END
+from langgraph.prebuilt import ToolNode
+
+class WeatherResponse(BaseModel):
+    temperature: float
+    conditions: str
+
+@tool
+def search(query: str) -> str: ...
+def respond(state: MessagesState):
+    return {"final": state["messages"][-1].tool_calls[0]["args"]}
+
+llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([search, WeatherResponse])
+
+def call_model(state: MessagesState):
+    return {"messages": [llm.invoke(state["messages"])]}
+
+def route(state) -> Literal["tools", "respond", END]:
+    last = state["messages"][-1]
+    if not last.tool_calls: return END
+    if last.tool_calls[0]["name"] == "WeatherResponse": return "respond"
+    return "tools"
+
+g = StateGraph(MessagesState)
+g.add_node("agent", call_model); g.add_node("tools", ToolNode([search]))
+g.add_node("respond", respond)
+g.set_entry_point("agent"); g.add_conditional_edges("agent", route)
+g.add_edge("tools", "agent"); g.add_edge("respond", END)
+app = g.compile()
+
+ +
+

R2. Plan-and-execute

+

Ideia. Gera plano completo upfront, executa step-a-step e replaneja quando necessário.

+

URL: examples/plan-and-execute

+
from pydantic import BaseModel
+from langgraph.graph import StateGraph, END
+
+class Plan(BaseModel):
+    steps: list[str]
+
+class PlanExecute(TypedDict):
+    input: str
+    plan: list[str]
+    past_steps: list[tuple[str, str]]
+    response: str
+
+planner   = planner_prompt   | ChatOpenAI(model="gpt-5.5", use_responses_api=True).with_structured_output(Plan)
+executor  = create_react_agent("openai:gpt-5.4-mini", tools=[search])
+replanner = replanner_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True).with_structured_output(Plan)
+
+async def plan_step(s):    return {"plan": (await planner.ainvoke({"input": s["input"]})).steps}
+async def execute_step(s):
+    step = s["plan"][0]
+    out  = await executor.ainvoke({"messages":[("user", step)]})
+    return {"past_steps": [(step, out["messages"][-1].content)]}
+async def replan_step(s):  return {"plan": (await replanner.ainvoke(s)).steps}
+def should_end(s):         return END if not s["plan"] else "agent"
+
+g = StateGraph(PlanExecute)
+g.add_node("planner", plan_step); g.add_node("agent", execute_step); g.add_node("replan", replan_step)
+g.set_entry_point("planner"); g.add_edge("planner", "agent")
+g.add_edge("agent", "replan"); g.add_conditional_edges("replan", should_end)
+app = g.compile()
+
+ +
+

R3. Reflection

+

Ideia. Generator escreve, reflector critica, loop até crítico satisfeito ou N rodadas.

+

URL: examples/reflection · blog

+
from langgraph.graph import StateGraph, MessagesState, END
+
+generate = generator_prompt  | ChatOpenAI(model="gpt-5.5", use_responses_api=True)
+reflect  = reflection_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True)
+
+async def generation_node(state: MessagesState):
+    return {"messages": [await generate.ainvoke(state["messages"])]}
+
+async def reflection_node(state: MessagesState):
+    # Flip roles para que o LLM veja o draft do assistente como input do usuário
+    flipped = [HumanMessage(m.content) if isinstance(m, AIMessage) else AIMessage(m.content)
+               for m in state["messages"][1:]]
+    crit = await reflect.ainvoke([state["messages"][0]] + flipped)
+    return {"messages": [HumanMessage(content=crit.content)]}
+
+def should_continue(state):
+    return END if len(state["messages"]) > 6 else "reflect"
+
+g = StateGraph(MessagesState)
+g.add_node("generate", generation_node); g.add_node("reflect", reflection_node)
+g.set_entry_point("generate")
+g.add_conditional_edges("generate", should_continue)
+g.add_edge("reflect", "generate")
+app = g.compile()
+
+ +
+

R4. Reflexion

+

Ideia. Após cada trial, o agente produz auto-feedback verbal estruturado (missing/superfluous/search_queries) que entra em memória persistente consultada no próximo trial.

+

URL: examples/reflexion

+
from pydantic import BaseModel, Field
+from langgraph.graph import StateGraph, MessagesState, END
+
+class Reflection(BaseModel):
+    missing: str = Field(description="What's missing.")
+    superfluous: str = Field(description="What's unnecessary.")
+
+class AnswerQuestion(BaseModel):
+    answer: str
+    reflection: Reflection
+    search_queries: list[str] = Field(description="1-3 queries to address gaps.")
+
+responder = responder_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([AnswerQuestion])
+revisor   = revisor_prompt   | ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([AnswerQuestion])
+
+def run_tools(state):
+    queries = state["messages"][-1].tool_calls[0]["args"]["search_queries"]
+    results = [tavily.invoke(q) for q in queries]
+    return {"messages": [ToolMessage(content=str(results), tool_call_id="t")]}
+
+def event_loop(state):
+    return END if state["messages"][-1].additional_kwargs.get("trial", 0) >= 3 else "execute_tools"
+
+g = StateGraph(MessagesState)
+g.add_node("draft", lambda s: {"messages":[responder.invoke(s["messages"])]})
+g.add_node("execute_tools", run_tools)
+g.add_node("revise", lambda s: {"messages":[revisor.invoke(s["messages"])]})
+g.set_entry_point("draft")
+g.add_edge("draft","execute_tools"); g.add_edge("execute_tools","revise")
+g.add_conditional_edges("revise", event_loop, {"execute_tools":"execute_tools", END:END})
+app = g.compile()
+
+ +
+

R5. Self-Discover

+

Ideia. Três passos: SELECT (módulos de raciocínio relevantes) → ADAPT (adapta ao problema) → IMPLEMENT (plano JSON) → solve. A estrutura de raciocínio é composta em runtime em vez de hardcoded.

+

URL: examples/self-discover

+
from langgraph.graph import StateGraph, END
+
+class State(TypedDict):
+    task: str; modules: list[str]
+    selected: str; adapted: str; plan: str; answer: str
+
+llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
+
+def select(s):    return {"selected": llm.invoke(f"Select modules for: {s['task']}\nFrom: {s['modules']}").content}
+def adapt(s):     return {"adapted":  llm.invoke(f"Adapt these to the task '{s['task']}': {s['selected']}").content}
+def implement(s): return {"plan":     llm.invoke(f"Produce a JSON reasoning plan from: {s['adapted']}").content}
+def solve(s):     return {"answer":   llm.invoke(f"Follow the plan to solve.\nTask: {s['task']}\nPlan: {s['plan']}").content}
+
+g = StateGraph(State)
+g.add_node("select", select); g.add_node("adapt", adapt)
+g.add_node("implement", implement); g.add_node("solve", solve)
+g.set_entry_point("select")
+g.add_edge("select", "adapt"); g.add_edge("adapt", "implement")
+g.add_edge("implement", "solve"); g.add_edge("solve", END)
+app = g.compile()
+
+ +
+

R6. ReWOO (Reasoning WithOut Observation)

+

Ideia. Planner emite plano completo com placeholders de evidência (#E1, #E2); workers rodam tools para preencher; solver sintetiza. Sem diálogo intercalado LLM↔tool → menos tokens que ReAct.

+

URL: examples/rewoo

+
import re
+from langgraph.graph import StateGraph, END
+
+PLAN_RE = re.compile(r"Plan:\s*(.*?)\n#E(\d+)\s*=\s*(\w+)\[(.*?)\]")
+
+class S(TypedDict):
+    task: str; steps: list; results: dict; result: str
+
+def plan(s):
+    raw = llm.invoke(planner_prompt.format(task=s["task"])).content
+    return {"steps": PLAN_RE.findall(raw)}
+
+def tool_execution(s):
+    _, n, tool, args = s["steps"][len(s["results"])]
+    args = re.sub(r"#E(\d+)", lambda m: s["results"][f"#E{m.group(1)}"], args)
+    return {"results": {**s["results"], f"#E{n}": tools[tool].invoke(args)}}
+
+def solve(s):
+    plan = "\n".join(f"Plan: {p}\n#E{n} = {t}[{a}] = {s['results'][f'#E{n}']}"
+                     for p,n,t,a in s["steps"])
+    return {"result": llm.invoke(solver_prompt.format(task=s["task"], plan=plan)).content}
+
+def route(s): return END if len(s["results"]) == len(s["steps"]) else "tool"
+
+g = StateGraph(S)
+g.add_node("plan", plan); g.add_node("tool", tool_execution); g.add_node("solve", solve)
+g.set_entry_point("plan"); g.add_edge("plan", "tool")
+g.add_conditional_edges("tool", route, {"tool":"tool","solve":"solve"}); g.add_edge("solve", END)
+app = g.compile()
+
+ +
+

R7. Multi-agent supervisor

+

Ideia. Um LLM supervisor escolhe qual especialista chamar próximo; cada chamada retorna controle ao supervisor.

+

URL: langgraph-supervisor-py

+
from langgraph_supervisor import create_supervisor
+from langgraph.prebuilt import create_react_agent
+from langgraph.checkpoint.memory import InMemorySaver
+
+def add(a: float, b: float) -> float: return a + b
+def web_search(q: str) -> str: return tavily.invoke(q)
+
+math_agent     = create_react_agent(model="openai:gpt-5.5", tools=[add], name="math_expert")
+research_agent = create_react_agent(model="openai:gpt-5.5", tools=[web_search], name="research_expert")
+
+workflow = create_supervisor(
+    [research_agent, math_agent],
+    model=ChatOpenAI(model="gpt-5.5", use_responses_api=True),
+    prompt="You manage a research expert and a math expert. Route accordingly.",
+)
+app = workflow.compile(checkpointer=InMemorySaver())
+result = app.invoke({"messages":[{"role":"user",
+    "content":"What's the combined FAANG headcount in 2024?"}]})
+
+ Note o contraste: os subagents acima usam a string "openai:gpt-5.5" + (que cai em Chat Completions), enquanto o supervisor recebe um + ChatOpenAI(..., use_responses_api=True) explícito. Para forçar a + Responses API nos subagents, instancie o modelo e passe o objeto em vez da + string — ver a política de integração (§2). +
+
+ +
+

R8. Multi-agent network (colaboração)

+

Ideia. Cada agent pode passar trabalho para qualquer peer; roteamento decidido por tool calls. FINAL ANSWER termina.

+

URL: multi-agent-collaboration.ipynb

+
from langgraph.graph import StateGraph, MessagesState, END
+
+def make_node(agent, name):
+    def node(state):
+        result = agent.invoke(state)
+        result["messages"][-1].name = name
+        return {"messages": result["messages"]}
+    return node
+
+def route(state):
+    last = state["messages"][-1]
+    if "FINAL ANSWER" in last.content: return END
+    return "Chart Generator" if last.name == "Researcher" else "Researcher"
+
+researcher = create_react_agent(llm, tools=[search],     prompt=research_prompt)
+charter    = create_react_agent(llm, tools=[python_repl], prompt=chart_prompt)
+
+g = StateGraph(MessagesState)
+g.add_node("Researcher",      make_node(researcher, "Researcher"))
+g.add_node("Chart Generator", make_node(charter,    "Chart Generator"))
+g.set_entry_point("Researcher")
+g.add_conditional_edges("Researcher",      route, {"Chart Generator":"Chart Generator", END:END})
+g.add_conditional_edges("Chart Generator", route, {"Researcher":"Researcher", END:END})
+app = g.compile()
+
+ +
+

R9. Times hierárquicos

+

Ideia. Cada sub-time é um subgrafo com seu próprio supervisor; um supervisor de topo roteia entre times.

+

URL: hierarchical_agent_teams.ipynb

+
from langgraph.graph import StateGraph, MessagesState, END
+
+def call_research(state): return research_team.invoke({"messages": state["messages"]})
+def call_writing(state):  return writing_team.invoke({"messages":  state["messages"]})
+
+def top_supervisor(state):
+    return llm.with_structured_output(Route).invoke(supervisor_prompt + state["messages"])
+
+def route(state):
+    decision = state["next"]   # "research_team" | "writing_team" | "FINISH"
+    return END if decision == "FINISH" else decision
+
+g = StateGraph(MessagesState)
+g.add_node("supervisor",    lambda s: {"next": top_supervisor(s).destination})
+g.add_node("research_team", call_research)
+g.add_node("writing_team",  call_writing)
+g.set_entry_point("supervisor")
+g.add_conditional_edges("supervisor", route)
+g.add_edge("research_team", "supervisor"); g.add_edge("writing_team", "supervisor")
+app = g.compile()
+
+ +
+

R10. Corrective RAG (CRAG)

+

Ideia. Grader avalia docs recuperados; se relevância baixa, reescreve a query e cai em web search antes de gerar.

+

URL: examples/rag/langgraph_crag.ipynb

+
from langgraph.graph import StateGraph, END
+
+class S(TypedDict):
+    question: str; documents: list; web_search: str; generation: str
+
+def retrieve(s):
+    return {"documents": retriever.invoke(s["question"])}
+
+def grade(s):
+    kept = [d for d in s["documents"]
+            if "yes" in grader.invoke({"q": s["question"], "d": d.page_content}).binary_score]
+    return {"documents": kept, "web_search": "Yes" if not kept else "No"}
+
+def transform_query(s):
+    return {"question": rewriter.invoke({"question": s["question"]}).content}
+
+def web_search_node(s):
+    docs = tavily.invoke(s["question"])
+    return {"documents": s["documents"] + [Document(page_content=d["content"]) for d in docs]}
+
+def generate(s):
+    return {"generation": rag_chain.invoke({"q": s["question"], "docs": s["documents"]})}
+
+def decide(s): return "transform_query" if s["web_search"]=="Yes" else "generate"
+
+g = StateGraph(S)
+for n, f in [("retrieve",retrieve),("grade",grade),("transform_query",transform_query),
+             ("web_search",web_search_node),("generate",generate)]:
+    g.add_node(n, f)
+g.set_entry_point("retrieve"); g.add_edge("retrieve","grade")
+g.add_conditional_edges("grade", decide); g.add_edge("transform_query","web_search")
+g.add_edge("web_search","generate"); g.add_edge("generate", END)
+app = g.compile()
+
+ +
+

R11. Self-RAG

+

Ideia. Três graders independentes: relevância por doc, grounding (alucinação) e utilidade da resposta. Retry de retrieval ou geração até passar nos três.

+

URL: examples/rag/langgraph_self_rag.ipynb

+
from langgraph.graph import StateGraph, END
+
+class S(TypedDict): question: str; documents: list; generation: str
+
+def retrieve(s):  return {"documents": retriever.invoke(s["question"])}
+def grade_docs(s):
+    kept = [d for d in s["documents"]
+            if doc_grader.invoke({"q": s["question"], "d": d.page_content}).score == "yes"]
+    return {"documents": kept}
+def generate(s):  return {"generation": rag.invoke({"q": s["question"], "docs": s["documents"]})}
+def transform(s): return {"question": rewriter.invoke({"q": s["question"]}).content}
+
+def decide_after_grade(s):    return "generate" if s["documents"] else "transform_query"
+def decide_after_generate(s):
+    grounded = halluc_grader.invoke({"docs": s["documents"], "gen": s["generation"]}).score == "yes"
+    if not grounded: return "generate"
+    useful = answer_grader.invoke({"q": s["question"], "gen": s["generation"]}).score == "yes"
+    return END if useful else "transform_query"
+
+g = StateGraph(S)
+for n, f in [("retrieve",retrieve),("grade",grade_docs),
+             ("generate",generate),("transform_query",transform)]:
+    g.add_node(n, f)
+g.set_entry_point("retrieve"); g.add_edge("retrieve","grade")
+g.add_conditional_edges("grade",    decide_after_grade)
+g.add_edge("transform_query","retrieve")
+g.add_conditional_edges("generate", decide_after_generate)
+app = g.compile()
+
+ +
+

R12. Adaptive RAG

+

Ideia. Router escolhe vectorstore vs. web search por query, depois roda um loop Self-RAG. Adapta a estratégia de retrieval à classe da pergunta.

+

URL: examples/rag/langgraph_adaptive_rag.ipynb

+
from pydantic import BaseModel, Field
+from langgraph.graph import StateGraph, END
+
+class Route(BaseModel):
+    datasource: Literal["vectorstore","web_search"] = Field(description="Pick one")
+
+router = (router_prompt | ChatOpenAI(model="gpt-5.4-mini", temperature=0, use_responses_api=True)
+                          .with_structured_output(Route))
+
+def route_query(s):
+    return "web_search" if router.invoke({"question": s["question"]}).datasource == "web_search" \
+                        else "retrieve"
+
+g = StateGraph(S)
+g.add_node("retrieve", retrieve); g.add_node("web_search", web_search_node)
+g.add_node("grade", grade_docs); g.add_node("generate", generate)
+g.add_node("transform_query", transform)
+g.set_conditional_entry_point(route_query, {"retrieve":"retrieve", "web_search":"web_search"})
+g.add_edge("retrieve","grade"); g.add_edge("web_search","generate")
+g.add_conditional_edges("grade", lambda s: "generate" if s["documents"] else "transform_query")
+g.add_edge("transform_query","retrieve")
+g.add_conditional_edges("generate", decide_after_generate)
+app = g.compile()
+
+ +
+

R13. LATS — Language Agent Tree Search

+

Ideia. MCTS sobre trajetórias de raciocínio LLM com seleção UCB, avaliação por reflexão e backpropagation. Troca 5–20× LLM calls por taxa de solução maior em raciocínio difícil.

+

URL: examples/lats/lats.ipynb

+
import math
+from dataclasses import dataclass, field
+
+@dataclass
+class Node:
+    messages: list
+    parent: "Node | None" = None
+    children: list = field(default_factory=list)
+    value: float = 0.0
+    visits: int = 0
+    reflection: str | None = None
+
+    def uct(self, c=1.4):
+        if self.visits == 0: return float("inf")
+        return self.value/self.visits + c*math.sqrt(math.log(self.parent.visits)/self.visits)
+
+    def best_child(self): return max(self.children, key=lambda n: n.uct())
+    def is_solved(self):  return self.reflection and "SOLVED" in self.reflection
+
+def expand(node):
+    candidates = generator.batch([node.messages]*5)
+    node.children = [Node(node.messages+[c], parent=node) for c in candidates]
+
+def evaluate(node):
+    node.reflection = reflector.invoke(node.messages).content
+    score = float(reflector_score(node.reflection))
+    while node:
+        node.visits += 1; node.value += score
+        node = node.parent
+
+def lats(root, max_rollouts=10):
+    for _ in range(max_rollouts):
+        leaf = root
+        while leaf.children: leaf = leaf.best_child()
+        expand(leaf)
+        for child in leaf.children:
+            evaluate(child)
+            if child.is_solved(): return child
+    return root.best_child()
+
+ +
+

R14. STORM — pesquisa + escrita

+

Ideia. Gera outline, simula entrevistas com múltiplos experts (cada um busca e responde em paralelo via Send), refina outline, escreve seções, monta artigo.

+

URL: examples/storm/storm.ipynb

+
from langgraph.graph import StateGraph, END
+from langgraph.constants import Send
+
+def outline(s):      return {"outline":  outline_llm.invoke({"topic": s["topic"]})}
+def perspectives(s): return {"experts":  expert_llm.invoke({"outline": s["outline"]}).experts}
+
+def dispatch(s):  # fan-out paralelo
+    return [Send("interview", {"expert": e, "topic": s["topic"]}) for e in s["experts"]]
+
+def interview(s):
+    qa = []
+    for _ in range(3):
+        q    = question_llm.invoke({"expert": s["expert"], "qa": qa})
+        docs = search.invoke(q)
+        a    = answer_llm.invoke({"q": q, "docs": docs})
+        qa.append({"q": q, "a": a})
+    return {"interviews": [{"expert": s["expert"], "qa": qa}]}
+
+def refine(s):  return {"outline_v2": refine_llm.invoke({"out": s["outline"], "int": s["interviews"]})}
+def write(s):   return {"article":    writer_llm.invoke({"outline": s["outline_v2"], "int": s["interviews"]})}
+
+g = StateGraph(STORMState)
+for n, f in [("outline",outline),("perspectives",perspectives),
+             ("interview",interview),("refine",refine),("write",write)]:
+    g.add_node(n, f)
+g.set_entry_point("outline"); g.add_edge("outline","perspectives")
+g.add_conditional_edges("perspectives", dispatch, ["interview"])
+g.add_edge("interview","refine"); g.add_edge("refine","write"); g.add_edge("write", END)
+app = g.compile()
+
+ +
+

Apêndice — endpoints REST e variáveis-chave

+

HTTP cheat-sheet

+
# Threads
+POST   /threads
+POST   /threads/search
+GET    /threads/{id}
+PATCH  /threads/{id}
+DELETE /threads/{id}
+POST   /threads/{id}/copy
+GET    /threads/{id}/state
+POST   /threads/{id}/state           # update_state
+GET    /threads/{id}/history
+GET    /threads/{id}/stream          # thread-wide SSE (atravessa runs)
+
+# Runs (em uma thread)
+POST   /threads/{tid}/runs
+POST   /threads/{tid}/runs/stream
+POST   /threads/{tid}/runs/wait
+GET    /threads/{tid}/runs
+GET    /threads/{tid}/runs/{rid}
+POST   /threads/{tid}/runs/{rid}/cancel
+GET    /threads/{tid}/runs/{rid}/join
+GET    /threads/{tid}/runs/{rid}/stream  # join_stream
+
+# Stateless runs
+POST   /runs
+POST   /runs/stream
+POST   /runs/wait
+
+# Assistants
+POST   /assistants
+POST   /assistants/search
+GET    /assistants/{id}
+PATCH  /assistants/{id}
+DELETE /assistants/{id}
+GET    /assistants/{id}/versions
+
+# Crons
+POST   /runs/crons
+POST   /threads/{tid}/runs/crons
+POST   /runs/crons/search
+DELETE /runs/crons/{cid}
+
+# Store
+PUT    /store/items
+GET    /store/items
+DELETE /store/items
+POST   /store/items/search
+POST   /store/namespaces
+
+# Health
+GET    /ok
+ +

Variáveis-chave Standalone Server

+
+ + + + + + + + +
VariávelFunção
DATABASE_URIPostgres ≥ 14 (checkpoints, assistants, threads, runs, crons, store)
REDIS_URIRedis ≥ 6 (pubsub para fan-out de streaming)
LANGGRAPH_CLOUD_LICENSE_KEYLicença Enterprise
LANGSMITH_API_KEYPush para LangSmith / tracing
LG_WEBHOOK_*Variáveis seguras interpoláveis em headers de webhook
+
+ +
+
+ + + + + diff --git a/references/agents_tools_best_guides/guia_langgraph_orquestracao.html b/references/agents_tools_best_guides/guia_langgraph_orquestracao.html new file mode 100644 index 0000000..e958db5 --- /dev/null +++ b/references/agents_tools_best_guides/guia_langgraph_orquestracao.html @@ -0,0 +1,911 @@ + + + + + +Orquestração com LangGraph — Guia complementar + + + + + + + + +
+
+
Orquestração com LangGraph guia complementar de orquestração
+
+ Verificado em 2026-06-25 + langgraph 1.2.6 + Python + +
+
+
+ +
+ + +
+ +
+

Orquestração com LangGraph

+

+ Este guia mostra como aplicar os padrões de orquestração do núcleo — ledger + canônico, estado durável, HITL, fan-out e multi-agente — usando LangGraph + (langgraph 1.x GA). O StateGraph tipado é o ledger; os + checkpointers são a persistência durável; interrupt()/Command + são o HITL. Complementa o guia de referência da API; aqui o foco é o mapeamento + arquitetural. Prosa em PT-BR; código e identificadores em inglês. +

+
+ langgraph 1.2.6 + Python + SOTA · verificado 2026-06-25 +
+
+ +
+

Sobre este guia

+

+ LangGraph modela um agente como um grafo de estado: nós que leem e escrevem um + estado tipado, arestas que decidem o próximo nó, e um runtime que persiste tudo a cada passo. Se + o Agents SDK esconde o loop, o LangGraph o expõe — o que o torna a base certa quando + você precisa de controle explícito, durabilidade e replay. +

+
+ Como ler: os fundamentos de cada primitiva (StateGraph, reducers, Send, + Command, checkpointers, interrupt, Store, supervisor/swarm, time-travel, durable execution e o + receituário R1–R14) estão em guia_langgraph.html. Para o + harness Deep Agents sobre LangGraph, ver guia_deepagents.html. + Aqui assumimos os fundamentos e mostramos como mapear os padrões agnósticos. +
+
+ Onde os conceitos vivem: padrões agnósticos em + guia_arquitetura_orquestracao.html; contrato de + estado durável e compaction em + guia_estado_contexto_memoria.html; HITL como + operação em guia_operacao_seguranca_evals.html. +
+
+ +
+

Fontes & verificação

+

+ APIs conferidas contra a referência oficial (reference.langchain.com / docs.langchain.com) e a + folha de fatos do projeto, re-conferida em 2026-06-19. Versões: langgraph 1.2.6, + langgraph-checkpoint-postgres 3.1.0 (PyPI). +

+
+ + + + + + + +
Recurso oficialURLUso aqui
LangGraph (docs)docs.langchain.com/oss/python/langgraphStateGraph, persistência, HITL, streaming
API reference (Python)reference.langchain.com/python/langgraphget_store, InMemoryStore, interrupt
langgraph-supervisor.../langgraph-supervisorcreate_supervisor
langgraph-swarm.../langgraph-swarmcreate_swarm, create_handoff_tool
+

+ Legenda dos selos: Verificado confirmado na doc oficial · + Novo recente · + Atenção ressalva · + N/D não documentado. +

+
+ +
+

1. Quando LangGraph é a base

+

+ LangGraph é uma base recomendada — não a única. Escolha-o quando o problema pede + um grafo de estado explícito, persistência durável com checkpoints versionados, time-travel e + HITL nativo por interrupção. Para um loop leve no ecossistema OpenAI, o Agents SDK é mais direto; + para runtime poliglota com A2A nativo, o Google ADK. O blueprint do núcleo é o mesmo nas três. +

+
+ + + + + + +
Se você precisa de…Base recomendadaPor quê
Grafo de estado explícito, checkpoints duráveis, time-travel, HITL por interrupção, durable executionLangGraph este guiaEstado tipado de primeira classe; persistência e replay nativos.
Loop leve no ecossistema OpenAI, handoffs + guardrails embutidosOpenAI Agents SDKVer guia_agents_sdk_orquestracao.html.
Runtime poliglota, workflow de grafo do provider, A2A nativo, deploy gerenciado no GCPGoogle ADKVer guia_google_adk_orquestracao.html.
+
+ Vantagem-chave do LangGraph: como o estado é explícito e persistido, você ganha + de graça três coisas que o núcleo pede — ledger reidratável, replay/time-travel e durabilidade + contra falhas. Ver padrões + por maturidade. +
+
+ +
+

2. StateGraph + reducers como ledger canônico

+

+ No núcleo, o ledger canônico é a fonte da verdade: itens tipados que são + reduzidos e projetados. No LangGraph, o estado do grafo é esse ledger. Você + declara um schema tipado (TypedDict) e, para campos que acumulam em vez de + sobrescrever, anexa um reducer via Annotated[tipo, reducer]. Cada + nó retorna um delta; o reducer decide como ele se funde ao estado — exatamente o ciclo + "registrar → reduzir" do núcleo. +

+ +
import operator
+from typing import Annotated, TypedDict
+from langgraph.graph import StateGraph, START, END
+from langgraph.graph.message import add_messages
+
+class AgentState(TypedDict):
+    # 'messages' acumula (reducer add_messages); 'step' sobrescreve (sem reducer).
+    messages: Annotated[list, add_messages]
+    findings: Annotated[list[str], operator.add]   # cada nó faz append, não overwrite
+    step: int
+
+def plan(state: AgentState) -> dict:
+    # Retorna apenas o DELTA — o reducer funde ao ledger.
+    return {"findings": ["planned 3 subtasks"], "step": state["step"] + 1}
+
+builder = StateGraph(AgentState)
+builder.add_node("plan", plan)
+builder.add_edge(START, "plan")
+builder.add_edge("plan", END)
+graph = builder.compile()
+
+result = graph.invoke({"messages": [], "findings": [], "step": 0})
+ + +
+ Reducer = regra de fusão do ledger. add_messages para histórico de + mensagens; operator.add para listas que acumulam; sem reducer = overwrite. Esta é a + materialização direta de "registrar e reduzir" — ver + ledger canônico. +
+
+ +
+

3. Checkpointers como estado durável

+

+ O núcleo separa estado durável de payload volátil. No LangGraph, o checkpointer + é a persistência durável: a cada super-passo do grafo, o estado completo é salvo sob um + thread_id. Isso dá reidratação, retomada após falha e time-travel sem código extra. + Para produção, use PostgresSaver; para dev/teste, InMemorySaver ou + SqliteSaver. +

+ +
+
+ + +
+
+
from langgraph.checkpoint.memory import InMemorySaver
+
+graph = builder.compile(checkpointer=InMemorySaver())
+
+# thread_id define o "fio" persistente do estado (uma conversa/sessão).
+config = {"configurable": {"thread_id": "session-42"}}
+graph.invoke({"messages": [("user", "oi")], "findings": [], "step": 0}, config)
+graph.invoke({"messages": [("user", "continua")]}, config)  # retoma o mesmo estado
+
+
+
# Persistência durável em Postgres (verificado: langgraph-checkpoint-postgres 3.1.0)
+# PostgresSaver exige um driver psycopg utilizável — sem ele, o import levanta ImportError.
+pip install "langgraph==1.2.6" "langgraph-checkpoint-postgres==3.1.0" "psycopg[binary,pool]"
+
+
+
# Produção: PostgresSaver (estado sobrevive a reinícios e falhas)
+from langgraph.checkpoint.postgres import PostgresSaver
+
+DB_URI = ...  # vem da config/secret manager — nunca hardcode credenciais
+with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
+    checkpointer.setup()                       # cria as tabelas na primeira vez
+    graph = builder.compile(checkpointer=checkpointer)
+    graph.invoke(initial_state, {"configurable": {"thread_id": "session-42"}})
+ + +
+ Contrato de estado: o checkpointer é a projeção persistida do ledger; + a teoria de compaction/reidratação (o que pode e o que não pode ser perdido) está em + compaction e + reidratação. Time-travel/replay: ver + tracing, replay e cost + ledger. +
+
+ +
+

Padrões de orquestração no grafo

+

+ Com estado tipado + checkpointer no lugar, os padrões do núcleo viram construções de grafo: + HITL é uma interrupção; composição é um subgraph; multi-agente é supervisor ou swarm; observar o + loop é streaming; memória entre threads é o Store. +

+
+ +
+

4. HITL: interrupt() & Command(resume=)

+

+ O fluxo de aprovação humana do núcleo (HITL) é nativo: dentro de um nó, chame + interrupt(payload) para pausar o grafo e devolver o controle. O estado é + persistido pelo checkpointer; quando o humano responde, você retoma com + Command(resume=valor) usando o mesmo thread_id. O valor de resume vira + o retorno do interrupt() — a execução continua exatamente de onde parou. +

+ +
from langgraph.types import interrupt, Command
+
+def approve_refund(state: AgentState) -> dict:
+    decision = interrupt({                       # PAUSA aqui; estado é persistido
+        "question": "Approve refund?",
+        "amount": state.get("amount"),
+    })
+    if decision != "approve":
+        return {"findings": ["refund denied by human"]}
+    return {"findings": ["refund approved"]}
+
+graph = builder.compile(checkpointer=InMemorySaver())
+config = {"configurable": {"thread_id": "ticket-9"}}
+
+# 1) Roda até a interrupção:
+graph.invoke(initial_state, config)
+# 2) Detecta o interrupt no stream/estado e mostra ao humano (chave __interrupt__).
+# 3) Retoma com a decisão humana:
+graph.invoke(Command(resume="approve"), config)
+ + +
+ Por que isso é robusto: como o estado fica no checkpointer, a pausa pode durar + segundos ou dias — o processo pode até reiniciar. É o contrato HITL do núcleo + (fluxo de aprovação) com + durabilidade real. Em stream, detecte a pausa pela chave __interrupt__ no chunk de + updates. +
+
+ +
+

5. Subgraphs como composição

+

+ O núcleo recomenda compor capacidades em unidades isoláveis. No LangGraph, um subgraph + é um grafo compilado usado como nó de outro grafo. Se os schemas de estado compartilham as chaves + relevantes, basta adicionar o subgraph compilado como nó; senão, embrulhe-o em uma função que + traduz o estado (o equivalente ao delegation packet do núcleo). +

+ +
# Subgraph: uma sub-rotina de pesquisa, compilada independentemente.
+research_graph = research_builder.compile()
+
+# Grafo pai: usa o subgraph como um nó (estados compartilham chaves).
+parent = StateGraph(AgentState)
+parent.add_node("research", research_graph)        # subgraph como nó
+parent.add_node("write", write_node)
+parent.add_edge(START, "research")
+parent.add_edge("research", "write")
+parent.add_edge("write", END)
+app = parent.compile(checkpointer=InMemorySaver())
+ +
+ Fan-out: para disparar a mesma sub-rotina em paralelo sobre N itens + (map-reduce), use Send — ver o detalhe em + guia_langgraph.html (seção Send) e o padrão agnóstico + em fan-out e wind-down. +
+
+ +
+

6. Multi-agente: supervisor & swarm

+

+ O núcleo distingue handoff (transferir o dono do turno) de + agent-as-tool (delegar e continuar no comando). O LangGraph oferece dois pacotes + prebuilt que materializam topologias multi-agente: +

+
    +
  • Supervisor (langgraph-supervisor): um agente coordenador + roteia para especialistas via tools de handoff e retoma o controle depois — é o padrão + "manager" do núcleo.
  • +
  • Swarm (langgraph-swarm): agentes transferem controle + diretamente entre si (handoff peer-to-peer); o último agente ativo é lembrado por thread.
  • +
+ +

Supervisor (coordenador retoma o controle)

+
from langgraph_supervisor import create_supervisor
+from langgraph.prebuilt import create_react_agent
+
+# Especialistas (model resolvido por config — não hardcode o slug).
+math_agent = create_react_agent(model=MODEL, tools=[add], name="math_expert")
+research_agent = create_react_agent(model=MODEL, tools=[web_search], name="research_expert")
+
+workflow = create_supervisor(
+    [research_agent, math_agent],
+    model=SUPERVISOR_MODEL,                 # o modelo do coordenador, vindo da config
+    output_mode="last_message",             # default; ou "full_history"
+)
+app = workflow.compile()                     # adicione checkpointer= para durabilidade
+result = app.invoke({"messages": [{"role": "user", "content": "combined headcount of FAANG 2024?"}]})
+ + +

Swarm (handoff peer-to-peer)

+
from langgraph_swarm import create_swarm, create_handoff_tool
+from langgraph.prebuilt import create_react_agent
+
+alice = create_react_agent(
+    model=MODEL, name="Alice", tools=[add,
+        create_handoff_tool(agent_name="Bob", description="Transfer to Bob")],
+)
+bob = create_react_agent(
+    model=MODEL, name="Bob",
+    tools=[create_handoff_tool(agent_name="Alice", description="Transfer to Alice for math")],
+)
+
+workflow = create_swarm([alice, bob], default_active_agent="Alice")
+app = workflow.compile(checkpointer=InMemorySaver())
+# A tool de handoff é nomeada transfer_to_<agent_name> por padrão.
+ + +
+ + + + + + +
Padrão do núcleoNo LangGraphQuem retoma o turno
Manager / delegação centralcreate_supervisor(...)O supervisor (volta a ele)
Handoff peer-to-peercreate_swarm(...) + create_handoff_toolO agente que recebeu o handoff
Agent-as-tool puroCompilar o subgrafo e expô-lo como toolO chamador
+
+ Deprecação (LangGraph v1): langgraph.prebuilt.create_react_agent + foi deprecado em favor de from langchain.agents import create_agent. Os exemplos + de create_supervisor/create_swarm acima ainda usam + create_react_agent (continua funcional com aviso @deprecated); código + novo deve usar create_agent(model, tools, system_prompt=…). Ver + guia_langgraph.html para a tabela completa de deprecações v1. +
+
+ +
+

7. Streaming v2

+

+ Observar o loop enquanto acontece (fan-out/wind-down visível, UX responsiva) é + graph.stream(...). Os modos determinam o que você recebe — combine + vários numa lista: +

+
+ + + + + + + + +
stream_modeO que emite
valuesSnapshot completo do estado a cada passo.
updatesSó as chaves alteradas por nó (e __interrupt__ em HITL).
messagesTuplas (chunk, metadata) de tokens do LLM.
customDados emitidos por você via get_stream_writer().
tasksEventos de início/fim de tarefas (nós).
+ +
for mode, chunk in graph.stream(
+    initial_state,
+    config={"configurable": {"thread_id": "s-1"}},
+    stream_mode=["updates", "messages"],     # múltiplos modos
+):
+    if mode == "messages":
+        token, meta = chunk
+        print(token.content, end="", flush=True)
+    elif mode == "updates":
+        if "__interrupt__" in chunk:          # HITL pausou o grafo
+            handle_human_review(chunk["__interrupt__"])
+ +
+ +
+

8. Store: memória cross-thread

+

+ O checkpointer guarda o estado de um thread. Para memória entre threads + (perfis de usuário, fatos persistentes que sobrevivem a sessões), use o Store — a + materialização da "memória de longo prazo" do núcleo. Você compila o grafo com + store= e, dentro de qualquer nó, acessa-o por get_store(). Itens são + organizados por namespace (tupla) + key. +

+ +
from langgraph.store.memory import InMemoryStore
+from langgraph.config import get_store
+
+store = InMemoryStore()
+store.put(("users",), "user_123", {"name": "Alice", "tier": "pro"})
+
+def personalize(state: AgentState) -> dict:
+    my_store = get_store()                                   # acessa o Store de dentro do nó
+    item = my_store.get(("users",), "user_123")
+    name = item.value["name"] if item else "unknown"
+    return {"findings": [f"greeting for {name}"]}
+
+graph = (
+    StateGraph(AgentState)
+    .add_node("personalize", personalize)
+    .add_edge(START, "personalize")
+    .compile(store=store, checkpointer=InMemorySaver())      # store= habilita get_store()
+)
+ +
+ Para produção: use PostgresStore (busca semântica opcional). O + contrato de memória vs estado de sessão está em + modos de estado. +
+
+ +
+

9. Mapeando o blueprint do núcleo ao grafo

+

Tabela-âncora: cada camada do blueprint SOTA e sua materialização no LangGraph.

+
+ + + + + + + + + + + + + +
Camada do núcleoNo LangGraphStatus
Estado durável (ledger canônico)StateGraph tipado + reducers; checkpointer persistenativo
Router / triagemConditional edges / Command(goto=)nativo
Manager / multi-agentecreate_supervisor (coordenador retoma)nativo
Handoff peer-to-peercreate_swarm + create_handoff_toolnativo
Capability registryTools nos nós/ReAct; MCP via adapternativo
HITL (aprovação)interrupt() + Command(resume=)nativo
ComposiçãoSubgraphs (grafo compilado como nó)nativo
Fan-out / wind-downSend (map-reduce) + streamingnativo
Observer / replayStreaming v2 + checkpoints (time-travel)nativo
Memória de longo prazoStore (cross-thread)nativo
+
+ Resumo: o que no Agents SDK é configuração do Runner, no LangGraph + é topologia do grafo. A vantagem é durabilidade e controle explícitos; o custo é mais cerimônia + de montagem. Escolha pela necessidade de estado durável e replay. +
+
+ +
+

Cheat sheet — imports, classes & decisões

+

Imports essenciais

+
# Grafo e estado
+from langgraph.graph import StateGraph, START, END
+from langgraph.graph.message import add_messages
+from typing import Annotated, TypedDict
+# HITL e roteamento
+from langgraph.types import interrupt, Command
+# Persistência
+from langgraph.checkpoint.memory import InMemorySaver
+from langgraph.checkpoint.postgres import PostgresSaver     # langgraph-checkpoint-postgres
+# Memória cross-thread
+from langgraph.store.memory import InMemoryStore
+from langgraph.config import get_store, get_stream_writer
+# Multi-agente (pacotes prebuilt)
+from langgraph_supervisor import create_supervisor
+from langgraph_swarm import create_swarm, create_handoff_tool
+from langgraph.prebuilt import create_react_agent
+ +

Decisão rápida

+
    +
  • ☐ Estado precisa acumular (não overwrite) → Annotated[tipo, reducer].
  • +
  • ☐ Precisa sobreviver a reinícios/falhas → compile(checkpointer=PostgresSaver(...)).
  • +
  • ☐ Precisa de aprovação humana no meio → interrupt() + Command(resume=).
  • +
  • ☐ Coordenador que delega e retoma → create_supervisor(...).
  • +
  • ☐ Agentes que transferem entre si → create_swarm(...).
  • +
  • ☐ Memória entre sessões/usuários → Store + get_store().
  • +
  • ☐ UX em tempo real → graph.stream(stream_mode=["updates","messages"]).
  • +
+
+ +
+

Notas de verificação

+

APIs conferidas contra a referência oficial LangChain/LangGraph e a folha de fatos do projeto em 2026-06-10.

+
    +
  • Resolvido langgraph 1.2.6 e langgraph-checkpoint-postgres 3.1.0 (PyPI, re-conferidos em 2026-06-19). LangGraph é 1.x GA (não 0.x).
  • +
  • Resolvido StateGraph, START/END, reducers via Annotated, add_messages.
  • +
  • Resolvido interrupt() + Command(resume=) (de langgraph.types); detecção por __interrupt__ no stream de updates.
  • +
  • Resolvido InMemoryStore (de langgraph.store.memory), store.put((ns,), key, value), store.get((ns,), key).value, get_store() (de langgraph.config), compile(store=) — confirmados na ref oficial em 2026-05-25 (resolve o item UNVERIFIED da folha §11).
  • +
  • Resolvido create_supervisor(agents, *, model, prompt=, output_mode='last_message', handoff_tool_prefix=, supervisor_name='supervisor') (de langgraph_supervisor) — assinatura confirmada na ref oficial (resolve UNVERIFIED §11).
  • +
  • Resolvido create_swarm(agents, *, default_active_agent, state_schema=SwarmState) + create_handoff_tool(agent_name=, name=, description=) → tool transfer_to_<agent_name> (de langgraph_swarm) — confirmados na ref oficial (resolve UNVERIFIED §11).
  • +
  • Resolvido Streaming v2: modos values | updates | messages | custom | tasks; get_stream_writer() de langgraph.config.
  • +
  • Atenção Prebuilt: a ref oficial expõe langchain.agents.create_agent como o mais novo; create_react_agent (de langgraph.prebuilt) segue válido e é o usado nos exemplos de supervisor. Use o que casa com a versão pinada do seu projeto (reconferido na ref oficial em 2026-06-10).
  • +
  • Atenção Slugs de modelo NÃO são hardcoded (MODEL/SUPERVISOR_MODEL vêm da config). Para IDs vigentes, ver a folha SOTA do projeto e o portal.
  • +
+
+ APIs UNVERIFIED neste guia: nenhuma. Os 3 itens que a folha §11 listava como + UNVERIFIED (Store, supervisor, swarm) foram confirmados ao vivo na referência oficial + (reference.langchain.com) em 2026-06-10. +
+
+ +
+
+ + + + + + diff --git a/references/agents_tools_best_guides/guia_multimodal.html b/references/agents_tools_best_guides/guia_multimodal.html new file mode 100644 index 0000000..6b95502 --- /dev/null +++ b/references/agents_tools_best_guides/guia_multimodal.html @@ -0,0 +1,9182 @@ + + + + + +Guia Multimodal — OpenAI, Gemini e Anthropic (imagens, PDFs, Office, vídeo, áudio, code interpreter) + + + + + + + + +
+
+
Guia Multimodal OpenAI · Gemini · Anthropic
+
+ Verificado em 2026-06-11 + OpenAI + Gemini + Claude + +
+
+
+ +
+ + +
+ +
+

Como OpenAI, Gemini e Claude leem imagens, PDFs, planilhas, vídeo e áudio

+

Referência técnica comparativa, exaustiva e verificada. Para cada provider documenta-se como entram os arquivos, quais parâmetros existem, como são tokenizados, quais são os limites de tamanho/duração, o que cada modelo aceita, exemplos rodáveis em Python e TypeScript, e onde estão as fronteiras práticas. Construída consultando a documentação oficial de cada provider via MCP em 2026-06-10.

+
+ SDKs oficiais atuais + Responses API · google-genai · Messages API + Itens marcados UNVERIFIED precisam re-verificação antes de citar publicamente +
+
+ +
+

Deltas após verificação ao vivo (2026-05-23)

+

Os fatos deste guia foram re-verificados independentemente contra as páginas oficiais dos três providers (developers.openai.com, ai.google.dev, platform.claude.com / docs.claude.com). Esta seção resume as correções e itens novos identificados na verificação. Todos foram absorvidos no guia abaixo onde aplicável; manter aqui o resumo facilita auditoria.

+
+ Varredura 2026-06-10. Re-verificação contra docs oficiais + PyPI/npm. Mudanças aplicadas nesta edição: +
    +
  • Gemini Interactions API: remoção do schema legado outputs[] consumada em 08/06/2026 — header Api-Revision agora ignorado (rollback impossível), SDKs google-genai/@google/genai 1.x quebrados para Interactions; steps[] é o único schema. A página oficial de migração passou a chamar a Interactions API de "the standard interface for building with Gemini" e a recomendá-la para todo desenvolvimento novo; a overview mantém Beta + generateContent para produção estável.
  • +
  • OpenAI containers (Code Interpreter): desde 02/06/2026 a cobrança de tempo de container é por minuto, com mínimo de 5 min por sessão (antes: blocos de 20 min).
  • +
  • Imagem Gemini: gemini-3.1-flash-image (Nano Banana 2) e gemini-3-pro-image (Nano Banana Pro) são GA desde 28/05/2026; os IDs -preview correspondentes serão desligados em 25/06/2026.
  • +
  • Correções internas: JSON-LD do Code Interpreter (container OpenAI expira após 20 min idle — a retenção de 30 dias é da Anthropic); caps da Files API do Gemini (2 GB por arquivo / 20 GB por projeto); leftover de Sora 2 seconds em §4.10 removido (API reference = 4/8/12, default 4); deep dive Anthropic renumerado para 7.x (numeração 6.x duplicava a do Interactions deep dive) com as seções seguintes renumeradas para 8–11.
  • +
+
+
+
+

OpenAI — confirmados & corrigidos

+
    +
  • Realtime sessão = 60 min (não 30 min). Confirmado em realtime-conversations#session-lifecycle-events.
  • +
  • Sora 2 seconds via API ref: 4, 8, 12 (default 4). O cookbook menciona 16/20 mas a API reference é autoridade.
  • +
  • Sora 2-Pro resolutions: além de 1920x1080/1080x1920, também aceita 1024x1792 e 1792x1024.
  • +
  • Realtime chunks ≤ 15 MB; conexões: WebSocket, WebRTC, SIP.
  • +
  • Modelos Realtime atuais: gpt-realtime-2 (mais capaz, com reasoning para voz realtime), gpt-realtime-1.5 (speech-to-speech rápido sem reasoning, com guia de prompting dedicado), gpt-realtime (GA base), gpt-realtime-mini (custo), gpt-realtime-translate (tradução) e gpt-realtime-whisper (STT streaming) — todos com página oficial em developers.openai.com/api/docs/models.
  • +
  • Files expires_after: agora confirmado {anchor: "created_at", seconds: 3600..2592000} (1h a 30 dias).
  • +
  • Audio guide: canonical de áudio em chat = gpt-audio-1.5.
  • +
+
+
+

Gemini — confirmados & corrigidos

+
    +
  • Inline cap distinguir por surface: 20 MB image/audio, 50 MB PDF, 100 MB external URL.
  • +
  • External URL fetch aceita image/bmp mas NÃO aceita HEIC/HEIF (esses só no inline nativo).
  • +
  • Priority tier é exatamente ~1.8× standard (não 175-200%).
  • +
  • Quirk confirmado: audio/mpeg e audio/mp3 são aceitos como equivalentes (samples JS do Google usam audio/mpeg).
  • +
  • Live API pricing: $0.005/min input, $0.018/min output.
  • +
  • File Search: $0.15/1M tokens. Cache storage: $1/1M tokens/hora.
  • +
  • Lib list do sandbox agora pública: inclui opencv-python, tensorflow, geopandas, openpyxl além de pandas/numpy/scipy/sympy/matplotlib/seaborn/scikit-learn etc. Matplotlib é a única lib de chart rendering.
  • +
+
+
+

Anthropic — confirmados & corrigidos

+
    +
  • Mínimo de prompt caching diverge por modelo: claude-opus-4-8 + claude-haiku-4-5 = 4.096 tokens; claude-sonnet-4-6 = 1.024 tokens.
  • +
  • Cache pricing multiplicadores: write 5m = 1,25× base input; write 1h = 2× base input; read = 0,1× base input (Opus 4.8 read therefore = $0,50/MTok).
  • +
  • document.source.type = "text" (PlainTextSource) e "content" (ContentBlockSource) agora formalmente documentados — UNVERIFIED removido.
  • +
  • Batch limits: 100k requests OU 256 MB por batch; resultados retidos 29 dias; max_tokens >= 1 obrigatório; output-300k-2026-03-24 é Batches-only e NÃO está em Bedrock/Vertex/Foundry.
  • +
  • Bedrock Converse PDF cost split: ~1k tokens (text-only) vs ~7k tokens (visual PDF) por 3 páginas — ilustra a importância de citations.enabled: true.
  • +
  • Haiku 4.5 thinking: extended-thinking sim; adaptive-thinking não.
  • +
  • ZDR matrix: PDF native = ZDR-elegível; Files API, Code Execution, Message Batches = NÃO ZDR-elegíveis.
  • +
  • Header exato code-execution-2026-01-20 ainda é UNVERIFIED: o upgrade table ainda publica só code-execution-2025-08-25; confirmar no SDK que você fixar.
  • +
+
+
+
+ Como ler estes deltas. As correções acima foram absorvidas inline no guia onde críticas (Realtime 60 min, Sora seconds 4/8/12, cache minimums por modelo, etc.). Itens marcados UNVERIFIED 2026-05-23 são onde a doc oficial divergiu ou não publicou; antes de citar publicamente, re-fetche. +
+
+ +
+

Como ler este guia

+

O guia tem quatro camadas. Comece pelo nível que se encaixa no seu uso e desça para profundidade.

+
    +
  1. Decisão rápida. Uma matriz "tenho X, quero Y → use Z".
  2. +
  3. Quadro comparativo. Tabelas lado-a-lado de imagem, PDF, Office, vídeo, áudio, code execution, Files API. É a primeira leitura de quem precisa escolher provider.
  4. +
  5. Deep-dive por provider. Três seções coloridas (verde OpenAI, azul Gemini, laranja Anthropic) com formatos aceitos, exemplos Python+TS, parâmetros, fórmulas de token, limites e gotchas.
  6. +
  7. Receitas, limitações catalogadas e fontes. Casos de uso recorrentes resolvidos nos 3 providers; catálogo cruzado de limitações; tabela com URLs oficiais usados na verificação.
  8. +
+
+ Convenções. Suportado = recurso nativo documentado. Parcial = funciona com workaround/conversão. Não suporta = ausente nas docs oficiais. N/D = depende de tier/modelo, ver nota. Itens marcados UNVERIFIED (2026-05-23) não foram confirmados na fonte oficial neste dia; antes de citar publicamente, re-fetche a doc. +
+
+ Stack padrão assumido (2026-05-23): OpenAI gpt-5.5 via Responses API; Google gemini-3.1-pro-preview/gemini-3.5-flash via google-genai; Anthropic claude-opus-4-8/claude-sonnet-4-6 via Messages API. Outros modelos são referenciados quando o comportamento diverge. +
+
+ +
+

Decisão rápida — eu tenho X, qual provider?

+

Mapeamento direto de cenários comuns para o provider/recurso mais alinhado em 2026-05-23. Onde dois são equivalentes, ambos são listados.

+
+ + + + + + + + + + + + + + + + + + + + + + +
Tenho / quero…OpenAIGeminiAnthropicObservação
Foto ou screenshot único + perguntaResponses · input_image URL/base64/file_idinlineData (≤20 MB) ou fileDataMessages · image base64/url/fileTodos suportam três modos de entrada.
OCR de texto pequeno / UI denso / computer-useIdeal detail: "original" em gpt-5.4+media_resolution: HIGH/ULTRA_HIGH (Gemini 3)Ideal Opus 4.8 (hi-res 2576 px)Em todos: levantar resolução custa tokens — meça antes.
PDF nativo com layout/chartsResponses · input_file ≤50 MBIdeal Nativo, ≤50 MB, ≤1000 páginasMessages · document ≤32 MB, 600 pgs (1M ctx)Os três renderizam página como imagem + texto.
PDF grande (>50 MB ou >1000 páginas)File Search (vector store)Cache explícito + paginaçãoFiles API (≤500 MB) + cachingAcima do limit por request, RAG/vector store é o caminho em todos.
Citações por trecho dentro do PDFFile Search annotationsPrompt com timestamps/instruçõesIdeal citations.enabled: true nativoApenas Anthropic tem citation primitive built-in.
XLSX/DOCX/PPTX com fidelidade visualConverter para PDF → input_fileConverter para PDF → inline/Files APIConverter para PDF → documentNenhum tem vision nativo para Office binário.
Análise de planilha (joins, pivots, gráficos)Code Interpreter · file_idsCode Execution · sandbox PythonCode Execution · container_uploadOs três rodam Python sandbox — diferenças em memória, network e duração.
CSV pequeno (consulta simples)input_file (até 1000 linhas processadas)Inline text/csvInline em text blockAnthropic e Gemini: enviar como texto é o atalho.
Vídeo <1 minFrame extraction (sem nativo)Ideal Inline (<20 MB) ou Files APIFrame extraction (sem nativo)Só Gemini tem ingestão de vídeo nativa.
Vídeo longo (palestra, filme)Sora 2 só gera; análise → extrair framesIdeal Files API 2GB / YouTube URLFrames + transcript externoGemini ganha de longe (até 3h em LOW res).
Transcrever áudio (STT)Ideal gpt-4o-transcribeGemini audio + Live APINão suporta nativoUse gpt-4o-transcribe/Gemini e mande transcript para Claude.
Áudio + texto em uma chamadaChat Completions input_audioInline/Files API · 32 tokens/segNão suportado nativamenteAnthropic: pré-transcrever.
Conversa de voz em tempo realRealtime API (gpt-realtime-2)Live API (gemini-3.1-flash-live-preview)Não suportadoWebSocket bidirecional nos dois primeiros.
Diarização (quem falou)gpt-4o-transcribe-diarizePrompt em gemini-3.5-flashNão suportadoOpenAI tem endpoint dedicado.
Gerar imagemgpt-image-2 via tool ou Images APIgemini-3.1-flash-imageNão suportaClaude é só image-understanding.
Gerar vídeoIdeal Sora 2 / Sora 2-Pro (até 20s)Veo 3 família (separada)Não suportaSora é o caminho principal.
Cachear PDF/imagem para re-usoPrompt caching automático (Responses)Implicit ≥1024 tk · explicit caches.createcache_control: ephemeral 5m/1hEstratégias bem diferentes — ver §9.
Batch offline multimodalBatch API (JSONL ≤200 MB)Batch · 50% off · ≤2 GB JSONLMessage Batches · 50% offDesconto similar nos três.
+
+
+ +
+

Quadro comparativo — equivalências e diferenças

+

As tabelas a seguir são a parte mais densa do guia. Cada uma cobre uma modalidade nos 3 providers. Use-as como referência de bolso; os deep-dives expandem cada célula.

+ +

3.1 Superfícies de API

+
+ + + + + + + + + + + + + + + +
ConceitoOpenAIGoogle GeminiAnthropic Claude
Endpoint principal multimodalPOST /v1/responsesPOST /v1beta/models/{m}:generateContentPOST /v1/messages
Endpoint agêntico server-side Beta—POST /v1beta/interactions · Interactions API—
SDK Pythonpip install openai · OpenAI()pip install google-genai · genai.Client()pip install anthropic · Anthropic()
SDK JS/TSnpm i openainpm i @google/genainpm i @anthropic-ai/sdk
Endpoint chat (legado)POST /v1/chat/completionsMesmo generateContentMesmo /v1/messages
Endpoint realtime / streaming bidirecionalRealtime API (WS/WebRTC)Live API (live.connect WS)Não suporta
API de upload de arquivo persistentePOST /v1/files (purpose)Files API (resumable upload)POST /v1/files (beta files-api-2025-04-14)
API de sandbox PythonPOST /v1/containers + tool code_interpreterTool code_execution (sem endpoint próprio)Tool code_execution_20250825 / _20260120
Batch / asyncPOST /v1/batches (JSONL ≤200 MB)client.batches.create (≤2 GB)messages.batches.create (50% off)
Modelo de conteúdoArray content[] tipado: input_text, input_image, input_file, input_audioPart union: text, inlineData, fileData, executableCode, videoMetadataArray content[] tipado: text, image, document, container_upload, tool_use
Header de versão / beta——anthropic-version: 2023-06-01 + anthropic-beta: ... quando aplicável
+
+ +

3.2 Modelos atuais com suporte multimodal (2026-05-23)

+
+ + + + + + + + + + + + + + + + +
ProviderModeloContextOutputImagemPDFÁudio inVídeo inCode exec
OpenAIgpt-5.5——Patch · até 10k patches @original50 MBvia Chat (gpt-audio-1.5)via framesTool code_interpreter
gpt-5.4-mini——Patch ·1536 ×1.6250 MBvia Chatvia framesSim
gpt-5.4-nano——Patch ·1536 ×2.4650 MBvia Chatvia framesSim
gpt-audio-1.5————Ideal Chat input_audio——
gpt-realtime-2————PCM16 streaming——
Geminigemini-3.1-pro-preview1M—1120 tok @media_resolution HIGH50 MB · 560 tok/pg32 tok/s70 tok/framePython sandbox
gemini-3.5-flash1M—media_resolutionIdemSimSimSim
gemini-3.1-flash-lite1M—media_resolutionIdemSimSimSim
gemini-3.1-flash-live-preview————Live API bidirLive API bidir—
Anthropicclaude-opus-4-81M128kHi-res 2576 px / 4784 tok600 pgs · 32 MBNãoNãoSim (ambas versões)
claude-sonnet-4-61M64kStd 1568 tok600 pgs · 32 MBNãoNãoSim (ambas)
claude-haiku-4-5200k64kStd 1568 tok100 pgs · 32 MBNãoNãoApenas _20250825
+
+

3.3 Imagem / visão

+

Os três providers aceitam vision input nativamente, mas divergem em MIME types aceitos, quantidade de imagens por request, tamanho máximo por arquivo, como tokenizam o pixel e como expõem coordenadas espaciais. A tabela abaixo lado-a-lado é a referência de bolso — cada célula expande no deep-dive correspondente. Observe que OpenAI usa patches 32 px (gpt-5.x; o método de tiles é legado), Gemini 3 tokeniza por media_resolution (1120 tokens em HIGH/default por imagem), e Anthropic usa a fórmula linear (W·H)/750.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
MIME types aceitos +
4 formatos +
    +
  • image/png
  • +
  • image/jpeg · .jpg
  • +
  • image/webp
  • +
  • image/gif (não-animado)
  • +
+
+
+
5 formatos +
    +
  • image/png
  • +
  • image/jpeg
  • +
  • image/webp
  • +
  • image/heic
  • +
  • image/heif
  • +
+

BMP não aceito no vision nativo.

+
+
+
4 formatos +
    +
  • image/jpeg
  • +
  • image/png
  • +
  • image/gif (só 1º frame)
  • +
  • image/webp (lossy degrada OCR)
  • +
+
+
Modos de entrada +
    +
  • input_image.image_url HTTPS
  • +
  • input_image.image_url data URL (base64)
  • +
  • input_image.file_id (Files API purpose="vision")
  • +
+
+
    +
  • inlineData (base64, ≤20 MB total)
  • +
  • fileData.fileUri (Files API)
  • +
  • fileData.fileUri HTTPS externo (≤100 MB)
  • +
  • GCS registration (files.register_files)
  • +
+
+
    +
  • source.type="base64" + media_type + data
  • +
  • source.type="url" + url
  • +
  • source.type="file" + file_id (beta files-api-2025-04-14)
  • +
+

Em Bedrock e Vertex: somente base64.

+
Máximo de imagens / request1.500 (também limita por 512 MB total)3.600 arquivos de imagem600 (modelos 1M ctx) / 100 (modelos 200k ctx)
Tamanho máximo por imagemSem cap por imagem; payload total ≤ 512 MB. Chat Completions image_url > 8 MB é silenciosamente descartado.Inline: payload total < 20 MB recomendado, ≤ 100 MB hard cap. Files API: 2 GB / arquivo, 20 GB / projeto.5 MB / imagem via API (10 MB no claude.ai UI). Request total ≤ 32 MB.
Dimensões máximas (px) + gpt-5.5 @ original: 6000 px max dim, 10.000 patches. high: 2048 px / 2.500 patches. low: forçado a 512×512. + PDF/imagem ≤ 3072×3072 (upscale para mín. 768×768, AR preservado). 384 px (1 tile) é o sweet-spot mais barato.8000×8000 px (geral); cai para 2000×2000 px se > 20 imagens no request. Long-edge reescalado: 1568 px (std) / 2576 px (Opus 4.8).
Fórmula de tokenização +
Patch (gpt-5.x, método atual) · Tile (legado) +

Patch (gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano):

+
patches = ceil(W/32) · ceil(H/32)
+billed = min(patches, budget) · multiplier
+budget: 10k (original) | 2.5k (high) | 1.5k (mini/nano)
+multiplier: 1.0 (gpt-5.5), 1.62 (mini), 2.46 (nano)
+

Tile — legado (não usado por modelos SOTA):

+
1. fit in 2048² square, AR preserved
+2. shortest side → 768 px
+3. count 512×512 tiles
+4. tokens = base + tiles · per_tile
+
+
+
Tiles 768×768 (258 tk cada) +
se W ≤ 384 e H ≤ 384:
+  tokens = 258 (1 tile)
+senão:
+  crop = floor(min(W,H)/1.5)
+  tiles = (W/crop) · (H/crop)
+  tokens = tiles · 258
+

Gemini 3 default: 1120 tk/img (HIGH); 280 (LOW); 2240 (ULTRA_HIGH per-part).

+
+
+ tokens ≈ (W · H) / 750 +

Sweet spot ~1.19 MP → ~1568 tk (std). Opus 4.8 até 4784 tk @ 2576 px long edge.

+
Parâmetro de resolução / detalhe + input_image.detail: +
    +
  • low · 512×512 (mais barato)
  • +
  • high · até 2.500 patches (gpt-5.x)
  • +
  • original · até 10.000 patches (gpt-5.4+)
  • +
  • auto · padrão; em gpt-5.5 ≡ original, em gpt-5.4 ≡ high
  • +
+
+ media_resolution (global) ou mediaResolution per-part (Gemini 3 + v1alpha): +
    +
  • MEDIA_RESOLUTION_LOW
  • +
  • MEDIA_RESOLUTION_MEDIUM
  • +
  • MEDIA_RESOLUTION_HIGH
  • +
  • MEDIA_RESOLUTION_ULTRA_HIGH (per-part, Gemini 3)
  • +
+
+ Sem parâmetro. Opus 4.8 ativa hi-res (2576 px / 4784 tk) automaticamente; demais usam std (1568 tk). Não há header beta. +
Saída de coordenadas (bounding box / points)Sem primitive nativo. Modelo retorna BBoxes via prompt, em coordenadas brutas pedidas. Sem normalização fixa.Normalizado [0, 1000] em ordem [ymin, xmin, ymax, xmax]. Suporta também pointing (1 ponto 2D), trajectories, e 3D pointing (experimental).Modelo retorna BBoxes em coordenadas da imagem pós-resize/pós-pad (múltiplo de 28 px). Cliente deve rescale para a imagem original.
Geração de imagemSim · gpt-image-2 via tool image_generation em Responses ou Images API (POST /v1/images/generations, /v1/images/edits)Sim · gemini-3.1-flash-image (Nano Banana 2)Não suporta. Apenas image-understanding.
Caveats / limitações específicas +
    +
  • CAPTCHAs bloqueados
  • +
  • EXIF/metadata nunca lidos
  • +
  • Imagens médicas: não para diagnóstico
  • +
  • Imagens contam para TPM
  • +
  • Counting é aproximado
  • +
  • Panorâmicas/fisheye fracas
  • +
+
+
    +
  • BMP não aceito (converter)
  • +
  • Verificar rotação antes
  • +
  • Texto após imagem em single-image prompts
  • +
  • Safety per-frame: vídeo pode bloquear em 1 FPS e passar em outro
  • +
+
+
    +
  • People identification recusada por AUP
  • +
  • AI-generated detection não confiável
  • +
  • Imagens base64/URL ephemeral, apagadas após response
  • +
  • EXIF não lido
  • +
  • GIF: somente 1º frame
  • +
  • Code Execution não em Bedrock/Vertex
  • +
+
+
+ +

3.4 PDF

+

PDF é o único tipo de documento em que os três providers têm vision nativo — extraem texto E rasterizam cada página como imagem, alimentando ambos ao modelo. As diferenças cruciais estão em page cap, size cap, existência de citation primitive built-in e em headers beta exigidos.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Vision nativo (texto + página como imagem)Sim em modelos com visão (gpt-5.5 e família gpt-5.x). "PDF parsing includes both extracted text and page images in context."Sim. Página renderizada como imagem + texto nativo extraído. Em Gemini 3, tokens de texto nativo são grátis.Sim. Cada página = text tokens (1.5k–3k típico) + image tokens (fórmula (W·H)/750).
Modos de entrada +
    +
  • input_file.file_id (Files purpose="user_data")
  • +
  • input_file.file_url HTTPS (Responses; não Chat)
  • +
  • input_file.file_data base64 + filename
  • +
+
+
    +
  • Inline inlineData (≤ 50 MB)
  • +
  • Files API fileData.fileUri
  • +
  • HTTPS externo fileData.fileUri (≤ 100 MB)
  • +
  • GCS registration
  • +
+
+
    +
  • source.type="base64" + media_type="application/pdf"
  • +
  • source.type="url"
  • +
  • source.type="file" + file_id
  • +
  • "text" / "content" UNVERIFIED 2026-05-23
  • +
+
Cap de tamanho por PDF50 MB por arquivo e combinado por request50 MB por PDF (inline ou Files API)32 MB request total (Bedrock/Vertex podem ser menores); 500 MB via Files API
Cap de páginas por requestUNVERIFIED 2026-05-23 — guia oficial documenta só os 50 MB; o famoso "100 páginas" não aparece no texto atual1.000 páginas (combinado entre todos os PDFs do request)600 páginas (modelos 1M ctx) / 100 páginas (modelos 200k ctx, ex. Haiku 4.5)
Estimativa de tokens por páginaTexto extraído + tokens da página-imagem (segue regra de imagem do modelo). Use count_tokens com file_id/file_url/file_data. + Gemini 3 (default): 560 tk/página (LOW=280, MEDIUM=560, HIGH=1120) + texto nativo grátis. + ~1.500–3.000 tk de texto por página + image tokens da página (pelo formula image). 100 páginas densas podem > 200k tokens.
Citation primitive built-inIndireto — File Search (vector store) retorna annotationsNão suporta primitive; cite-via-prompt (referência por número de página)Sim · citations: { enabled: true } no document block. Em Bedrock Converse, obrigatório para vision PDF.
Beta header necessário——PDF: GA sem header. file_id source: files-api-2025-04-14 obrigatório.
Caminho para PDFs > capFile Search (vector store; até 10k arquivos ou 100M em stores criados de Nov/2025)Cache explícito (caches.create) + paginação manual / splitFiles API (500 MB) + prompt caching ephemeral 5m/1h + split em chunks
Restrições adicionaisModelos pré-4o não veem imagens das páginas (só texto)Senha/criptografia UNVERIFIED 2026-05-23; outros doc MIME (HTML, MD, RTF) vão como texto puro — perde layoutSem PDFs com senha/criptografia; coloque PDF antes do texto no content; cite por número de página do viewer
+
+ +

3.5 Office, Excel, CSV e documentos estruturados

+

Nenhum dos três providers tem vision nativo para formatos Office binários (DOCX/PPTX/XLSX). A estratégia universal é (a) converter para PDF quando fidelidade visual importa, (b) mandar como texto inline para CSV/TXT/MD pequenos, ou (c) delegar para o sandbox Python (Code Interpreter / Code Execution) para tabular analytics. A tabela abaixo mostra como cada provider trata cada família.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FormatoOpenAIGoogle GeminiAnthropic Claude
.docx · .doc · .rtf · .odt + input_file: extrai texto somente; imagens/charts não extraídos. Converter para PDF se charts importam. +

Parcial · text-only path

+
+ Sem vision nativo. Files API armazena, modelo lê como texto. UNVERIFIED 2026-05-23 para vision em DOCX. +

Converter para PDF antes (LibreOffice, etc.)

+
+ Caminho oficial: converter para PDF e usar document block para manter parsing de imagens + citations. Alternativa: container_upload + sandbox com python-docx. +
.pptx · .ppt · Keynote · Google Slides + input_file: texto somente. Sem extração de slide visual. Converter para PDF para preservar visuais. + + Sem vision nativo. Converter para PDF. + + Mesmo caminho: PDF para visual fidelity, ou container_upload + python-pptx no sandbox. +
.xlsx · .xls + input_file: spreadsheet augmentation — parseia até 1.000 linhas / sheet + header/summary metadata. Sem vision em células. +

Para joins/pivots/charts: Code Interpreter ou Hosted Shell.

+
+ Code Execution é o caminho oficial. Upload via Files API, prompt: pandas.read_excel(...). UNVERIFIED 2026-05-23 para vision nativo em XLSX. + + Code Execution obrigatório. container_upload + tool code_execution_20250825 + openpyxl/xlrd/pyarrow pré-instalados. +
.csv · .tsv · .iif + input_file (mesma augmentation de 1.000 linhas) para consultas simples; Code Interpreter para tudo que precise > 1.000 linhas ou cálculos. Aceito também como text/csv. + + Inline text/csv é o atalho para CSV pequeno (model lê raw); Code Execution para grandes. + + Inline em text block (recomendado para CSV/TXT/MD pequenos): f.read() → {"type": "text", "text": csv_text}. Para grande: container_upload + pandas.read_csv. +
.txt · .md · .html · .xml · .json · código-fonte + input_file: extrai texto puro. Suporta dezenas de extensões (.c, .py, .java, .cpp, .cs, .rb, .php, .ts, .tex, ...). + + Inline como text/plain, text/html, application/json, text/markdown, text/css, text/xml, etc. Sem layout. + + text/plain → block document via Files API; .md/.html/.json/código → inline text block é o padrão. +
Quando Code Execution / Code Interpreter é exigido + Spreadsheets > 1.000 linhas; joins, pivots, regressions, plots; OCR-style em XLSX (não suportado vision-nativo). + + XLSX, DOCX, PPTX vision-grade; qualquer tabular analytics > tamanho cabível em context; chart generation. + + Sempre para XLSX/DOCX/PPTX e CSV grandes. container_upload é a única forma de "mountar" binário no sandbox. +
Caveat principalNão há vision pipeline para XLSX renderizado. Converter sheet → PDF se cores/células/imagens embarcadas importam.Vision Gemini é engineered for PDF; outros formatos perdem fidelidade visual.Code Execution é not ZDR-eligible e retém dados até 30 dias. Sem network outbound no sandbox.
+
+ +

3.6 Vídeo

+

Vídeo é a modalidade onde os três providers mais divergem. Apenas Gemini tem ingestão de vídeo nativa (com URLs de YouTube, clipping, FPS configurável e horas em contexto). OpenAI tem geração via Sora 2 mas não entrada; Anthropic não tem nenhum dos dois. O workaround em OpenAI e Anthropic é extração de frames + transcript externo.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Input de vídeo nativoNão suporta em Responses/Chat. UNVERIFIED 2026-05-23 — sem input_video content type. Realtime tem gpt-realtime-translate (live video translation) mas sem stream content type geral.Sim, nativo. video/* MIMEs: mp4, mpeg, mov, avi, x-flv, mpg, webm, wmv, 3gpp.Não suporta. UNVERIFIED 2026-05-23 — nenhum beta de vídeo nas docs públicas.
Cap inline—Recomendado < 20 MB; hard cap 100 MB por payload—
Cap via Files API—2 GB por arquivo; 20 GB por projeto; retenção 48 h—
URL pública / YouTubeNão suporta para inputYouTube nativo via fileData.fileUri = "https://www.youtube.com/watch?v=...". Free tier: ≤ 8h/dia. Paid: sem limit. Apenas vídeos públicos. Até 10 vídeos / request.Não suporta
Controle de FPS / samplingManual (extrair frames com OpenCV/ffmpeg)videoMetadata.fps (default 1.0). UNVERIFIED 2026-05-23 range exato; valores observados 0.1–~24.Manual (ffmpeg)
Trim / clipping—videoMetadata.startOffset / endOffset (string "1250s")—
Duração máxima em contexto—Em modelo de 1M tokens: 1 hora (default media_resolution); 3 horas (LOW)—
Token rate por segundo— + Gemini 3: 70 tk/frame (UNSPECIFIED/LOW/MEDIUM) ou 280 (HIGH).
+ Baseline count_tokens (estimativa genérica): 258 tk/frame @ 1 FPS + áudio 32 tk/s → ~300 tk/s; LOW: 66 tk/frame + 32 tk/s → ~100 tk/s. +
—
Workaround sem ingestão nativaFrame extraction (OpenCV/ffmpeg) → enviar como input_image[] + audio.transcriptions.create separado. O cookbook de visão da OpenAI chama isso de padrão "Visual + Audio Summary".—Frame extraction + transcript externo. Até 600 frames @ Opus 4.8. Files API para reuso.
Geração de vídeoSora 2 / Sora 2-Pro via POST /v1/videos. API ref: seconds ∈ {4, 8, 12} (default 4); cookbook menciona 16/20 (verify). Extensões até 6 × 20s = 120s; sora-2-pro 1080p @ $0.70/s; também aceita 1024x1792/1792x1024. URL válida 1h (24h em batch). Sem people, copyrighted chars, ou faces humanas como ref.Veo família (separada do generateContent; ver Vertex/Veo docs).Não suporta
Safety / restriçãoSora: no real people / copyrighted / NSFW / faces as ref. Batch: JSON only, sem multipart.Per-frame safety: vídeo pode bloquear em 1 FPS e passar em outro FPS (frames diferentes amostrados).—
+
+ +

3.7 Áudio

+

Áudio é a modalidade com maior assimetria entre os providers. OpenAI tem três superfícies dedicadas (Chat input_audio, Audio API, Realtime); Gemini tem ingestão nativa via generateContent + Live API; Anthropic não tem áudio nativo. Diarização tem caminhos específicos.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Input de áudio nativo (em chat) + Chat Completions com input_audio.{data, format} em gpt-audio-1.5. Responses: Coming soon conforme Migrate matrix. + + Sim via inlineData ou fileData em generateContent. Modelos gemini-3.x entendem fala, música, sons ambientais, emoção. + Não suporta. Pré-transcrever externamente (Whisper / Gemini / Deepgram) e mandar como text block.
MIME types aceitos +
Transcription/translation (Audio API) +
    +
  • flac
  • +
  • mp3
  • +
  • mp4
  • +
  • mpeg
  • +
  • mpga
  • +
  • m4a
  • +
  • ogg
  • +
  • wav
  • +
  • webm
  • +
+

Chat input_audio: tipicamente wav/mp3. Realtime: PCM16 24 kHz mono LE / g711_ulaw / g711_alaw (sem MP3/Opus).

+
+
+ audio/wav, audio/mp3, audio/aiff, audio/aac, audio/ogg (Vorbis), audio/flac. audio/mpeg ≡ audio/mp3 UNVERIFIED 2026-05-23. + N/D
Token rate por segundoPer-input/output token (audio + text streams) — taxas separadas em gpt-audio-1.5 e Realtime. Audio API gpt-4o-transcribe: per-minute (rate) + token output.32 tokens / segundo. 1 min → 1.920 tk. 1 h → 115.200 tk. Multi-canal mixado para mono; downsample para 16 Kbps.N/D
Length máximoTranscription/translation upload: 25 MB. Realtime session: 60 minutos (chunks ≤ 15 MB). Whisper-1 prompt: 224 tk.9,5 horas combinadas por request, sem cap por arquivo individual.N/D
Endpoints de transcrição (STT) + POST /v1/audio/transcriptions + POST /v1/audio/translations. Modelos SOTA: gpt-4o-transcribe, gpt-4o-mini-transcribe (snapshot gpt-4o-mini-transcribe-2025-12-15), gpt-4o-transcribe-diarize. whisper-1 é legado mas necessário: única opção em /v1/audio/translations e para os formatos srt/vtt/verbose_json + timestamp_granularities (word/segment). Formatos de saída: json, text, srt, verbose_json, vtt, diarized_json. + + Via generateContent com prompt de transcrição (não-realtime). Para realtime: Live API ou Google Cloud Speech-to-Text. Suporta timestamp-anchored ("transcribe from 02:30 to 03:29"), translation, emotion. + Não tem endpoint próprio. Use Whisper / Gemini para STT, depois mande para Claude.
Streaming bidirecional / Realtime + Realtime API via WebSocket/WebRTC. Modelos: gpt-realtime-2, gpt-realtime-mini, gpt-realtime-translate, gpt-realtime-whisper. Eventos: input_audio_buffer.append, response.output_audio.delta, server VAD. + + Live API (client.aio.live.connect). Modelo: gemini-3.1-flash-live-preview. WebSocket; audio in/out + video in + text out + tool calls. Resumption ≤ 24 h. + Não suporta
Diarização (quem falou) + Endpoint dedicado gpt-4o-transcribe-diarize. Até 4 known speakers via known_speaker_names[] + known_speaker_references[] (clips 2–10s data URLs). chunking_strategy obrigatório para input > 30s. Sem prompt/logprobs/timestamps. Não disponível em Realtime. + Via prompt em gemini-3.5-flash (structured JSON com speaker field). Sem endpoint dedicado.Não suporta nativo. Pré-processar com Whisper-diarize ou Pyannote.
Saída de áudio (TTS)POST /v1/audio/speech (modelo dedicado gpt-4o-mini-tts; vozes recomendadas marin, cedar) e família gpt-realtime-* para áudio em tempo real. Chat Completions com modalities:["text","audio"] e audio.{voice, format}.Modelo TTS dedicado: gemini-3.1-flash-tts-preview. generateContent sozinho retorna texto, não áudio.Não suporta
+
+ +

3.8 Code execution / Code Interpreter

+

Os três providers oferecem sandbox Python server-side, mas com arquiteturas e quotas radicalmente diferentes. OpenAI expõe Containers como recurso REST com tiers de memória; Gemini embute o sandbox como tool sem endpoint próprio; Anthropic versiona o tool e cobra por hora de container com cota mensal grátis. Cada um tem seu próprio modelo de upload e retorno de arquivos.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Tool name(s){"type": "code_interpreter"} em Responses, Chat Completions, Assistants. Também chamado "python tool" internamente pelo modelo.types.Tool(code_execution=types.ToolCodeExecution). Sem endpoint REST próprio; sub-tool de generateContent. + {"type": "code_execution_20260120", "name": "code_execution"} (Opus 4.8, Sonnet 4.6; REPL state + programmatic tool calling)
+ {"type": "code_execution_20250825", ...} (todos os modelos; Bash + file ops + Python)
+ code_execution_20250522 (legacy: Python only)
+ Sub-tools: bash_code_execution, text_editor_code_execution. +
Linguagem(ns)Python (sandbox). Modelo pode escrever outras línguas como texto, mas só executa Python.Python onlyPython 3.11.12 + Bash + file ops
Tiers de memória / quotasmemory_limit: "1g" (default), "4g", "16g", "64g". Fixo no ciclo de vida do container. Tiers maiores cobram mais.Limitado pela janela de contexto do modelo (1M tk ≈ ~2 MB de texto em AI Studio).5 GiB RAM, 1 vCPU. Fixo, não-configurável.
Disco / workspaceEphemeral block storage; tamanho não publicado.Workspace dentro do sandbox; sem cap explícito.5 GiB workspace. Workspace dir only file access.
Network outboundDesabilitado por default. Em 2026 abriu networking opcional (Hosted Shell tier).Disabled. Sandbox sem rede outbound — pip install falha.Disabled. pip install de PyPI falha; pré-instaladas cobrem maioria.
Container lifetime20 minutos idle → expira. Qualquer op (retrieve/add/delete) reseta last_active_at. Files e in-memory state somem na expiração.Scope: dentro de uma chamada / chat (não expõe container_id ao caller). Sandbox recriado entre turns a menos que reuse via SDK.30 dias após criação. Reuse via container=<id> em request seguinte. Bound a workspace da API key.
Upload de arquivos para o sandbox +
    +
  • Em tools[].container: {"type":"auto", "file_ids":["..."]}
  • +
  • POST /v1/containers/{id}/files (multipart ou JSON com file_id)
  • +
  • GET /v1/containers/{id}/files lista
  • +
+
+ Upload via Files API → enviar como fileData ou inlineData dentro de contents; sandbox monta o arquivo no workspace. Não há endpoint container/files separado. + + container_upload block com file_id (da Files API + beta files-api-2025-04-14). Modelo discovera caminho via ls no bash_code_execution. +
Output retrieval + Annotation container_file_citation em output_text. Download via GET /v1/containers/{id}/files/{file_id}/content. + + Arquivos gerados retornam como inlineData nas parts da resposta (charts matplotlib como PNG/JPEG base64). + + file_ids aparecem aninhados em bash_code_execution_tool_result.content.content[]. Download via client.beta.files.download(file_id); arquivos criados pelo Claude têm downloadable: true. +
Pre-installed libraries +
MIMEs aceitos + bibliotecas +

Sandbox aceita: .c, .cs, .cpp, .csv, .doc, .docx, .html, .java, .json, .md, .pdf, .php, .pptx, .py, .rb, .tex, .txt, .css, .js, .sh, .ts, .jpeg, .gif, .png, .pkl, .tar, .xlsx, .xml, .zip.

+

Bibliotecas específicas não publicadas; assume stack data-science padrão (pandas, numpy, matplotlib, scipy, etc.).

+
+
+ UNVERIFIED 2026-05-23 — lista completa não publicada exaustivamente. Historicamente: numpy, pandas, matplotlib, scipy, sympy, seaborn, Pillow, scikit-learn, chess, tabulate, mpmath. + +
Lista oficial (extensa) +
    +
  • Data science: pandas, numpy, scipy, scikit-learn, statsmodels
  • +
  • Visualização: matplotlib, seaborn
  • +
  • File processing: pyarrow, openpyxl, xlsxwriter, xlrd, pillow, python-pptx, python-docx, pypdf, pdfplumber, pypdfium2, pdf2image, pdfkit, tabula-py, reportlab[pycairo], Img2pdf
  • +
  • Math: sympy, mpmath
  • +
  • Utilities: tqdm, python-dateutil, pytz, joblib, unzip, unrar, 7zip, bc, rg (ripgrep), fd, sqlite
  • +
+
+
Tempo limite por execução—30 segundos wall-time por invocação. Auto-retry: até 5 vezes em um turn.—
Rate limit100 RPM / org——
Pricing modelBilled at built-in-tools rate. Tiers maiores de memory_limit custam mais. Desde 02/06/2026, o tempo de container é cobrado por minuto, com mínimo de 5 min por sessão (antes: blocos de 20 min). ZDR honrado.Não-separately-metered. Paga input + output tokens no rate do modelo. Código gerado, charts gerados e stdout contam como output tokens. + $0.05/hora/container após 1.550 horas grátis/org/mês. Mínimo 5 min por sessão. Free quando combinado com web_search ou web_fetch. Não ZDR-eligible. Containers em paralelo: 10×min(5min, real) cada. +
Disponibilidade em cloudsDisponível em todas as APIs (Responses, Chat, Assistants).Gemini API; Vertex AI (verificar paridade exata por região).Não disponível em Amazon Bedrock ou Vertex AI. Apenas Claude API direto, Claude Platform on AWS, e Microsoft Foundry.
+
+ +

3.9 Files API

+

Os três providers oferecem Files API para upload persistente e reuso. As diferenças importantes são per-file cap, quota total por projeto/org, retenção (alguns expiram automaticamente), se você pode baixar de volta o que subiu, e a existência de "purposes" / categorias.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Endpoints +
    +
  • POST /v1/files
  • +
  • GET /v1/files
  • +
  • GET /v1/files/{id}
  • +
  • DELETE /v1/files/{id}
  • +
  • GET /v1/files/{id}/content
  • +
+
+
    +
  • POST upload/v1beta/files (resumable multipart)
  • +
  • GET /v1beta/files
  • +
  • GET /v1beta/files/{name}
  • +
  • DELETE /v1beta/files/{name}
  • +
  • files.register_files (GCS, sem re-upload)
  • +
+

Sem download endpoint.

+
+
    +
  • POST /v1/files (multipart)
  • +
  • GET /v1/files
  • +
  • GET /v1/files/{id}
  • +
  • GET /v1/files/{id}/content (só para arquivos criados pelo Claude)
  • +
  • DELETE /v1/files/{id}
  • +
+
Cap por arquivo512 MB por arquivo2 GB por arquivo500 MB por arquivo
Quota total (org / projeto)2,5 TB por projeto. Org-wide: sem limit (conta no projeto).20 GB por projeto500 GB por organização
Retenção / expiraçãoPersiste até delete. expires_after param TTL opcional UNVERIFIED 2026-05-23. Batch outputs: 30 dias. Sora download URLs: 1h (24h em batch). Container files: 20 min idle.48 horas auto-delete. GCS registration: até 30 dias de validade.Persiste até delete. Container files: 30 dias (Code Execution).
Purposes / categorias + purpose obrigatório: +
    +
  • assistants · Assistants v2 (vector store, code_interpreter)
  • +
  • vision · imagens via file_id
  • +
  • batch · JSONL Batch API (≤200 MB)
  • +
  • fine-tune · training data
  • +
  • user_data · model inputs via input_file (default)
  • +
  • evals · datasets para Evaluations
  • +
+
Sem campo purpose. MIME detectado automaticamente. State machine: PROCESSING → ACTIVE / FAILED.Sem campo purpose. MIME detectado e mapeado para content block: application/pdf → document; text/plain → document; image/* → image; outros → container_upload.
Rate limit1.000 requests/min/user. Vector store: 2.000 attached files/min/org.—~100 RPM (beta-level)
Download semanticsGET /v1/files/{id}/content retorna bytes raw. Funciona para todos os arquivos.Download não suportado. Só metadata.downloadable: true somente em arquivos criados pelo Claude (via Code Execution / Skills). Arquivos uploaded pelo usuário não podem ser baixados.
Beta header——anthropic-beta: files-api-2025-04-14 obrigatório em todo request que mencione file_id (upload, source file, container_upload).
CustoOperações: free. Content em request: standard input-token pricing.Free em todas as regiões da Gemini API.Operações: free. Content em messages.create: standard input-token pricing.
Escopo de visibilidadeProjeto OpenAI. Service accounts e API keys herdam.Projeto GCP / Gemini API key.Workspace Anthropic — qualquer API key do mesmo workspace pode ver/deletar qualquer arquivo. Trate como compartilhado.
Outros caveatsVector stores: até 10k arquivos (ou 100M para stores criados de Nov/2025). Combined input_file payload: ≤ 50 MB por request.Large media inicia em PROCESSING; aguardar ACTIVE antes de usar em generateContent.Filename: 1–255 chars, sem < > : " | ? * \ / ou unicode 0–31. Not ZDR-eligible (Files API). PDF support: ZDR-eligible (separado).
+
+ +

3.10 Caching / Context caching

+

Cache de prefixo é uma alavanca de custo importante quando você reusa grandes contextos (PDFs, imagens, instruções). As três estratégias diferem: OpenAI faz caching automático em Responses (sem opt-in explícito); Gemini tem dois modelos (implicit grátis + explicit via caches.create); Anthropic exige opt-in explícito via cache_control: ephemeral em cada bloco cacheável.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Mecanismo (automático vs explícito) + Automático (Responses API e Chat). Prompt caching aplicado quando prefixo se repete entre requests recentes. Sem campo de opt-in no body. + + Ambos: +
    +
  • Implícito (default nos modelos atuais): automático ao bater prefixo com request recente.
  • +
  • Explícito via client.caches.create(...) + cached_content=cache.name.
  • +
+
+ Explícito. Anexar cache_control: { type: "ephemeral", ttl: "5m" | "1h" } em image, document, text, tool def ou tool result block. Até 4 breakpoints por request. +
Tamanho mínimo cacheávelUNVERIFIED 2026-05-23 — taxa de hit reportada em usage.input_tokens_details.cached_tokens (Responses API; Chat Completions: usage.prompt_tokens_details.cached_tokens). + Implicit cache mín. tokens: +
    +
  • Gemini 3 Pro Preview: 4.096 tk
  • +
  • Gemini 3 Flash Preview: 1.024 tk
  • +
+ Explicit: sem mínimo, sem máximo. +
Pragmaticamente ~1.024 tokens de prefixo (refer to canonical caching docs). UNVERIFIED 2026-05-23 para a tabela exata atual.
TTL optionsGerenciado automaticamente; não exposto.Explicit: default 1 hora, sem mínimo nem máximo. Configurável (ttl="300s", etc.). Update via caches.update."5m" (default) ou "1h".
Fator de custo (cache read)Tokens cacheados aparecem em usage.input_tokens_details.cached_tokens (Responses) ou usage.prompt_tokens_details.cached_tokens (Chat Completions) a rate reduzido (verificar pricing page).Explicit: ~90% de desconto em cached input tokens + cobrança prorrateada de storage por TTL. Implicit: pass-through savings (até 75–90%).Reduced rate em cache reads — verificar canonical caching docs para fator exato. Inspecione usage.cache_creation_input_tokens e cache_read_input_tokens.
Modalidades suportadas no cacheTexto + imagem (Responses prompt caching). Aplica a prefixos de qualquer modalidade aceita. + Tudo: texto, imagem, PDF, áudio, vídeo. Exemplos oficiais cachêam vídeos longos (Sherlock Jr. 10 min) e PDFs grandes via Files API. Ideal para vídeos > 10 min reusados em múltiplos prompts. + + image, document (PDF + text/plain), text, tool def, tool result. Não comum em container_upload. +
Posicionamento / ordemColoque conteúdo grande/estável no início do prompt para maximizar cache hits.Conteúdo grande/comum (system instruction, PDF, vídeo) no início. Implicit cache exige prefixo idêntico.Prefix-keyed: system → tools → docs/images → user dynamic. Qualquer mudança antes do breakpoint invalida tudo após.
Inspeção do cacheRead-only via usage stats. Sem API de listagem.Explicit: caches.list(), caches.get(); conteúdo não pode ser inspecionado/lido de volta, apenas metadata.Não-inspecionável. Apenas counters em usage.cache_*.
Casos de uso ideais + Mesmo system prompt grande reusado; mesmo PDF/imagem em multi-turn; agentic loops com tool schema grande. + + Chatbots com system instructions grandes; análise repetitiva de vídeo longo; queries recorrentes sobre PDFs grandes; análise frequente de repo de código. + + Mesmo PDF, muitas perguntas (Q&A analyst-style); mesmo screenshot, muitos prompts diagnósticos; tool schema grande reusado em loops. +
Quando NÃO cachear—Se prefixo muda a cada request: explicit cache só adiciona storage cost sem savings. Use implicit.—
+
+ +

3.11 Coding tool, ZDR e onde roda o Python — síntese de decisão

+

Esta subseção consolida 3.5 + 3.8 + 3.9 em um único quadro de decisão para três perguntas operacionais que aparecem juntas em quase todo projeto multimodal: "Para mandar um arquivo, preciso ativar coding tool? Isso é ZDR? Onde o Python realmente roda?". Cobre os quatro modos de entrega (inline, Files API, File Search/RAG, code execution), a posição por provider, ZDR cruzado, sandbox lado a lado, reupload por modo, fluxo recomendado para Excel e disponibilidade em clouds gerenciadas.

+ +
+ TL;DR em três linhas.
+ ① Só quer ler/resumir/perguntar? Não precisa coding tool — inline, Files API ou File Search resolvem.
+ ② Quer manipular de verdade? (joins, pivots, gerar arquivo, calcular margem, plotar) — precisa coding tool do provider ou Python no seu backend.
+ ③ Compliance ZDR estrito? Faça o cálculo determinístico no seu backend e mande ao modelo só schema + amostra + erros + objetivo — evite Files API persistente, explicit cache e code execution server-side onde não for ZDR-elegível. +
+ +

3.11.1 Resumo executivo — quatro modos de entregar arquivo ao modelo

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModoO que aconteceExige coding tool?Bom para
Inline / Base64 no requestArquivo viaja junto com a chamada; cada request carrega os bytes.NãoUso único, arquivo pequeno, footprint mínimo (melhor caminho sob ZDR).
Files API / File APIArquivo fica armazenado (temporário ou até deletar) e você referencia por file_id / URI.Não, por si sóReuso em várias chamadas; arquivos que não cabem inline.
File Search / RAGArquivo vira chunks + embeddings em um store; modelo pergunta ao índice.NãoPerguntas sobre documentos grandes; reuso recorrente.
Code execution / Code InterpreterModelo escreve Python (e/ou Bash, na Anthropic) e roda em sandbox do provider.SimAnálise real de planilha, cálculos determinísticos, gráficos, geração/edição de arquivos.
+
+ +

3.11.2 Posição de cada provider quando o arquivo é uma planilha

+
+ + + + + + + + + + + + + + + + + + + +
ProviderComportamento "só ler / resumir"Quando exige coding tool
OpenAI + input_file aceita Base64, file_id da Files API ou URL externa. PDF é processado extraindo texto + imagens das páginas; documentos não-PDF extraem texto. Para spreadsheets (.xlsx, .xls, .csv, .tsv, .iif) a API aplica spreadsheet augmentation: parseia até as primeiras 1.000 linhas por aba e adiciona "summary and header metadata". Para arquivos não-PDF, imagens e gráficos embutidos NÃO são extraídos para o contexto — converter para PDF se a fidelidade visual importa. Combined input_file payload: ≤ 50 MB por arquivo e por request. + + Quando precisa de agregações, joins, gráficos, cálculos custom, > 1.000 linhas, a própria doc (file-inputs) recomenda Hosted Shell — umbrella oficial sobre o Code Interpreter / "python tool" ({"type":"code_interpreter"}). Também recomenda File Search em vez de input_file direto quando o arquivo é grande demais para retrieval. +
Gemini + Quatro modos: inline data (até 100 MB por payload, 50 MB para PDF), File API upload (até 2 GB/arquivo, armazenado por 48 horas), GCS URI registration (registro pode conceder acesso por até 30 dias) e External URL (HTTPS pública, S3/Azure presigned; 100 MB/payload). A lista oficial de External-URL inclui texto/CSV/JSON/PDF/imagens/vídeo — não inclui .xlsx nativamente. Para Excel como RAG, o File Search aceita application/vnd.ms-excel e application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; embeddings não têm TTL e persistem até deleção, enquanto o arquivo bruto expira em 48 h. + + Para manipular o arquivo, ative types.Tool(code_execution=types.ToolCodeExecution). Sandbox Python-only, runtime de 30 segundos por invocação, até 5 retries em um turn, input via inlineData ou fileData, output via inlineData. Pré-instaladas: pandas, numpy, matplotlib, openpyxl, python-docx, python-pptx, xlrd entre 37 libs — não pode pip install (sem rede outbound). +
Anthropic + Files API entrega file_id reusável (beta header files-api-2025-04-14 obrigatório). Mapeamento de bloco: application/pdf e text/plain viram document; imagens viram image; .csv, .docx, .xlsx NÃO são tratados como document blocks comuns. Para esses, ou (a) converter para texto e enviar inline em bloco text, ou (b) usar code execution com container_upload. Uploads do usuário não podem ser baixados de volta via API. + + Para Excel/DOCX/PPTX o caminho prático é Files API → container_upload → tool code_execution_20250825 (todos os modelos; Python + Bash + file ops) ou code_execution_20260120 UNVERIFIED (2026-05-23) (Opus 4.8, Sonnet 4.6; soma persistência REPL no turno + tool calling programático). Sandbox Linux x86_64, Python 3.11.12, 5 GiB RAM, 5 GiB workspace, 1 vCPU, sem internet; libs incluem pandas, numpy, matplotlib, openpyxl, xlsxwriter, xlrd, python-pptx, python-docx, pypdf, pdfplumber. Container reusável por container_id por até 30 dias após criação. +
+
+ +

3.11.3 Isso é ZDR? — não confundir "API não treina com meus dados" com Zero Data Retention

+

"API não treina por padrão" e "Zero Data Retention" são coisas diferentes. Treinamento e logging operam em planos distintos; cada provider tem regras próprias de elegibilidade por endpoint/feature. Estado oficial 2026-05-23 abaixo.

+
+ + + + + + + + + + + + + + + + + + + +
ProviderTreinamento por padrãoZDR com arquivo / código
OpenAI + "data sent to the OpenAI API is not used to train or improve OpenAI models (unless you explicitly opt in to share data with us)". Por padrão, abuse-monitoring logs são gerados e retidos por até 30 dias. + + /v1/responses é ZDR-eligible com limitações: sob ZDR, store é tratado como false. /v1/files é "No" na tabela ZDR e mantém application state até deleção. Hosted Shell / Code Interpreter podem escrever estado temporário no filesystem do container enquanto ele estiver ativo; o estado é apagado quando o container expira ou é deletado. Pegadinha Background mode retém dados ~10 min (quebra ZDR se usado); MCP servers são third-party e ficam fora de ZDR; image/file inputs em /v1/responses passam por CSAM scan e podem ser retidos para revisão mesmo sob ZDR/MAM. +
Gemini + Para Paid Services: "Google does not use your prompts (including associated system instructions, cached content, and files such as images, videos, or documents) or responses to improve our products". + + Para ZDR real: prompts/responses podem ser logados por tempo limitado para abuse; ZDR precisa ser aprovado por projeto; Interactions API deve usar store=false; File API storage é INDEPENDENTE do ZDR logging — os arquivos ficam armazenados até expirar (48 h) ou serem deletados manualmente; explicit caching (cached_content) deve ser evitado para footprint zero absoluto. Pegadinha crítica Grounding com Google Search/Maps SEMPRE retém prompts/output por 30 dias, SEM opt-out. OK sob ZDR Implicit caching em RAM (24 h TTL) não viola ZDR. +
Anthropic + Dados retidos não são usados para treinamento sem permissão expressa. + + PDF support nativo é ZDR-elegível. Files API NÃO é ZDR-elegível — segue retenção padrão; arquivos persistem até deleção explícita. Code Execution NÃO é ZDR-elegível — dados do container (uploads, artefatos, outputs) retidos por até 30 dias. Message Batches também NÃO é ZDR-elegível. Uploads pelo usuário não podem ser baixados de volta via API; só arquivos criados por skills/code execution têm downloadable: true. +
+
+
+ Arquitetura realmente ZDR / zero-footprint: evite Files API persistente, File Search store, caches explícitos e code execution server-side quando não forem elegíveis. Envie conteúdo inline quando couber, use store=false onde aplicável (Gemini Interactions API; OpenAI Responses sob ZDR já trata como false automaticamente), e faça processamento determinístico no seu backend para a parte sensível. +
+ +

3.11.4 Onde o Python efetivamente roda?

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
ProviderLocal de execuçãoPersistência / reuso
OpenAIContainer sandbox da OpenAI associado ao Code Interpreter / Hosted Shell. Não é o seu servidor.Auto-mode: container reusável dentro de 20 min idle; depois expira e perde estado e arquivos. Explicit mode: criar via POST /v1/containers e passar container_id. Arquivos no input do modelo são auto-uploaded ao container — não precisa subir manualmente.
GeminiSandbox do Gemini code execution, Python only, sem rede outbound, sem instalação de libs próprias.Sem container_id público ao caller — escopo é a chamada / chat. Runtime 30 s por invocação; até 5 retries automáticos em um turn. Apenas matplotlib consegue devolver charts inline (inlineData PNG/JPEG).
AnthropicContainer server-side da Anthropic com Python 3.11.12 + Bash + file ops; sem internet; 5 GiB RAM / 5 GiB workspace / 1 vCPU fixos.Container reusável por container_id por até 30 dias após criação; arquivos criados persistem entre requests no mesmo container. code_execution_20260120 adiciona persistência REPL dentro do turn + tool calling programático de dentro do sandbox.
Seu backendPython local em servidor sob seu controle.Persistência e auditoria 100% suas. Opção mais controlável para compliance, logs, determinismo, versionamento e validação.
+
+
+ Recomendação técnica: se o resultado precisa ser determinístico, auditável e sensível a compliance, rode Python no seu backend com pandas/openpyxl e mande ao modelo apenas o resumo / tabelas / erros detectados / objetivo da análise. Use code execution do provider para análise ad hoc, prototipagem, exploração e geração rápida de gráficos/arquivos quando a política de retenção for aceitável. +
+ +

3.11.5 O arquivo precisa estar no input toda vez?

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
ModoReupload?O que basta enviar nas chamadas seguintes
Inline / Base64SimO arquivo viaja em cada request em que for usado.
Files API (OpenAI / Anthropic / Gemini)NãoReferenciar por file_id / fileData.fileUri na chamada que precisa dele. O arquivo não vira contexto eterno automaticamente; é preciso citá-lo explicitamente em cada request.
Code execution — container reusadoDependeSe o arquivo já está no mesmo container ativo, basta reusar o container. OpenAI: container auto expira após 20 min idle. Anthropic: container vive 30 dias, reusável por container_id. Gemini: sem container persistente entre requests para o caller.
File Search / RAGNãoO arquivo bruto pode expirar (Gemini: 48 h), mas o índice/embeddings persiste no store até deleção (Gemini File Search: sem TTL; OpenAI vector stores: persistentes; Anthropic: RAG externo, sem File Search nativo na Messages API).
+
+
+ Regra prática para produção: mantenha o estado real no seu banco/storage. Trate file_id, container_id ou store_id como ponte temporária, não fonte primária de verdade. Cada provider tem retenções diferentes e o que está no provider pode expirar sem aviso útil para o seu app. +
+ +

3.11.6 Fluxo recomendado para Excel — árvore de decisão

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CenárioOpenAIGeminiAnthropic
Pergunta simples ("resuma essa planilha", "quais colunas existem?")input_file aproveita spreadsheet augmentation (primeiras 1.000 linhas/aba + summary/header).CSV inline (text/csv) funciona bem; XLSX nativo na vision é limitado — preferir File Search ou converter.Converter para CSV/texto e mandar inline em bloco text; XLSX direto exige container_upload.
Operações reais (joins, pivots, margem por SKU, gerar gráfico, devolver .xlsx)code_interpreter (Hosted Shell); arquivos no input são auto-encaminhados ao container (container.type=auto + memory_limit).code_execution tool — upload via Files API + prompt com pandas.read_excel(...); chart volta como inlineData.container_upload + code_execution_20250825 (ou _20260120 para REPL persistente); openpyxl/xlsxwriter/pandas já pré-instalados.
Determinismo + compliance estritoRode Python no seu backend com pandas/openpyxl; envie ao modelo apenas schema, amostra, estatísticas, erros detectados e o objetivo da análise.
Análise exploratória assistidaCode Interpreter / Hosted Shell, aceitando retenção do container (20 min idle / até deleção).Code execution; respeitar 30 s/invocação e até 5 retries.Code Execution, aceitando retenção de até 30 d do container.
ZDR estritoInline em /v1/responses (sob ZDR, store é tratado como false automaticamente). Evitar /v1/files (não é ZDR-eligible).Inline com store=false na Interactions API. Evitar File API persistente, explicit cache e Grounding com Google Search/Maps (retém 30 d sem opt-out).PDF nativo (ZDR-elegível) ou inline em text block. Não usar Files API nem Code Execution (nenhum é ZDR-elegível).
+
+ +

3.11.7 Disponibilidade do coding tool e Files API em clouds gerenciadas

+

Antes de desenhar arquitetura, valide se a superfície que você precisa existe na cloud onde sua org consome o provider. Em particular, nem todo recurso server-side do provedor direto é exposto em Bedrock, Vertex AI ou Foundry — e a ausência é frequentemente bloqueante para o caminho "envie XLSX, peça pivot, devolva CSV".

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Provider · RecursoAPI diretaAWS BedrockGoogle Vertex AIMicrosoft Foundry / outras
OpenAI Code Interpreter / Hosted ShellSim Responses, Chat Completions, AssistantsN/D OpenAI não publica em clouds de terceiros — distribuição é pelo próprio api.openai.com (e Microsoft Azure OpenAI Service, que tem paridade limitada — verificar por região).
OpenAI Files API · File Search · BatchSim via /v1/files, vector stores, /v1/batchesAzure OpenAI mirror tem subset; conferir quotas, modelos e features por região antes de prometer paridade.
Gemini Code ExecutionSim via generateContent toolN/A (não distribuído)Verificar paridade exata em Vertex AI por regiãoN/A
Gemini File API · File SearchSimN/ASim (Vertex tem Storage/GCS-first; semântica difere)N/A
Anthropic Code ExecutionSim via Claude API diretoNãoNãoMicrosoft Foundry e Claude Platform on AWS (não Bedrock-generic)
Anthropic Files APISim (beta files-api-2025-04-14)NãoNãoMicrosoft Foundry
Anthropic PDF nativoSim (ZDR-elegível)Sim (Bedrock Converse — split de custo text-only vs visual)SimSim
+
+
+ Implicação prática: se sua org consome Claude via Bedrock ou Vertex, o caminho "Files API → container_upload → code_execution" simplesmente não existe. Para Excel/DOCX/PPTX nesse cenário, ou (a) faça parsing local com pandas/openpyxl e mande texto/PDF ao modelo, ou (b) migre o workload para Claude API direto / Foundry. Mesma decisão para qualquer roteamento multi-cloud. +
+ +

3.11.8 Armadilhas comuns confirmadas pelos verifiers

+
    +
  • OpenAI · "input_file basta para qualquer planilha". Falso para arquivos com > 1.000 linhas por aba, gráficos embutidos ou cálculos custom — augmentation é truncada e imagens/charts não são extraídos em formatos não-PDF. Convertendo para PDF, charts voltam ao contexto.
  • +
  • OpenAI · "ZDR cobre tudo". Falso: /v1/files é "No" para ZDR; background mode retém ~10 min; image/file inputs em /v1/responses passam por CSAM scan e podem ser retidos para revisão mesmo sob ZDR/MAM; MCP servers são third-party.
  • +
  • Gemini · "ZDR Paid Services = zero retenção". Falso: Grounding com Google Search/Maps SEMPRE retém prompts/output por 30 dias sem opt-out; File API storage é independente do ZDR logging (precisa deleção manual); explicit caching (cached_content) deve ser evitado para footprint zero. Implicit caching em RAM (24 h TTL) não viola ZDR.
  • +
  • Gemini · "Excel entra na vision nativa". Falso na lista oficial External-URL — .xlsx não aparece. Use File Search (que aceita application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) ou Code Execution com pandas.read_excel.
  • +
  • Anthropic · ".xlsx é só document block". Falso: a doc lista explicitamente que ".csv, .txt, .md, .docx, .xlsx" NÃO são suportados como document. Use text block convertido ou container_upload.
  • +
  • Anthropic · "Posso baixar o que subi". Falso para uploads do usuário — só arquivos criados por skills / Code Execution têm downloadable: true.
  • +
  • Anthropic · "container_upload não custa se o modelo não chamar a tool". Falso: quando há blocos container_upload, o tempo é cobrado mesmo se Claude nunca invocar o tool (arquivos são pré-carregados no container).
  • +
  • Todos · "Container é estado persistente". Falso. OpenAI: 20 min idle e tudo evapora. Gemini: sem container_id ao caller, escopo é a chamada. Anthropic: persiste por até 30 d se você passar container_id; sem ID, é container novo a cada request.
  • +
  • Todos · "Files API vira contexto eterno". Falso. Mesmo armazenado, o arquivo só entra no contexto da chamada que citá-lo explicitamente por file_id/fileData.fileUri. Em produção, mantenha o estado real no seu banco/storage e use IDs do provider como ponte temporária.
  • +
+ +

3.11.9 Impacto de custo e rate limit da escolha "coding tool sim/não"

+

Custo + throughput frequentemente decidem entre "fazer no provider" e "fazer no backend". Resumo decisão-relevante (detalhes em 3.8 e §4.5/§5.5/§7.5):

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProviderModelo de cobrança do coding toolRate limitImplicação prática
OpenAIBilled at built-in-tools rate; memory_limit escala tiers (1g < 4g < 16g < 64g). Desde 02/06/2026, tempo de container cobrado por minuto, mínimo de 5 min por sessão. ZDR e residência de dados são honrados.100 RPM por org para chamadas de Code Interpreter.Custo previsível por execução; tiers altos só quando o workload realmente precisa. Para batch grande, considere Files + backend ao invés de invocar tool 100×/min.
GeminiNão separadamente metrado: paga input + output tokens à taxa do modelo. Código gerado, charts inline (inlineData) e stdout contam como output tokens.Mesmas quotas do generateContent do modelo escolhido.Custo varia com volume de chart/stdout produzido. Gráficos grandes inflam output token count.
Anthropic1.550 horas grátis por org/mês; acima disso $0,05 por hora por container, mínimo de 5 min por sessão. Free quando combinado com web_search ou web_fetch. Containers paralelos contam separadamente. Tempo é cobrado mesmo se Claude não invocar a tool quando há container_upload.~100 RPM (beta) compartilhado com Files API.O "mínimo 5 min por sessão" + cobrança em container_upload pré-carregado tornam workloads de "muitas requests pequenas" caros. Reuse container_id ou agrupe perguntas em poucos turns longos.
Seu backendSem cobrança incremental do provider; você paga apenas tokens do modelo (input + output da narrativa).Limitado pela sua infra.Modelo mais previsível para volume alto, compliance estrito e auditoria; troca conveniência por controle.
+
+
+ Regra de bolso de scale: abaixo de ~1.500 horas/mês de execução, o Anthropic está em cota grátis; o Gemini é "grátis" mas você paga pelo output token volume (charts inflam isso); o OpenAI cobra por tier e respeita ZDR — preferível para workloads regulados de baixo a médio volume. Acima disso ou para compliance crítica, migre o trabalho determinístico para seu backend. +
+ +
+ Onde aprofundar: comparativo de Excel em §3.5; sandbox lado a lado em §3.8; quotas e retenção da Files API em §3.9; deep-dive OpenAI em §4.4 / §4.5 / §4.8; Gemini em §5.4 / §5.5 / §5.8; Anthropic em §7.4 / §7.5 / §7.8. Catálogo cruzado em §9; fontes oficiais em §10. +
+
+
+
OpenAI
+

OpenAI — deep dive

+

+ Reference date: 2026-05-23. Default frontier model: gpt-5.5; + low-latency variants: gpt-5.4-mini, gpt-5.4-nano; image generation: gpt-image-2; + realtime: gpt-realtime-2 / gpt-realtime-mini / gpt-realtime-translate / gpt-realtime-whisper; + speech-to-text: gpt-4o-transcribe, gpt-4o-mini-transcribe, gpt-4o-transcribe-diarize, whisper-1. + The Responses API is the preferred multimodal surface; Chat Completions is still required for some audio I/O patterns until Responses reaches parity. +

+ +

4.1 API surface

+

+ OpenAI exposes multimodal capabilities through several distinct HTTP endpoints. Most modern multimodal work uses the + Responses API; some patterns still require Chat Completions or the Realtime API. +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Endpoint matrix — what each API accepts and produces
APIHTTP endpointMultimodal inputsMultimodal outputsNotes
Responses APIPOST /v1/responsesinput_text, input_image, input_file (PDF, Office, CSV/XLSX, code/text), tool inputs (web/file search, code interpreter results)Text, structured JSON, image generation (via image_generation tool), code interpreter files (container_file_citation), audio output currently labeled "Coming soon" on the Migrate pagePreferred surface. Agentic loop with built-in tools (web_search, file_search, code_interpreter, image_generation, computer use, MCP).
Chat CompletionsPOST /v1/chat/completionstext, image_url (data URL or http URL), input_audio (base64 + format)Text, audio (when modalities: ["text","audio"] with an audio-capable model such as gpt-audio-1.5)Required today for audio in/out chat patterns (input_audio). Vision image_url over 8 MB is silently dropped.
Realtime APIWebSocket / WebRTC sessions (e.g. gpt-realtime-2, gpt-realtime-translate, gpt-realtime-whisper)Streaming audio (input_audio_buffer.append), text events; some realtime models accept images via session itemsStreaming audio (response.output_audio.delta), streaming text transcriptsUse for live, low-latency voice/translation/transcription. PCM16 / G.711 µ-law / G.711 A-law.
Audio API (request-based)POST /v1/audio/transcriptions, POST /v1/audio/translations, POST /v1/audio/speechAudio file upload (mp3/mp4/mpeg/mpga/m4a/wav/webm; flac/ogg also accepted by transcriptions)Text (transcription/translation) or audio (TTS)25 MB upload limit on transcriptions/translations. Models: gpt-4o-transcribe, gpt-4o-mini-transcribe, gpt-4o-mini-transcribe-2025-12-15, gpt-4o-transcribe-diarize, whisper-1.
Images APIPOST /v1/images/generations, POST /v1/images/editsText prompt; reference images via image_url or file_id (JSON requests) or multipartGenerated images (gpt-image-2)Edits now accept application/json with image_url/file_id instead of multipart.
Videos API (Sora)POST /v1/videos, POST /v1/videos/edits, POST /v1/videos/extensions, POST /v1/videos/characters, GET /v1/videos/{id}, GET /v1/videos/{id}/contentText prompt; optional input_reference image (file_id or image_url or multipart); optional characters[]; existing video (edits/extensions)MP4 video, thumbnail, spritesheetAsync job model; webhooks video.completed / video.failed.
Files APIPOST /v1/files, GET /v1/files, GET /v1/files/{id}, DELETE /v1/files/{id}, GET /v1/files/{id}/contentAny supported file with purpose in assistants, vision, batch, fine-tune, user_data, evalsReturns file object with id reusable as file_id everywhereUp to 512 MB per file, 2.5 TB per project, 1,000 uploads/min/user.
Containers / Code InterpreterPOST /v1/containers, POST /v1/containers/{id}/files, GET /v1/containers/{id}/files, GET /v1/containers/{id}/files/{file_id}/contentFiles (text, code, CSV/XLSX, PDF, images, pkl, tar, zip…) attached to a containerFiles produced by Python (container_file_citation annotations)Used by code_interpreter tool (Responses, Chat Completions, Assistants). 20-minute idle expiration.
Assistants API (v2)POST /v1/assistants, POST /v1/threads, POST /v1/threads/{id}/messages, runsText + image_file/image_url content parts; code_interpreter and file_search tool resourcesText, tool results, attachmentsStill available; files attached via purpose="assistants". Up to 20 files for code_interpreter, up to 10,000 (or 100,000,000 for vector stores created from Nov 2025) for file_search.
Batch APIPOST /v1/batches, JSONL inputWraps requests to /v1/responses, /v1/chat/completions, /v1/embeddings, /v1/completions, /v1/moderations, /v1/images/generations, /v1/images/edits, /v1/videosSame JSON body as underlying endpointJSONL up to 200 MB. For /v1/videos, only JSON (no multipart); input_reference must use file_id/image_url. Output retained 30 days; videos for 24 hours after batch completes.
+
+ +

Preferred multimodal stack (per global config 2026-05-23)

+
    +
  • Default text + vision + PDF + spreadsheets: Responses API on gpt-5.5 (or gpt-5.4-mini/gpt-5.4-nano for cost/latency).
  • +
  • Default audio I/O chat: Chat Completions on gpt-audio-1.5 (Responses audio is "Coming soon" in the Migrate-to-Responses matrix).
  • +
  • Default live voice agent: Realtime session on gpt-realtime-2 (or gpt-realtime-mini for cost).
  • +
  • Default transcription: gpt-4o-transcribe (or -mini for cost, -diarize for speaker labels, whisper-1 for SRT/VTT/word timestamps).
  • +
  • Default image generation: gpt-image-2 via Responses image_generation tool or Images API.
  • +
  • Default video generation: sora-2 (iteration) or sora-2-pro (1080p production) via Videos API.
  • +
+ +

4.2 Imagem / visão

+ +

Supported image file types

+
+ + + + + + + + +
TypeExtensions
PNG.png
JPEG.jpeg, .jpg
WEBP.webp
GIF.gif (non-animated only)
+
+
"No watermarks or logos. No NSFW content. Clear enough for a human to understand." — Images-and-vision guide.
+ +

Size limits

+
    +
  • Up to 512 MB total payload per request.
  • +
  • Up to 1,500 individual image inputs per request.
  • +
  • Per-image dimensions: see Model sizing behavior. Images that exceed a model's patch budget or pixel cap are resized by OpenAI before tokenization.
  • +
+ +

Three input modes

+

You can attach an image to Responses (or Chat Completions) as:

+
    +
  1. Image URL — a fully qualified HTTPS URL.
  2. +
  3. Base64 data URL — data:image/<type>;base64,<...>.
  4. +
  5. File ID — created with client.files.create(file=..., purpose="vision").
  6. +
+

In Chat Completions, the field is image_url.url (data URL or http). In Responses, the field is input_image.image_url (data URL or http) or input_image.file_id.

+ +
Mode 1 — Image URL
+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "What is in this image?"},
+            {
+                "type": "input_image",
+                "image_url": "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
+            },
+        ],
+    }],
+)
+
+print(response.output_text)
+
+
import OpenAI from "openai";
+const openai = new OpenAI();
+
+const response = await openai.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "What is in this image?" },
+      {
+        type: "input_image",
+        image_url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
+      },
+    ],
+  }],
+});
+
+console.log(response.output_text);
+
+
+ +
Mode 2 — Base64 data URL
+
+
+ + +
+
import base64
+from openai import OpenAI
+
+client = OpenAI()
+
+with open("path_to_your_image.jpg", "rb") as f:
+    b64 = base64.b64encode(f.read()).decode("utf-8")
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "What's in this image?"},
+            {
+                "type": "input_image",
+                "image_url": f"data:image/jpeg;base64,{b64}",
+                "detail": "high",
+            },
+        ],
+    }],
+)
+
+print(response.output_text)
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+const base64Image = fs.readFileSync("path_to_your_image.jpg", "base64");
+
+const response = await openai.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "what's in this image?" },
+      {
+        type: "input_image",
+        image_url: `data:image/jpeg;base64,${base64Image}`,
+        detail: "high",
+      },
+    ],
+  }],
+});
+
+console.log(response.output_text);
+
+
+ +
Mode 3 — File ID (Files API)
+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+uploaded = client.files.create(
+    file=open("path_to_your_image.jpg", "rb"),
+    purpose="vision",
+)
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "What's in this image?"},
+            {"type": "input_image", "file_id": uploaded.id},
+        ],
+    }],
+)
+
+print(response.output_text)
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+
+const uploaded = await openai.files.create({
+  file: fs.createReadStream("path_to_your_image.jpg"),
+  purpose: "vision",
+});
+
+const response = await openai.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "what's in this image?" },
+      { type: "input_image", file_id: uploaded.id },
+    ],
+  }],
+});
+
+console.log(response.output_text);
+
+
+ +

detail parameter — semantics per model family

+

detail controls the resolution at which the model processes the image. Allowed values: low, high, original (newer models), auto (default).

+
+ + + + + + + + +
DetailBehavior
lowModel receives a low-resolution 512×512 version. Fast and cheap; lose fine detail.
highHigh-fidelity tokenization (still bounded by the model's patch budget or tile budget).
originalAvailable on gpt-5.4 and later. Largest patch budget; recommended for computer-use, click-accuracy, dense text, and spatially sensitive tasks.
autoDefault. On gpt-5.5, auto and the omitted default are equivalent to original. On gpt-5.4, auto equals high.
+
+
+ The Images-and-vision guide notes verbatim: "On gpt-5.5, auto and the default omitted behavior are equivalent to original." + and "For computer use, localization, and click-accuracy use cases on gpt-5.4 and future models, we recommend "detail": "original"." +
+ +

Model sizing behavior (patch-based vs tile-based)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Model familySupported detail levelsSizing behavior
gpt-5.5low, high, original, autoPatch-based. high → up to 2,500 patches OR 2048 px max dimension. original → up to 10,000 patches OR 6000 px max dimension. auto ≡ original.
gpt-5.4low, high, original, autoPatch-based. Same numeric budgets as gpt-5.5. auto ≡ high.
gpt-5.4-mini, gpt-5.4-nanolow, high, autoPatch-based. high → up to 1,536 patches OR 2048 px max dimension.
+
+ +

Token cost formulas

+ +
Patch-based tokenization (gpt-5.x — current method for all SOTA models)
+

OpenAI tokenizes the image by covering it with 32 px × 32 px patches. Each model has a maximum patch budget. Steps:

+
A. original_patch_count = ceil(width/32) * ceil(height/32)
+
+B. If original_patch_count > patch_budget, resize:
+   shrink_factor = sqrt((32^2 * patch_budget) / (width * height))
+   adjusted_shrink_factor = shrink_factor * min(
+       floor(width  * shrink_factor / 32) / (width  * shrink_factor / 32),
+       floor(height * shrink_factor / 32) / (height * shrink_factor / 32)
+   )
+
+C. resized_patch_count = ceil(resized_width/32) * ceil(resized_height/32)
+   (capped by patch_budget)
+
+D. billed_tokens = resized_patch_count * model_multiplier
+
+
+ + + + + + + +
ModelMultiplier
gpt-5.51.0
gpt-5.4-mini1.62
gpt-5.4-nano2.46
+
+

gpt-5.5 bills the resized patch count at an effective ×1.0 multiplier (it is not listed in the Images-and-vision multiplier table because it is the reference unit). For the per-token rate, check the live pricing calculator. Source: developers.openai.com/api/docs/guides/images-vision#calculating-costs.

+ +

Worked examples (patch_budget = 1,536):

+
    +
  • 1024 × 1024 image → ceil(1024/32) * ceil(1024/32) = 32 * 32 = 1024. Below budget, no resize. resized_patch_count = 1024.
  • +
  • 1800 × 2400 image → ceil(1800/32) * ceil(2400/32) = 57 * 75 = 4275. Over budget. shrink_factor = sqrt(32² * 1536 / (1800 * 2400)) ≈ 0.603. Adjusted to ≈ 0.586. Resized to 1056 × 1408. resized_patch_count = 33 * 44 = 1452.
  • +
+ +
Tile-based tokenization — legado (não usado pelos modelos SOTA)
+

O método de tiles é exclusivamente legado: todos os modelos SOTA (gpt-5.x) usam patches. Documentado aqui apenas para referência histórica. Para detail: low, o custo era um base token count fixo por modelo. Para detail: high:

+
    +
  1. Scale to fit in a 2048 × 2048 square (aspect ratio preserved).
  2. +
  3. Scale so the shortest side is 768 px.
  4. +
  5. Count the number of 512 × 512 tiles. Multiply by per-tile cost.
  6. +
  7. Add the base token count.
  8. +
+
O método tile-based usado pela geração anterior de modelos é legado e não deve ser usado em novas integrações; prefira o método patch-based dos modelos gpt-5.x acima. Source: developers.openai.com/api/docs/guides/images-vision#calculating-costs.
+ +
Entrada de imagem em geração/edição de imagem (gpt-image-2)
+
+ gpt-image-2 always processes image inputs at high fidelity automatically; the input_fidelity parameter is not user-settable for it. Source: Image-generation guide #image-input-fidelity. +
+ +

Documented vision limitations (verbatim from the guide)

+
    +
  • Medical images: Not suitable for CT scans, MRIs, or medical advice.
  • +
  • Non-English: May underperform on non-Latin scripts (e.g. Japanese, Korean).
  • +
  • Small text: Enlarge text within the image; use "detail": "original" if available.
  • +
  • Rotation: May misinterpret rotated/upside-down content.
  • +
  • Visual elements: Struggles with graphs where colors/styles (solid/dashed/dotted) vary.
  • +
  • Spatial reasoning: Struggles with precise spatial localization (e.g. chess positions).
  • +
  • Accuracy: May generate incorrect descriptions/captions in certain scenarios.
  • +
  • Image shape: Struggles with panoramic and fisheye images.
  • +
  • Metadata and resizing: Doesn't process original file names or EXIF; resizes per detail.
  • +
  • Counting: Approximate counts only.
  • +
  • CAPTCHAs: Submissions are blocked for safety.
  • +
+ +

TPM accounting note

+
"We process images at the token level, so each image we process counts towards your tokens per minute (TPM) limit." — Images-and-vision guide.
+ +

4.3 PDF e documentos

+

PDF is the only file type for which the API extracts both text and per-page images into the model context — and only on vision-capable models (gpt-5.5, gpt-5.4-mini, gpt-5.4-nano).

+ +

Three input modes

+

You can attach a PDF to Responses as input_file using:

+
    +
  1. file_id returned from a client.files.create(..., purpose="user_data") upload.
  2. +
  3. file_url pointing at an external PDF.
  4. +
  5. file_data base64-encoded PDF bytes (with filename).
  6. +
+
Chat Completions does not support file_url. Use Responses for that mode. Source: File-inputs guide § File URLs.
+ +

Size limits

+
    +
  • Per-file limit: 50 MB. The combined size of all files in a single request also cannot exceed 50 MB. (Files-inputs guide § Usage considerations.)
  • +
  • Page/document caps: UNVERIFIED 2026-05-23 — the live File-inputs guide on this date documents only the 50 MB constraint. The often-cited "100 pages" figure does not appear in the current guide text and should be re-verified against the pricing page before quoting in user-facing material.
  • +
  • For files larger than 50 MB or many-hundred-page PDFs, use File Search (vector store ingestion) instead of input_file. Vector stores support up to 100,000,000 attached files for vector stores created from Nov 2025 (Files create reference).
  • +
+ +

How OpenAI tokenizes PDFs

+
"PDF parsing includes both extracted text and page images in context, which can increase token usage." — File-inputs guide.
+

This means each PDF page contributes two token streams: the OCR/extracted text and the rendered page image (subject to the model's image tokenization rules from the previous section). The Token-counting guide also confirms that count_tokens supports file_id, file_url, or file_data "currently PDFs" and "reflects the model's full processed input."

+ +

Example — file_url

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "Summarize the key points of this letter."},
+            {
+                "type": "input_file",
+                "file_url": "https://www.berkshirehathaway.com/letters/2024ltr.pdf",
+            },
+        ],
+    }],
+)
+
+print(response.output_text)
+
+
import OpenAI from "openai";
+const client = new OpenAI();
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "Summarize the key points of this letter." },
+      {
+        type: "input_file",
+        file_url: "https://www.berkshirehathaway.com/letters/2024ltr.pdf",
+      },
+    ],
+  }],
+});
+
+console.log(response.output_text);
+
+
+ +

Example — file_id (recommended for reuse)

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+uploaded = client.files.create(
+    file=open("draconomicon.pdf", "rb"),
+    purpose="user_data",
+)
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_file", "file_id": uploaded.id},
+            {"type": "input_text", "text": "What is the first dragon in the book?"},
+        ],
+    }],
+)
+
+print(response.output_text)
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const file = await client.files.create({
+  file: fs.createReadStream("draconomicon.pdf"),
+  purpose: "user_data",
+});
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_file", file_id: file.id },
+      { type: "input_text", text: "What is the first dragon in the book?" },
+    ],
+  }],
+});
+
+console.log(response.output_text);
+
+
+ +

Example — base64 file_data

+
+
+ + +
+
import base64
+from openai import OpenAI
+
+client = OpenAI()
+
+with open("draconomicon.pdf", "rb") as f:
+    b64 = base64.b64encode(f.read()).decode("utf-8")
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {
+                "type": "input_file",
+                "filename": "draconomicon.pdf",
+                "file_data": f"data:application/pdf;base64,{b64}",
+            },
+            {"type": "input_text", "text": "What is the first dragon in the book?"},
+        ],
+    }],
+)
+
+print(response.output_text)
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const data = fs.readFileSync("draconomicon.pdf");
+const base64String = data.toString("base64");
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      {
+        type: "input_file",
+        filename: "draconomicon.pdf",
+        file_data: `data:application/pdf;base64,${base64String}`,
+      },
+      { type: "input_text", text: "What is the first dragon in the book?" },
+    ],
+  }],
+});
+
+console.log(response.output_text);
+
+
+ +

Processing matrix — Office / Excel / CSV / structured documents

+

The Responses API input_file mechanism accepts a wide list of file types beyond PDF, but the processing path differs depending on type.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
File familyWhat the API does with itWhy this matters
PDF (.pdf)Extracts text and rasterizes each page to an image; both go to the model.Best for charts/diagrams.
Rich documents (.doc, .docx, .rtf, .odt, Pages, Google Docs)Extracts text only. Embedded images/charts are not extracted.Convert to PDF first if charts matter.
Presentations (.ppt, .pptx, Keynote, Google Slides)Extracts text only.Convert to PDF if slide visuals matter.
Spreadsheets (.xls, .xlsx, .csv, .tsv, .iif, Google Sheets)Runs a spreadsheet augmentation flow: parses up to the first 1,000 rows per sheet, plus model-generated header/summary metadata.Direct vision on cells is not performed; use Code Interpreter or Hosted Shell for analytics.
Text / code (.txt, .md, .json, .html, .xml, code files in dozens of languages)Extracts text only.Standard text path.
+
+
"For non-PDF files, the API doesn't extract embedded images or charts into the model context. To preserve chart and diagram fidelity, convert the file to PDF first, then send the PDF as input_file." — File-inputs guide § Non-PDF image and chart limitations.
+ +

4.4 Planilhas

+ +

Spreadsheets — direct ingestion via input_file

+

Direct input_file ingestion is fine for "find me the row where…" or "summarize the sheet" tasks where 1,000 rows are sufficient.

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+uploaded = client.files.create(
+    file=open("sales_2025.xlsx", "rb"),
+    purpose="user_data",
+)
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_file", "file_id": uploaded.id},
+            {"type": "input_text", "text": "Which region had the largest Q3 growth? Show the top 5 SKUs."},
+        ],
+    }],
+)
+
+print(response.output_text)
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const file = await client.files.create({
+  file: fs.createReadStream("sales_2025.xlsx"),
+  purpose: "user_data",
+});
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_file", file_id: file.id },
+      { type: "input_text", text: "Which region had the largest Q3 growth? Show the top 5 SKUs." },
+    ],
+  }],
+});
+
+console.log(response.output_text);
+
+
+ +

Spreadsheets — Code Interpreter for real analytics

+

For aggregations, joins, charting, regressions, or any task that needs more than the first 1,000 rows, use the code_interpreter tool. Files attached to the Responses request are auto-uploaded to the container.

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+uploaded = client.files.create(
+    file=open("sales_2025.xlsx", "rb"),
+    purpose="user_data",
+)
+
+response = client.responses.create(
+    model="gpt-5.5",
+    tools=[{
+        "type": "code_interpreter",
+        "container": {"type": "auto", "memory_limit": "4g", "file_ids": [uploaded.id]},
+    }],
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text",
+             "text": "Compute total revenue by month, plot it as a line chart, and save it as revenue.png. Return the chart and a CSV of the data."},
+        ],
+    }],
+)
+
+for item in response.output:
+    if item.type == "message":
+        for part in item.content:
+            if getattr(part, "type", None) == "output_text":
+                print(part.text)
+            for ann in getattr(part, "annotations", []) or []:
+                if ann.type == "container_file_citation":
+                    print("File:", ann.filename, "container:", ann.container_id, "file:", ann.file_id)
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const uploaded = await client.files.create({
+  file: fs.createReadStream("sales_2025.xlsx"),
+  purpose: "user_data",
+});
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  tools: [{
+    type: "code_interpreter",
+    container: { type: "auto", memory_limit: "4g", file_ids: [uploaded.id] },
+  }],
+  input: [{
+    role: "user",
+    content: [{
+      type: "input_text",
+      text: "Compute total revenue by month, plot it as a line chart, and save it as revenue.png. Return the chart and a CSV of the data.",
+    }],
+  }],
+});
+
+console.log(JSON.stringify(response.output, null, 2));
+
+
+ +

Caveat — no direct .xlsx vision

+

There is no vision pipeline that renders an XLSX as images. If you need OCR-style understanding of formatting (cell colors, merged regions, embedded screenshots), export each sheet to PDF and use input_file on the PDF.

+ +

Hosted Shell

+

The Hosted Shell tool (launched in 2026 alongside Code Interpreter networking) is the documented alternative for "spreadsheet-heavy tasks that need detailed analysis, such as aggregations, joins, charting, or custom calculations" (File-inputs guide § How it works).

+ +

4.5 Code Interpreter

+

The Code Interpreter tool runs Python in a sandboxed container that the model controls. It is exposed in the Responses, Chat Completions, and Assistants APIs.

+
"While we call this tool Code Interpreter, the model knows it as the 'python tool'." — Code Interpreter guide.
+ +

Tool definition

+
{
+  "type": "code_interpreter",
+  "container": { "type": "auto", "memory_limit": "4g" }
+}
+
+

container may be:

+
    +
  • {"type": "auto", "memory_limit": "...", "file_ids": ["..."]} — auto-create or reuse a recent container, optionally pre-attached files.
  • +
  • "cntr_..." — an explicit container ID created via POST /v1/containers.
  • +
+

memory_limit accepts "1g" (default), "4g", "16g", or "64g". Higher tiers are billed at the built-in-tools rate; the limit is fixed for the container's lifetime.

+ +

Container lifecycle

+
    +
  • Expiration: A container expires if it is not used for 20 minutes. Any container operation (retrieve, add file, delete file) refreshes last_active_at.
  • +
  • Recovery: You cannot reanimate an expired container — files and in-memory Python state are gone. Always treat containers as ephemeral and download any files you care about while the container is alive.
  • +
  • Discovery: Auto-created containers are still reachable via GET /v1/containers/{id}.
  • +
+ +

Supported files (into the container)

+
+ Full MIME-type table (click to expand) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Extension(s)MIME type
.ctext/x-c
.cstext/x-csharp
.cpptext/x-c++
.csvtext/csv, application/csv
.docapplication/msword
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.htmltext/html
.javatext/x-java
.jsonapplication/json
.mdtext/markdown
.pdfapplication/pdf
.phptext/x-php
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.pytext/x-python, text/x-script.python
.rbtext/x-ruby
.textext/x-tex
.txttext/plain
.csstext/css
.jstext/javascript
.shapplication/x-sh
.tsapplication/typescript
.jpeg, .jpgimage/jpeg
.gifimage/gif
.pngimage/png
.pklapplication/octet-stream
.tarapplication/x-tar
.xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xmlapplication/xml or text/xml
.zipapplication/zip
+
+
+ +

Output retrieval — container_file_citation

+

When Code Interpreter writes a file, it shows up as an annotation on the assistant's message:

+
{
+  "annotations": [{
+    "type": "container_file_citation",
+    "container_id": "cntr_...",
+    "file_id": "cfile_...",
+    "filename": "cfile_....png"
+  }],
+  "text": "Here is the histogram...",
+  "type": "output_text"
+}
+
+

Download with GET /v1/containers/{container_id}/files/{file_id}/content. List with GET /v1/containers/{container_id}/files. Add new files with POST /v1/containers/{container_id}/files (multipart or JSON with file_id).

+ +

Auto-mode example (chart generation)

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+resp = client.responses.create(
+    model="gpt-5.5",
+    tools=[{
+        "type": "code_interpreter",
+        "container": {"type": "auto", "memory_limit": "4g"},
+    }],
+    instructions="You are a personal math tutor. Always use the python tool to do math.",
+    input="I need to solve the equation 3x + 11 = 14. Plot the solution on a number line and save it as solution.png.",
+)
+print(resp.output)
+
+
import OpenAI from "openai";
+const client = new OpenAI();
+
+const resp = await client.responses.create({
+  model: "gpt-5.5",
+  tools: [{
+    type: "code_interpreter",
+    container: { type: "auto", memory_limit: "4g" },
+  }],
+  instructions: "You are a personal math tutor. Always use the python tool to do math.",
+  input: "I need to solve the equation 3x + 11 = 14. Plot the solution on a number line and save it as solution.png.",
+});
+
+console.log(JSON.stringify(resp.output, null, 2));
+
+
+ +

Explicit-container example (reuse across turns)

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+container = client.containers.create(name="analytics", memory_limit="16g")
+
+response = client.responses.create(
+    model="gpt-5.5",
+    tools=[{"type": "code_interpreter", "container": container.id}],
+    tool_choice="required",
+    input="use the python tool to calculate sqrt(sqrt(4 * 3.82))",
+)
+
+print(response.output_text)
+
+
import OpenAI from "openai";
+const client = new OpenAI();
+
+const container = await client.containers.create({ name: "analytics", memory_limit: "16g" });
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  tools: [{ type: "code_interpreter", container: container.id }],
+  tool_choice: "required",
+  input: "use the python tool to calculate sqrt(sqrt(4 * 3.82))",
+});
+
+console.log(response.output_text);
+
+
+ +

Downloading a generated file

+
+
+ + +
+
import os, openai
+from openai import OpenAI
+
+client = OpenAI()
+# annotation.container_id and annotation.file_id from a previous response
+binary = client.containers.files.content.retrieve(
+    file_id="cfile_682d514b2e00819184b9b07e13557f82",
+    container_id="cntr_682d513bb0c48191b10bd4f8b0b3312200e64562acc2e0af",
+)
+with open("histogram.png", "wb") as f:
+    f.write(binary.read())
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const binary = await client.containers.files.content.retrieve(
+  "cfile_682d514b2e00819184b9b07e13557f82",
+  { container_id: "cntr_682d513bb0c48191b10bd4f8b0b3312200e64562acc2e0af" }
+);
+const ab = await binary.arrayBuffer();
+fs.writeFileSync("histogram.png", Buffer.from(ab));
+
+
+ +

Limits and pricing

+
    +
  • API availability: Responses, Chat Completions, Assistants.
  • +
  • Rate limit: 100 RPM per org for Code Interpreter calls.
  • +
  • Pricing: billed at the built-in-tools rate; higher memory_limit tiers cost more (1g < 4g < 16g < 64g). Since 2026-06-02, container time is billed per minute with a 5-minute minimum per session (previously charged in whole 20-minute blocks).
  • +
  • ZDR + data residency are honored; the container filesystem is ephemeral block storage.
  • +
+ +

4.6 Vídeo (frames + Sora)

+

OpenAI's video posture as of 2026-05-23:

+
    +
  • No native video understanding on Responses/Chat Completions today. The current Responses API "Coming soon" matrix lists only Audio; there is no input_video content type. UNVERIFIED 2026-05-23 based on absence in the Responses content schema and the Migrate-to-Responses matrix.
  • +
  • Realtime API has video conversation support contextualized around gpt-realtime-translate (live video conversation translation) and gpt-realtime-2 voice/audio, but no documented general "input_video" frame stream content type.
  • +
  • The supported pattern for analyzing arbitrary video is the frame-extraction + audio-transcription pattern: split video into N keyframes, send them as input_image[] to gpt-5.5, and transcribe the audio track separately with gpt-4o-transcribe.
  • +
  • Generation is fully supported via the Videos API (Sora 2 / Sora 2-Pro).
  • +
+ +

Frame-extraction workflow (the working pattern)

+
import base64
+import cv2
+from openai import OpenAI
+
+client = OpenAI()
+
+def extract_frames(video_path, every_n_seconds=2, max_frames=24):
+    cap = cv2.VideoCapture(video_path)
+    fps = cap.get(cv2.CAP_PROP_FPS)
+    frames_per_step = int(fps * every_n_seconds)
+    frames = []
+    idx = 0
+    while cap.isOpened() and len(frames) < max_frames:
+        ok, frame = cap.read()
+        if not ok:
+            break
+        if idx % frames_per_step == 0:
+            ok2, buf = cv2.imencode(".jpg", frame)
+            if ok2:
+                frames.append(base64.b64encode(buf.tobytes()).decode("utf-8"))
+        idx += 1
+    cap.release()
+    return frames
+
+frames = extract_frames("meeting.mp4", every_n_seconds=2, max_frames=24)
+content = [{"type": "input_text", "text": "Summarize what happens in this meeting clip."}]
+content += [
+    {
+        "type": "input_image",
+        "image_url": f"data:image/jpeg;base64,{f}",
+        "detail": "low",
+    }
+    for f in frames
+]
+
+resp = client.responses.create(
+    model="gpt-5.5",
+    input=[{"role": "user", "content": content}],
+)
+print(resp.output_text)
+
+

Combine that with a separate client.audio.transcriptions.create(model="gpt-4o-transcribe", file=open("meeting.mp4","rb")) call to attach the speech transcript as text. The OpenAI vision cookbook calls this the "Visual + Audio Summary" pattern and notes it is the most accurate of the three (visual-only, audio-only, visual+audio).

+ +

Video generation (Sora 2 / Sora 2-Pro)

+
    +
  • Async job model: POST /v1/videos returns a job with status queued|in_progress|completed|failed. Poll GET /videos/{id} or subscribe to webhooks video.completed / video.failed.
  • +
  • Download MP4 with GET /videos/{id}/content; thumbnail with ?variant=thumbnail; spritesheet with ?variant=spritesheet. Download URLs valid for 1 hour.
  • +
  • Durations: API reference allows seconds ∈ {4, 8, 12} (default 4); cookbook also mentions 16 s / 20 s. Treat the API reference as authoritative — verified 2026-05-23.
  • +
  • Resolutions: sora-2 for fast 720p iteration; sora-2-pro for 1080p (1920x1080 or 1080x1920) at $0.70/sec.
  • +
  • input_reference: a guiding first frame, accepted as multipart upload or as JSON object with file_id or image_url. Supported formats: image/jpeg, image/png, image/webp. Must match the target video size.
  • +
  • characters[]: reusable non-human subject from a POST /v1/videos/characters upload (2–4s clip, 16:9 or 9:16, 720p–1080p). Up to two per video. Human likeness blocked by default.
  • +
  • Extensions (POST /v1/videos/extensions): up to 6 extensions of 20 s each, max 120 s total.
  • +
  • Edits (POST /v1/videos/edits): targeted, single-change edit of an existing video by ID; multipart uploads of new videos require an model field and eligibility.
  • +
  • Batch: supported on POST /v1/videos only (JSON, not multipart). Outputs available for 24 h after batch completes.
  • +
  • Restrictions: no real people, no copyrighted characters/music, U18-safe content, no input images with human faces (Sora guardrails).
  • +
+ +

Minimal generation example

+
from openai import OpenAI
+client = OpenAI()
+
+video = client.videos.create_and_poll(
+    model="sora-2",
+    prompt="A cinematic dolly shot of a teal coupe driving through a sunset desert highway, heat ripples visible.",
+)
+if video.status == "completed":
+    content = client.videos.download_content(video.id, variant="video")
+    content.write_to_file("clip.mp4")
+
+ +

4.7 Áudio

+ +

Three distinct surfaces

+
+ + + + + + + + + + + + + + + + + + + +
SurfaceWhat it doesPrimary models
Chat Completions with input_audioSend a base64-encoded audio clip alongside text to a single multimodal model that can also respond with text and/or audio.gpt-audio-1.5
Audio API transcriptions / translationsConvert an uploaded audio file to text.gpt-4o-transcribe, gpt-4o-mini-transcribe, gpt-4o-mini-transcribe-2025-12-15, gpt-4o-transcribe-diarize, whisper-1
Realtime sessionsStream audio bidirectionally for live agents/translation/transcription.gpt-realtime-2, gpt-realtime-mini, gpt-realtime-translate, gpt-realtime-whisper
+
+
The Responses API matrix still labels Audio as "Coming soon" (Migrate-to-Responses), so the Chat-Completions path is the current canonical surface for in-chat audio inputs/outputs.
+ +

Supported audio file formats

+
+ + + + + + + + + + + + + + + + +
EndpointSupported formats
/v1/audio/transcriptions and /v1/audio/translations (file upload, 25 MB cap)flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, webm
Chat Completions input_audio.formatwav, mp3 (typically; the Chat Completions reference accepts string format identifiers tied to gpt-audio-* models)
Realtime PCM streamRaw PCM16 at 24 kHz mono little-endian; or g711_ulaw / g711_alaw for telephony
+
+ +

Chat Completions — input_audio

+
+
+ + +
+
import base64, requests
+from openai import OpenAI
+
+client = OpenAI()
+
+url = "https://cdn.openai.com/API/docs/audio/alloy.wav"
+wav = requests.get(url).content
+b64 = base64.b64encode(wav).decode("utf-8")
+
+completion = client.chat.completions.create(
+    model="gpt-audio-1.5",
+    modalities=["text", "audio"],
+    audio={"voice": "alloy", "format": "wav"},
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text", "text": "What is in this recording?"},
+            {"type": "input_audio", "input_audio": {"data": b64, "format": "wav"}},
+        ],
+    }],
+)
+
+print(completion.choices[0].message)
+audio_b64 = completion.choices[0].message.audio.data
+open("reply.wav", "wb").write(base64.b64decode(audio_b64))
+
+
import OpenAI from "openai";
+const openai = new OpenAI();
+
+const url = "https://cdn.openai.com/API/docs/audio/alloy.wav";
+const audioResponse = await fetch(url);
+const base64str = Buffer.from(await audioResponse.arrayBuffer()).toString("base64");
+
+const response = await openai.chat.completions.create({
+  model: "gpt-audio-1.5",
+  modalities: ["text", "audio"],
+  audio: { voice: "alloy", format: "wav" },
+  messages: [{
+    role: "user",
+    content: [
+      { type: "text", text: "What is in this recording?" },
+      { type: "input_audio", input_audio: { data: base64str, format: "wav" } },
+    ],
+  }],
+});
+
+console.log(response.choices[0]);
+
+
+ +

Transcription — gpt-4o-transcribe

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+with open("meeting.mp3", "rb") as f:
+    t = client.audio.transcriptions.create(
+        model="gpt-4o-transcribe",
+        file=f,
+        response_format="json",
+        language="en",
+        prompt="Discussion about Q3 revenue, mention of OKRs, KPIs, and ARR.",
+    )
+print(t.text)
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+const t = await openai.audio.transcriptions.create({
+  file: fs.createReadStream("meeting.mp3"),
+  model: "gpt-4o-transcribe",
+  response_format: "json",
+  language: "en",
+  prompt: "Discussion about Q3 revenue, mention of OKRs, KPIs, and ARR.",
+});
+console.log(t.text);
+
+
+ +

Transcription with diarization — gpt-4o-transcribe-diarize

+
import base64
+from openai import OpenAI
+
+client = OpenAI()
+
+def to_data_url(path):
+    with open(path, "rb") as fh:
+        return "data:audio/wav;base64," + base64.b64encode(fh.read()).decode("utf-8")
+
+with open("meeting.wav", "rb") as audio_file:
+    transcript = client.audio.transcriptions.create(
+        model="gpt-4o-transcribe-diarize",
+        file=audio_file,
+        response_format="diarized_json",
+        chunking_strategy="auto",   # required for inputs > 30 seconds
+        extra_body={
+            "known_speaker_names": ["agent", "customer"],
+            "known_speaker_references": [to_data_url("agent.wav"), to_data_url("customer.wav")],
+        },
+    )
+
+for seg in transcript.segments:
+    print(f"[{seg.start:.2f}-{seg.end:.2f}] {seg.speaker}: {seg.text}")
+
+

Constraints:

+
    +
  • Up to 4 known speakers (known_speaker_names[]/known_speaker_references[]).
  • +
  • Reference clips: 2–10 s, data URLs in the same set of input audio formats.
  • +
  • chunking_strategy is required for inputs longer than 30 s.
  • +
  • prompt, logprobs, and timestamp_granularities[] are not supported for diarize.
  • +
  • Diarize is available on /v1/audio/transcriptions only — not in Realtime as of 2026-05-23.
  • +
+ +

Streaming transcription

+

stream=True is supported on gpt-4o-transcribe and gpt-4o-mini-transcribe (not on whisper-1). Events: transcript.text.delta, transcript.text.done, transcript.text.segment (diarized). include[]=logprobs for token confidences.

+ +

Timestamps (word/segment)

+

timestamp_granularities[] is supported only on whisper-1 with response_format="verbose_json". Set to ["word"] or ["segment"] or both. Word-level timestamps cost some additional latency.

+ +

Long audio (>25 MB / >30 min)

+

Chunk the input externally (e.g., PyDub) and combine prompts across segments. Whisper-1 only honors the first 224 tokens of the prompt.

+ +

Realtime audio

+

For live audio (microphone, calls, media streams) use a Realtime session:

+
    +
  • Connect via WebSocket or WebRTC (gpt-realtime-2, gpt-realtime-translate, gpt-realtime-whisper).
  • +
  • Stream PCM16 with input_audio_buffer.append, then either rely on server VAD (session.update) or commit manually.
  • +
  • Receive incremental response.output_audio.delta (base64 PCM) and conversation.item.input_audio_transcription.{delta,segment,completed,failed} events.
  • +
  • Restricted formats: pcm16 (16-bit, 24 kHz, mono, little-endian), g711_ulaw, g711_alaw. No MP3 or Opus.
  • +
  • Sessions are limited to 60 minutes (corrigido após verificação ao vivo 2026-05-23; audio chunks ≤ 15 MB; conexões WebSocket/WebRTC/SIP).
  • +
+ +

Text-to-speech

+

POST /v1/audio/speech with the dedicated TTS model gpt-4o-mini-tts (recommended voices marin, cedar). See the Text-to-speech guide for current voices and formats; for realtime speech, the gpt-realtime-* family is the canonical path.

+ +

4.8 Files API

+ +

Endpoints

+
+ + + + + + + + + +
MethodPathPurpose
POST/v1/filesUpload a file. Form-encoded file, purpose. Optional expires_after.
GET/v1/filesList files. Optional purpose, limit, after, order.
GET/v1/files/{file_id}Retrieve file metadata.
DELETE/v1/files/{file_id}Delete a file.
GET/v1/files/{file_id}/contentRetrieve file content (raw bytes).
+
+ +

Purposes (verified 2026-05-23)

+
+ + + + + + + + + + +
purposeUse
assistantsFiles for the Assistants v2 API (vector store ingestion, code_interpreter resources).
visionImage files attached to chat/responses via file_id.
batchJSONL input for the Batch API (up to 200 MB JSONL).
fine-tune.jsonl training data for the Fine-tuning API.
user_dataDefault for files you plan to pass as model inputs (input_file).
evalsDatasets used with the Evaluations product.
+
+
The File-inputs guide explicitly states: "You can upload files with any supported purpose, but use user_data for files you plan to pass as model inputs."
+ +

Limits (verified 2026-05-23)

+
    +
  • Per-file size: up to 512 MB.
  • +
  • Per-project storage: up to 2.5 TB.
  • +
  • Org-wide storage: no limit — files only count against the project they live in.
  • +
  • Upload rate: 1,000 requests/minute per authenticated user.
  • +
  • Assistants files: up to 2 million tokens per file when used through the Assistants API; code_interpreter can have up to 20 attached files per run; file_search vector stores can attach up to 10,000 files (or 100,000,000 files for vector stores created from November 2025).
  • +
  • Batch JSONL: up to 200 MB per file.
  • +
  • Vector store attachment rate: 2,000 attached files/minute per organization.
  • +
  • Combined input_file payload: each file in a single request must be under 50 MB; combined ≤ 50 MB.
  • +
  • Output retention: Batch output files are retained 30 days. Video download URLs are valid 1 hour (Sora) or 24 hours after batch completion for Batch-generated videos.
  • +
+ +

Expiration policies

+

By default, uploaded files persist until you delete them. The Files create reference supports an expires_after parameter to schedule TTL-style auto-deletion (UNVERIFIED 2026-05-23 — specific syntax should be re-checked against the OpenAPI before final docs). Hosted container files expire with their container (20-min idle).

+ +

Examples — upload + list + delete

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+# Upload
+uploaded = client.files.create(
+    file=open("draconomicon.pdf", "rb"),
+    purpose="user_data",
+)
+print(uploaded.id, uploaded.bytes, uploaded.purpose, uploaded.status)
+
+# List
+for f in client.files.list(purpose="user_data", limit=10).data:
+    print(f.id, f.filename)
+
+# Retrieve metadata
+meta = client.files.retrieve(uploaded.id)
+print(meta)
+
+# Retrieve content
+binary = client.files.content(uploaded.id)
+with open("local_copy.pdf", "wb") as out:
+    out.write(binary.read())
+
+# Delete
+client.files.delete(uploaded.id)
+
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const uploaded = await client.files.create({
+  file: fs.createReadStream("draconomicon.pdf"),
+  purpose: "user_data",
+});
+console.log(uploaded.id);
+
+const list = await client.files.list({ purpose: "user_data", limit: 10 });
+for (const f of list.data) console.log(f.id, f.filename);
+
+const meta = await client.files.retrieve(uploaded.id);
+console.log(meta);
+
+const stream = await client.files.content(uploaded.id);
+const ab = await stream.arrayBuffer();
+fs.writeFileSync("local_copy.pdf", Buffer.from(ab));
+
+await client.files.delete(uploaded.id);
+
+
+ +

4.9 Parâmetros completos

+

Every multimodal-relevant parameter, scoped to the API where it appears.

+ +

Responses API — input content parts

+
+ + + + + + + + + + + + + +
FieldTypeDefaultAllowed valuesApplies to
typestring—input_text, input_image, input_file, input_audio (UNVERIFIED 2026-05-23 for top-level audio on Responses — see Migrate matrix), image_generation_call.result (output side)All Responses inputs
input_text.textstring—Free textinput_text
input_image.image_urlstring—data: URL or HTTPS URLinput_image
input_image.file_idstring—File ID with purpose="vision" (or user_data for general image attachments)input_image
input_image.detailstringautolow, high, original, autoinput_image
input_file.file_idstring—File ID with purpose="user_data" recommendedinput_file
input_file.file_urlstring—HTTPS URL pointing at a PDF or docinput_file (Responses only; not Chat)
input_file.file_datastring—data:application/pdf;base64,...input_file
input_file.filenamestring—Required with file_data to name the fileinput_file
+
+ +

Responses API — top-level multimodal parameters

+
+ + + + + + + + + + +
ParameterTypeDefaultAllowed valuesApplies to
modelstring—Any model with vision (e.g., gpt-5.5, gpt-5.4-mini, gpt-5.4-nano)All
tools[].type=image_generationtool—Enables gpt-image-2-style generation as a tool callImage output
tools[].type=code_interpretertool—Enables python tool with attached filesSpreadsheet/data tasks
tools[].containerobject|string{"type":"auto","memory_limit":"1g"}{"type":"auto","memory_limit":"1g|4g|16g|64g","file_ids":[...]} or "cntr_..."Code Interpreter
instructionsstringnullSystem-level guidanceAll
storebooltrueIf false (or org has ZDR) no application state is retainedAll
+
+ +

Chat Completions — multimodal content

+
+ + + + + + + + + + + + +
FieldTypeDefaultAllowed valuesApplies to
messages[].content[].typestring—text, image_url, input_audioAll
image_url.urlstring—data: URL or http URL (≤8 MB or it is dropped)Vision
image_url.detailstringautolow, high, original (for supporting models), autoVision
input_audio.datastring—Base64 audio bytesAudio in
input_audio.formatstring—wav, mp3 (model-specific)Audio in
modalitiesstring[]["text"]["text"], ["text","audio"]Audio out
audio.voicestring—e.g. alloy, plus other named voicesAudio out
audio.formatstring—wav, mp3, opus, etc. (model-specific)Audio out
+
+ +

Audio API — audio.transcriptions.create

+
+ + + + + + + + + + + + + + + + +
ParameterTypeDefaultAllowed valuesApplies to
filefile—mp3/mp4/mpeg/mpga/m4a/wav/webm/flac/ogg ≤ 25 MBAll transcription models
modelstring—gpt-4o-transcribe, gpt-4o-mini-transcribe, gpt-4o-mini-transcribe-2025-12-15, gpt-4o-transcribe-diarize, whisper-1All
response_formatstringjsonjson, text, srt, verbose_json, vtt, diarized_json (diarize only)Per model: whisper-1 supports all; gpt-4o-* json/text only; diarize json/text/diarized_json
chunking_strategystring | objectunset"auto" or server_vad configRequired for diarize > 30s
languagestringunsetISO-639-1 (e.g. en, pt)Optional accuracy boost
promptstringunsetFree-text style/spelling hints (224 tokens max for whisper-1)Not supported on diarize
temperaturenumber00–1All
timestamp_granularities[]string[]unsetword, segmentwhisper-1 only
include[]string[]unsetlogprobsgpt-4o-transcribe / -mini only
streamboolfalsetrue to stream transcript.* eventsgpt-4o-transcribe / -mini-transcribe (not whisper-1, not diarize-partial-speaker)
known_speaker_names[]string[]unsetUp to 4 short identifiersdiarize
known_speaker_references[]string[]unsetData URLs of 2–10 s clipsdiarize
+
+ +

Realtime session — audio configuration

+
+ + + + + + + + + + +
FieldAllowed values
session.audio.input.formatpcm16, g711_ulaw, g711_alaw
session.audio.output.formatsame as input
session.turn_detectionnull (off) or server_vad object
session.modalities["text"] or ["audio","text"]
response.audio.output.formatOverride format per response
input_audio_buffer.append.audioBase64 PCM payload
+
+ +

Files API — files.create

+
+ + + + + + + +
ParameterAllowed
fileBinary file ≤ 512 MB
purposeassistants, vision, batch, fine-tune, user_data, evals
expires_afterOptional TTL UNVERIFIED 2026-05-23 — verify the OpenAPI for current shape
+
+ +

Videos API — videos.create

+
+ + + + + + + + + + +
ParameterAllowed
modelsora-2, sora-2-pro
promptFree-text; respect content policy
size1280x720, 720x1280, 1920x1080, 1080x1920 (1920x1080/1080x1920 require sora-2-pro)
secondsAPI reference: 4, 8, 12 (default 4) — confirmed 2026-05-23. Cookbook also mentions 16, 20 (may be enabled via OpenAPI/batch only).
input_referenceMultipart file or JSON {file_id: "..."} / {image_url: "..."} (JPEG/PNG/WebP, must match size)
characters[]Array of {id: "char_..."} (up to 2; only non-human likeness unless approved)
+
+ +

4.10 Limitações & gotchas

+

Cross-cutting list to surface as "watch outs" in the comparative HTML guide.

+ +

Vision

+
    +
  • Medical images: not for diagnosis.
  • +
  • Non-Latin scripts and small text are weaker — enlarge text, prefer detail: "original" on gpt-5.4+.
  • +
  • Rotated content can be misread.
  • +
  • Graphs with dashed/dotted/colored variants: weak comprehension.
  • +
  • Spatial reasoning (chess, layout) is unreliable.
  • +
  • Panoramas and fisheye distortion: weak.
  • +
  • File metadata (EXIF, filename) is never read.
  • +
  • CAPTCHAs are blocked.
  • +
  • Images > 8 MB on Chat Completions image_url are silently dropped.
  • +
  • TPM accounting: every image counts.
  • +
  • Counting objects: approximate.
  • +
+ +

Files

+
    +
  • input_file is per-request capped at 50 MB total (per file ≤ 50 MB).
  • +
  • Non-PDF docs lose embedded images/charts (text-only extraction). Convert to PDF if visuals matter.
  • +
  • Spreadsheet ingestion stops at the first 1,000 rows per sheet. Use Code Interpreter or Hosted Shell for larger sheets.
  • +
  • PDF parsing needs vision-capable models (gpt-5.5 e família gpt-5.4). Older models won't see page images.
  • +
  • purpose matters: model-input use cases must use user_data (not assistants).
  • +
  • Chat Completions doesn't support file_url; Responses does.
  • +
+ +

Code Interpreter

+
    +
  • Container expires after 20 minutes of idle.
  • +
  • All container files vanish at expiration — download what you need.
  • +
  • Filesystem is ephemeral block storage; no networking unless explicitly enabled.
  • +
  • memory_limit is fixed for life of container.
  • +
  • Rate limit: 100 RPM per org for the tool.
  • +
+ +

Audio

+
    +
  • Transcription/translation upload: 25 MB max, must be chunked for longer.
  • +
  • Whisper-1: 224 tokens max prompt; no streaming.
  • +
  • Diarize: chunking_strategy required > 30s; no prompt/logprobs/timestamps; max 4 known speakers; reference clips 2–10s.
  • +
  • Realtime sessions: 60-minute max (corrigido 2026-05-23); chunks ≤ 15 MB; PCM16/G.711 only; no MP3/Opus input.
  • +
  • Chat Completions input_audio is the current canonical audio-chat surface — Responses audio is "Coming soon".
  • +
  • Audio output application state retained 1 h for multi-turn conversations.
  • +
+ +

Video

+
    +
  • No native video input on Responses today; use frame-extraction + transcription pattern.
  • +
  • Sora 2 generates max 20s per render; up to 6 extensions to 120s total.
  • +
  • Sora rejects real people, copyrighted characters/music, NSFW, and (by default) any human-face reference.
  • +
  • Sora download URLs are valid only 1 hour (24 h for Batch).
  • +
  • Sora 1080p only on sora-2-pro (and $0.70/sec at 1080p).
  • +
+ +

4.11 Pricing & token accounting

+

Refer to the live pricing pages for current per-token / per-second / per-asset rates:

+
    +
  • Model pricing: https://developers.openai.com/api/docs/pricing#latest-models
  • +
  • Built-in tool rates (Code Interpreter, File Search, Web Search, Image Generation, Computer Use, Hosted Shell): https://developers.openai.com/api/docs/pricing#built-in-tools
  • +
  • Vision/image pricing calculator: https://openai.com/api/pricing/ (FAQ section).
  • +
+ +

How OpenAI bills each modality

+
+ + + + + + + + + + + + + + + +
ModalityBilling unitHow it's computed
Text input/outputInput/output tokensStandard tokenizer
Image input (patch-based models)Input tokensresized_patch_count * model_multiplier (see formulas above)
Image input (tile-based models)Input tokensbase_tokens + tile_count * per_tile_tokens (tile count derived from detail and image size)
PDF inputInput tokensSum of extracted-text tokens plus per-page image tokens (image tokenization as above)
Spreadsheet inputInput tokensTokens for first 1,000 rows + auto-generated header/summary metadata
Image generation (gpt-image-2)Image output tokens + image input tokens (for edits/refs)Aspect-ratio-dependent. With high input fidelity, +4,160 (square) or +6,240 (portrait/landscape) input tokens.
Audio (Chat)Audio input tokens + audio output tokens + text tokensgpt-audio-1.5 quotes separate per-token rates for audio I/O.
Audio transcription (gpt-4o-transcribe)Per-minute (audio minutes per minute is an explicit rate metric)Plus token-based output billing.
Realtime sessionsPer-input/output token (audio + text streams)Sessions ≤ 60 min (corrigido 2026-05-23); audio chunks ≤ 15 MB.
Video generation (Sora)Per-second of generated video1080p on sora-2-pro = $0.70/sec; lower-res rates per the pricing page.
Code InterpreterPer-container, billed per minute since 2026-06-02 (5-minute minimum per session)Higher memory_limit tiers cost more.
+
+
The Counting-tokens guide notes that count_tokens supports file_id, file_url, or file_data for files (currently PDFs) and that "the token count reflects the model's full processed input." This is the most reliable way to forecast PDF cost.
+ +

Image-input billing cheatsheet

+
    +
  • detail: low is the cheapest path; always use it for thumbnails, previews, or any "is this safe / what category" task.
  • +
  • detail: high doubles or triples the bill on tile-based models; on patch-based models the budget jumps from 1,536 → 2,500 patches.
  • +
  • detail: original on gpt-5.4+ allows up to 10,000 patches — by far the most expensive image input, but the only mode that captures dense text/small UI.
  • +
  • Plan for the multiplier on *-mini (1.62×) and *-nano (2.46×): the same image costs more on the smaller models, not less. Use Code Interpreter / Hosted Shell + smaller models for cheap aggregations, and only escalate to vision on the frontier model when the picture is the question.
  • +
+ +

Consolidated unverified items (2026-05-23)

+
    +
  • UNVERIFIED 2026-05-23 PDF "100 pages" cap — not documented in current File-inputs guide; only the 50 MB per-file cap is explicit.
  • +
  • UNVERIFIED 2026-05-23 Files expires_after exact syntax — present in the OpenAPI but not detailed here.
  • +
  • UNVERIFIED 2026-05-23 Token multiplier for gpt-5.5 and gpt-5.4 themselves on patch-based images — the live multiplier table on this date enumerates only mini/nano variants.
  • +
  • UNVERIFIED 2026-05-23 Native input_video on Responses or Chat Completions — none documented. Frame extraction is the working pattern.
  • +
+
+
+
Google Gemini
+

Gemini — deep dive

+

Tudo o que o Gemini Developer API aceita como entrada multimodal — imagem, PDF, planilha, vídeo, áudio — passa pelo mesmo endpoint generateContent e pelo mesmo modelo de Part. Esta seção destrincha cada superfície, cada limite, cada tabela de tokens, parâmetros, exemplos rodáveis em Python e TypeScript, e os pontos onde a documentação oficial diverge da prática. Tudo verificado em 2026-05-23 contra a doc oficial (ai.google.dev/gemini-api/docs/*) via o MCP geminiApiDocs; o que não foi confirmado é marcado UNVERIFIED (2026-05-23).

+ +
+ Aviso legado. Os SDKs antigos google-generativeai (Python) e @google/generative-ai (JavaScript) são deprecated. Use apenas os novos google-genai / @google/genai. Modelos default deste guia: gemini-3.1-pro-preview, gemini-3.5-flash e gemini-3.1-flash-lite. +
+ + + + +

5.1 API surface

+

O Gemini Developer API é exposto sob https://generativelanguage.googleapis.com, com a versão estável em /v1beta e flags experimentais (notavelmente media_resolution por part) em /v1alpha. O upload de arquivos grandes vai por um host separado (/upload/v1beta/files) usando o protocolo de upload reservadamente resumable do Google. A autenticação preferida hoje é o header x-goog-api-key (em vez do antigo ?key= em query).

+ +

SDKs e endpoints

+
+ + + + + + + + + + +
SuperfícieEndpoint / pacotePropósito
SDK Pythonpip install google-genai; from google import genaiTodas as APIs Gemini (texto, multimodal, files, caches, tuning, batches, embeddings).
SDK JavaScript/TypeScriptnpm install @google/genai; import { GoogleGenAI } from "@google/genai"Mesma superfície do Python; Node ≥ 18 / browsers modernos (em alguns entry points).
SDK Gogoogle.golang.org/genaiMesma superfície.
RESThttps://generativelanguage.googleapis.com/v1betaTodas as capabilities. v1alpha é usado apenas para flags experimentais como per-part media_resolution (Gemini 3 only).
Upload hosthttps://generativelanguage.googleapis.com/upload/v1beta/filesUpload resumable multipart para o Files API.
AuthHeader x-goog-api-key: $GEMINI_API_KEY (preferido) ou query ?key=A recomendação mais recente é a forma por header.
+
+ +

Construção do client (padrão atual)

+
+
+ + +
+
+
from google import genai
+from google.genai import types
+
+# Reads GEMINI_API_KEY from env by default.
+client = genai.Client()
+
+
+
import { GoogleGenAI } from "@google/genai";
+const ai = new GoogleGenAI({}); // reads GEMINI_API_KEY from env
+
+
+ +

RPCs principais que aceitam input multimodal

+
+ + + + + + + + + + + + +
RPCSDK call (Python)Uso
models.generateContentclient.models.generate_content(model=..., contents=[...])Geração multimodal one-shot (síncrono, bloqueante).
models.streamGenerateContentclient.models.generate_content_stream(...) (Python) / generateContentStream (JS)Streaming SSE de tokens gerados; deltas de tools/parts.
models.countTokensclient.models.count_tokens(model=..., contents=[...])Estimativa de tokens para qualquer combinação de parts (text, image, PDF, audio, video). Útil antes de enviar request grande.
caches.create / list / get / update / deleteclient.caches.*Context caching explícito para prefixos multimodais muito grandes (vídeos longos, PDFs grandes).
files.upload / get / list / delete / register_filesclient.files.*Files API, registro de arquivos no GCS, metadados.
chats.create + chat.send_messageclient.chats.*Camada de conveniência multi-turn sobre generateContent.
Live API (live.connect)client.aio.live.connect(...) (Python async)Sessões realtime bidirecionais áudio/vídeo. Transport WebSocket separado; não invocada via generateContent.
Batch APIclient.batches.create(...)Geração multimodal assíncrona em massa a 50% do custo padrão.
+
+ +

O modelo de Part (do que é feito um Content)

+

Toda requisição Gemini é uma lista de objetos Content, cada um com um role ("user" ou "model") e uma lista de Part. Um Part é uma tagged union — exatamente um dos campos abaixo está setado:

+
+ + + + + + + + + + + + + + +
Campo do PartTipoSignificado
textstringSegmento de texto puro do prompt ou da resposta do modelo.
inlineData (REST inline_data)Blob { mimeType, data }Bytes de arquivo inline em base64 (image, PDF, audio, vídeo curto).
fileData (REST file_data)FileData { fileUri, mimeType }Referência a URI do Files API, URI GCS registrada, URL HTTPS pública (≤100 MB), URL assinada S3/Azure, ou URL do YouTube.
functionCall{ name, args }Chamada de tool emitida pelo modelo (function calling).
functionResponse{ name, response }Resultado fornecido pelo desenvolvedor para uma tool call.
executableCode{ language, code }Python que o modelo quer rodar via sandbox interno de code execution.
codeExecutionResult{ outcome, output }Resultado da execução de código (e imagens inline para plots).
videoMetadata{ startOffset, endOffset, fps }Companheiro de um part fileData/inlineData de vídeo — clipping + taxa de amostragem.
mediaResolution (per-part){ level: MEDIA_RESOLUTION_* }Override de resolução por imagem/video/PDF. Gemini 3 apenas, v1alpha apenas.
thoughtSignaturestring opacaToken interno de preservação de contexto (deve ser ecoado quando você constrói manualmente histórico de tool-use com code execution).
+
+ +

O GenerationConfig top-level (a.k.a. GenerateContentConfig nos SDKs) também pode globalmente setar mediaResolution, responseMimeType, responseSchema, thinkingConfig, tools, systemInstruction etc.

+ +

Roles e realtime

+
    +
  • Geração standard: síncrono generateContent / streaming streamGenerateContent.
  • +
  • Realtime: a Live API — gemini-3.1-flash-live-preview. Expõe um transporte WebSocket bidirecional para áudio in/áudio out/vídeo in/texto out/function calling. É conceitualmente separada do generateContent mas reaproveita o mesmo modelo de Part.
  • +
+ + + + +

5.2 Imagem / visão

+

O Gemini trata imagens como cidadãs de primeira classe — pode ler até 3 600 imagens por request, suporta cinco MIME types nativos para vision, e oferece três caminhos de ingestão (inline, Files API, URL externa, GCS registrado). Aqui consolidamos MIME, limites, exemplos de cada caminho, a matemática de tokens por tile, e o controle fino via media_resolution global e per-part.

+ +

MIME types suportados

+
+ + + + + + + + + +
FormatoMIME
PNGimage/png
JPEGimage/jpeg
WEBPimage/webp
HEICimage/heic
HEIFimage/heif
+
+
+ BMP não está na lista nativa. BMP é aceito pelo tool de URL-context e pelo path de fetch de External URL — mas para vision multimodal direto em generateContent, fique com PNG/JPEG/WEBP/HEIC/HEIF (ou converta). +
+ +

Três (na verdade quatro) caminhos de input

+
+ + + + + + + + +
MétodoMelhor paraLimite hard
Inline (inlineData / Part.from_bytes)Testes rápidos, imagens one-off, apps real-time.20 MB no total do request (texto + system + TODOS os bytes inline). Inline data de um único arquivo pode ir até 100 MB pela nova tabela de input methods, mas para PDFs o cap é 50 MB; na prática a doc recomenda Files API acima de 20 MB.
Files API (fileData / client.files.upload)Imagens grandes, reuso em várias requests, batch.2 GB por arquivo, 20 GB por projeto. Retenção: 48 horas.
External HTTPS / signed URL (fileData.fileUri = "https://...")Dados web públicos, S3 presigned, Azure SAS.100 MB por payload de request.
GCS registration (client.files.register_files(uris=[...]))Arquivos já em GCS — sem re-upload, validade até 30 dias.2 GB por arquivo, sem cap geral de storage. Requer service-account auth e IAM Storage Object Viewer.
+
+ +

Limite de contagem por request: Gemini suporta no máximo 3 600 imagens por request.

+ +

Imagem inline — Python

+
from google import genai
+from google.genai import types
+
+with open("path/to/sample.jpg", "rb") as f:
+    image_bytes = f.read()
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",  # ou gemini-3.1-pro-preview / gemini-3.1-flash-lite
+    contents=[
+        types.Part.from_bytes(data=image_bytes, mime_type="image/jpeg"),
+        "Caption this image."
+    ],
+)
+print(response.text)
+ +

Imagem inline — TypeScript

+
import { GoogleGenAI } from "@google/genai";
+import * as fs from "node:fs";
+
+const ai = new GoogleGenAI({});
+const base64ImageFile = fs.readFileSync("path/to/sample.jpg", { encoding: "base64" });
+
+const response = await ai.models.generateContent({
+  model: "gemini-3.5-flash",
+  contents: [
+    { inlineData: { mimeType: "image/jpeg", data: base64ImageFile } },
+    { text: "Caption this image." },
+  ],
+});
+console.log(response.text);
+ +

Imagem por URL (download e envia inline) — Python

+
import requests
+from google import genai
+from google.genai import types
+
+image_bytes = requests.get("https://goo.gle/instrument-img").content
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        "What is this image?",
+        types.Part.from_bytes(data=image_bytes, mime_type="image/jpeg"),
+    ],
+)
+print(response.text)
+ +

Files API upload — Python

+
from google import genai
+
+client = genai.Client()
+my_file = client.files.upload(file="path/to/sample.jpg")  # MIME auto-detected
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[my_file, "Caption this image."],
+)
+print(response.text)
+ +

Files API upload — TypeScript

+
import { GoogleGenAI, createUserContent, createPartFromUri } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const myfile = await ai.files.upload({
+  file: "path/to/sample.jpg",
+  config: { mimeType: "image/jpeg" },
+});
+
+const response = await ai.models.generateContent({
+  model: "gemini-3.5-flash",
+  contents: createUserContent([
+    createPartFromUri(myfile.uri, myfile.mimeType),
+    "Caption this image.",
+  ]),
+});
+console.log(response.text);
+ +

Múltiplas imagens em um prompt

+

Você pode misturar inline data e referências do Files API à vontade — o modelo processa as parts em ordem do array. Para uma única imagem com prompt, ponha a imagem antes do texto (guia de prompting do Google).

+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+uploaded_file = client.files.upload(file="path/to/image1.jpg")
+
+with open("path/to/image2.png", "rb") as f:
+    img2_bytes = f.read()
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        "What is different between these two images?",
+        uploaded_file,
+        types.Part.from_bytes(data=img2_bytes, mime_type="image/png"),
+    ],
+)
+print(response.text)
+ +

Contagem de tokens para imagens

+
+ + + + + + +
Tamanho da imagemTokens
Ambas dimensões ≤ 384 px258 tokens (único tile)
Imagens maioresCortadas em tiles de 768×768 px, cada um custando 258 tokens
+
+ +

Uma fórmula aproximada para o número de tiles em imagens maiores:

+
crop_unit = floor(min(width, height) / 1.5)
+tiles    = (width / crop_unit) * (height / crop_unit)
+

Exemplo: uma imagem 960×540 tem crop_unit = floor(540/1.5) = 360, as dimensões dividem em 3 × 2 = 6 tiles ⇒ 6 × 258 = 1 548 tokens.

+ +

Media resolution (Gemini 3) — global vs per-part

+

media_resolution (camelCase mediaResolution) limita o número máximo de tokens alocados por imagem (ou frame de vídeo, ou página de PDF renderizada como imagem). Valores válidos:

+
+ + + + + + + + + +
ValorSignificado
MEDIA_RESOLUTION_UNSPECIFIEDDefault — varia por família de modelo.
MEDIA_RESOLUTION_LOWMenos tokens, mais rápido, menos detalhe.
MEDIA_RESOLUTION_MEDIUMBalance de detalhe/custo/latência.
MEDIA_RESOLUTION_HIGHRecomendado para a maioria de tarefas de imagem.
MEDIA_RESOLUTION_ULTRA_HIGHPer-part apenas, para computer-use / detalhe pequeno e denso.
+
+ +

Tokens por resolução (Gemini 3):

+
Gemini 3
+
+ + + + + + + + + +
MediaResolutionImageVideoPDF
UNSPECIFIED (default)112070560
LOW28070280 + Native Text
MEDIUM56070560 + Native Text
HIGH11202801120 + Native Text
ULTRA_HIGH2240N/AN/A
+
+ + +

Global media resolution — Python

+
config = types.GenerateContentConfig(
+    media_resolution=types.MediaResolution.MEDIA_RESOLUTION_HIGH
+)
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=["Describe this image:", image_part],
+    config=config,
+)
+ +

Per-part media resolution (experimental, v1alpha, Gemini 3 only) — Python

+
client = genai.Client(http_options={"api_version": "v1alpha"})
+
+image_part_high = types.Part.from_bytes(
+    data=image_bytes,
+    mime_type="image/jpeg",
+    media_resolution=types.MediaResolution.MEDIA_RESOLUTION_HIGH,
+)
+
+response = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=["Describe these images:", image_part_high],
+)
+ +

Object detection (built-in)

+

Modelos Gemini são treinados para retornar bounding boxes 2D normalizados em [0, 1000] para cada eixo na ordem [ymin, xmin, ymax, xmax], com labels opcionais.

+
from google import genai
+from google.genai import types
+from PIL import Image
+import json
+
+client = genai.Client()
+image = Image.open("/path/to/image.png")
+prompt = (
+    "Detect all of the prominent items in the image. "
+    "The box_2d should be [ymin, xmin, ymax, xmax] normalized to 0-1000."
+)
+config = types.GenerateContentConfig(response_mime_type="application/json")
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[image, prompt],
+    config=config,
+)
+
+w, h = image.size
+for bb in json.loads(response.text):
+    y1 = int(bb["box_2d"][0] / 1000 * h)
+    x1 = int(bb["box_2d"][1] / 1000 * w)
+    y2 = int(bb["box_2d"][2] / 1000 * h)
+    x2 = int(bb["box_2d"][3] / 1000 * w)
+    print(bb.get("label"), (x1, y1, x2, y2))
+ +

O modelo também suporta:

+
    +
  • Bounding boxes com instruções customizadas ("only green objects", "label items by their allergens" etc.).
  • +
  • Pointing (pontos 2D normalizados em [0, 1000]) — bastante usado por Gemini Robotics-ER 1.6.
  • +
  • Trajectory generation como sequência de pontos rotulados.
  • +
  • 3D pointing — experimental, ver o cookbook Spatial_understanding_3d.
  • +
+ +

Image best practices (literal das docs)

+
    +
  • Verifique se as imagens estão rotacionadas corretamente.
  • +
  • Use imagens claras, não borradas.
  • +
  • Para prompts com uma única imagem, ponha o texto depois do part de imagem em contents.
  • +
+ +
+ Limitações específicas de imagem. BMP não está na lista nativa (converta); raciocínio espacial além de bboxes/points/contagem simples ainda pode derrapar em cenas densas — suba media_resolution para HIGH ou use code execution para croppar; coordenadas de object detection são normalizadas em [0,1000] — desescale para o tamanho real. +
+ + + + +

5.3 PDF / documentos

+

Gemini renderiza cada página de PDF como imagem E extrai o texto embarcado (no Gemini 3) — então ele entende layout, charts, diagramas, tabelas, equações e assinaturas, não apenas o texto OCR. Esse caminho é o canônico para qualquer "documento" rico com formatação.

+ +

Limites e formato

+
+ + + + + + + + + +
LimiteValor
Máx páginas por request1 000 páginas (somadas em todos os PDFs do request)
Máx tamanho de PDF (inline ou Files API)50 MB
Tokens por página de PDF (Gemini 3, default)560 tokens; LOW=280, MEDIUM=560, HIGH=1120 (+ native text no Gemini 3, grátis)
Escala da imagemPáginas maiores são reduzidas para no máx 3072×3072; menores são aumentadas para 768×768; aspect ratio é preservado.
Outros MIME "document"Aceitos mas tratados como texto plano — formatação de charts/diagramas/markdown/HTML é perdida.
+
+ +

Inline PDF — Python

+
from google import genai
+from google.genai import types
+import pathlib
+
+client = genai.Client()
+filepath = pathlib.Path("file.pdf")
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        types.Part.from_bytes(
+            data=filepath.read_bytes(),
+            mime_type="application/pdf",
+        ),
+        "Summarize this document",
+    ],
+)
+print(response.text)
+ +

Inline PDF — TypeScript

+
import { GoogleGenAI } from "@google/genai";
+import * as fs from "fs";
+
+const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
+
+const response = await ai.models.generateContent({
+  model: "gemini-3.5-flash",
+  contents: [
+    { text: "Summarize this document" },
+    {
+      inlineData: {
+        mimeType: "application/pdf",
+        data: fs.readFileSync("file.pdf").toString("base64"),
+      },
+    },
+  ],
+});
+console.log(response.text);
+ +

PDF grande via Files API — Python

+
import io, httpx
+from google import genai
+
+client = genai.Client()
+doc_io = io.BytesIO(
+    httpx.get("https://www.nasa.gov/wp-content/uploads/static/history/alsj/a17/A17_FlightPlan.pdf").content
+)
+
+sample_doc = client.files.upload(file=doc_io, config={"mime_type": "application/pdf"})
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[sample_doc, "Summarize this document"],
+)
+print(response.text)
+ +

PDF grande via Files API — TypeScript (com espera de PROCESSING)

+
import { createPartFromUri, GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
+
+const pdfBuffer = await fetch("https://example.com/big.pdf").then((r) => r.arrayBuffer());
+const fileBlob = new Blob([pdfBuffer], { type: "application/pdf" });
+
+const file = await ai.files.upload({
+  file: fileBlob,
+  config: { displayName: "big.pdf" },
+});
+
+// Files for large media (PDF/video) start in PROCESSING — poll until ACTIVE.
+let getFile = await ai.files.get({ name: file.name });
+while (getFile.state === "PROCESSING") {
+  await new Promise((r) => setTimeout(r, 5000));
+  getFile = await ai.files.get({ name: file.name });
+}
+if (getFile.state === "FAILED") throw new Error("File processing failed.");
+
+const response = await ai.models.generateContent({
+  model: "gemini-3.5-flash",
+  contents: [
+    "Summarize this document",
+    createPartFromUri(getFile.uri, getFile.mimeType),
+  ],
+});
+console.log(response.text);
+ +

Múltiplos PDFs em um prompt — Python

+
import io, httpx
+from google import genai
+
+client = genai.Client()
+
+doc1 = client.files.upload(
+    file=io.BytesIO(httpx.get("https://arxiv.org/pdf/2312.11805").content),
+    config={"mime_type": "application/pdf"},
+)
+doc2 = client.files.upload(
+    file=io.BytesIO(httpx.get("https://arxiv.org/pdf/2403.05530").content),
+    config={"mime_type": "application/pdf"},
+)
+
+prompt = (
+    "What is the difference between each of the main benchmarks between "
+    "these two papers? Output these in a table."
+)
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[doc1, doc2, prompt],
+)
+print(response.text)
+ +

PDF best practices

+
    +
  • Pré-rotacione páginas para a orientação correta antes do upload.
  • +
  • Evite scans borrados; se o PDF for image-only e ruidoso, aumente resolução ou pré-processe.
  • +
  • Para extração de página única em alta precisão, ponha o prompt depois da página.
  • +
  • Apenas PDFs. Outros MIME de documento (TXT, Markdown, HTML, XML, RTF, …) funcionam mas perdem contexto visual/layout. O modelo os vê como texto plano.
  • +
  • Para tabelas densas, use media_resolution=MEDIUM (o default recomendado para PDFs); HIGH raramente melhora OCR de documentos padrão.
  • +
+ +

Comportamento específico de PDF no Gemini 3

+
    +
  1. Inclusão de texto nativo: o texto nativamente embarcado no PDF é extraído e fornecido ao modelo lado a lado com a imagem renderizada da página.
  2. +
  3. Billing / reporting de tokens: +
      +
    • Tokens de native text não são cobrados.
    • +
    • Tokens de "página como imagem" são reportados sob a modalidade IMAGE em usage_metadata (não há uma modalidade DOCUMENT separada).
    • +
    +
  4. +
+ + + + +

5.4 Office / Excel / CSV

+

A vision documental do Gemini é engenheirada para PDF. Para outros formatos de Office e tabulares, prefira um dos caminhos abaixo:

+
    +
  1. Converter para PDF antes de fazer upload (melhor fidelidade para Office docs).
  2. +
  3. Mandar como texto para formatos texto plano (o modelo não vai ver formatação).
  4. +
  5. Usar a tool de Code Execution para spreadsheets — deixe o sandbox parsear XLSX/CSV com pandas.
  6. +
+ +

MIMEs aceitos pelo Files API e External URL fetcher

+

Lista oficial de content types "External HTTP / Signed URLs" (que espelha em larga medida o que o File API aceita para documentos tipo-texto):

+ +
Text MIME types
+
+ + + + + + + + + + + + +
MIMEObservações
text/plainTexto plano UTF-8.
text/htmlTratado como texto (tags visíveis mas não renderizadas).
text/cssCódigo-fonte.
text/xmlCódigo-fonte.
text/csvTexto tabular — Gemini vê o conteúdo CSV cru.
text/rtfTexto com markup.
text/javascriptCódigo-fonte.
text/markdownNão está na lista oficial External-URL; usado comumente inline como text/plain.
+
+ +
Application MIME types
+
+ + + + + + +
MIMEObservações
application/jsonJSON como texto.
application/pdfVision nativa de PDF — entendimento documental completo.
+
+ +

Image / Video / Audio — cobertos nas seções respectivas.

+ +
+ A lista de External-URL "is intended as initial guidance and is not comprehensive". O Files API em si aceita MIME types arbitrários para upload, mas o modelo só faz raciocínio multimodal profundo em image, audio, video e PDF; tudo o mais é interpretado como texto. +
+ +

CSV — texto inline

+
from google import genai
+from google.genai import types
+import pathlib
+
+csv_bytes = pathlib.Path("sales.csv").read_bytes()
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        types.Part.from_bytes(data=csv_bytes, mime_type="text/csv"),
+        "Summarize total sales by region and month.",
+    ],
+)
+print(response.text)
+ +

Para qualquer coisa além de CSVs de brinquedo, use code execution (próxima seção). De outro modo o modelo tem que "ler" o CSV inteiro como tokens.

+ +

XLSX — padrão recomendado (Code Execution sandbox)

+

application/vnd.openxmlformats-officedocument.spreadsheetml.sheet é UNVERIFIED (2026-05-23) como content type entendido diretamente pela vision nativa do Gemini; a lista oficial External-URL não o inclui. Padrão recomendado:

+
    +
  1. Subir o XLSX via Files API.
  2. +
  3. Habilitar Code Execution como tool.
  4. +
  5. Instruir o modelo a carregar o workbook com pandas.read_excel(...), então computar/plotar o que precisar. O sandbox retorna charts como imagens inline.
  6. +
+ +
from google import genai
+from google.genai import types
+
+client = genai.Client()
+xlsx = client.files.upload(file="sales_2026.xlsx")  # 50 MB+ allowed via Files API
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        xlsx,
+        "Load the Excel workbook with pandas, then "
+        "(a) report total revenue by region for 2026, "
+        "(b) plot monthly revenue, and "
+        "(c) return the chart as an image.",
+    ],
+    config=types.GenerateContentConfig(
+        tools=[types.Tool(code_execution=types.ToolCodeExecution)],
+    ),
+)
+
+for part in response.candidates[0].content.parts:
+    if part.text:
+        print(part.text)
+    if getattr(part, "executable_code", None):
+        print("CODE:\n", part.executable_code.code)
+    if getattr(part, "code_execution_result", None):
+        print("OUTPUT:\n", part.code_execution_result.output)
+ +

Outros formatos Office (DOCX / PPTX)

+

UNVERIFIED (2026-05-23) — o Google não documentou vision nativa para .docx / .pptx. Converta-os para PDF primeiro (e.g. via LibreOffice ou serviço de rendering em cloud) para a melhor fidelidade. O Files API armazena qualquer MIME, mas o modelo só faz vision documental completa em PDF.

+ + + + +

5.5 Code execution

+

O Gemini vem com uma tool de code execution Python sandboxed. O modelo decide quando escrever código, o sandbox roda, e o resultado volta ao contexto para o modelo raciocinar em cima. É a contraparte do Code Interpreter da OpenAI — só que sem endpoint próprio para containers, é apenas uma tool habilitada inline em generateContent.

+ +

Habilitar a tool — Python

+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=(
+        "What is the sum of the first 50 prime numbers? "
+        "Generate and run code for the calculation, and make sure you get all 50."
+    ),
+    config=types.GenerateContentConfig(
+        tools=[types.Tool(code_execution=types.ToolCodeExecution)],
+    ),
+)
+
+for part in response.candidates[0].content.parts:
+    if part.text is not None:
+        print(part.text)
+    if part.executable_code is not None:
+        print(part.executable_code.code)
+    if part.code_execution_result is not None:
+        print(part.code_execution_result.output)
+ +

Habilitar a tool — TypeScript

+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const response = await ai.models.generateContent({
+  model: "gemini-3.5-flash",
+  contents: [
+    "What is the sum of the first 50 prime numbers? Generate and run code.",
+  ],
+  config: { tools: [{ codeExecution: {} }] },
+});
+
+for (const part of response?.candidates?.[0]?.content?.parts || []) {
+  if (part.text) console.log(part.text);
+  if (part.executableCode) console.log(part.executableCode.code);
+  if (part.codeExecutionResult) console.log(part.codeExecutionResult.output);
+}
+ +

Tipos de part na resposta

+
+ + + + + + + + +
PartCampo na responseSignificado
textpart.textComentário inline do modelo.
executableCodepart.executableCode.{language, code}Source que o modelo decidiu rodar. language é tipicamente PYTHON.
codeExecutionResultpart.codeExecutionResult.{outcome, output}outcome é e.g. OUTCOME_OK; output é stdout / resultado inline.
inlineDatapart.inlineData.{mimeType, data}Artefatos gerados (charts matplotlib voltam como bytes PNG/JPEG inline).
+
+ +

Propriedades do sandbox

+
+ + + + + + + + + + + + +
PropriedadeValor
LinguagemPython only (o modelo pode escrever outras linguagens como texto, mas elas não executam).
Wall time máximo por invocação30 segundos.
Auto-retryO modelo pode regerar código após erros até 5 vezes em um turno.
Tamanho máximo de arquivo de inputLimitado pela context window do modelo. Em AI Studio: 1 M tokens (~2 MB para texto).
Shape do part de inputpart.inlineData ou part.fileData (upload via Files API).
Shape do part de outputSempre part.inlineData (charts como imagens inline).
NetworkO sandbox não tem acesso outbound à rede.
id / thoughtSignature discipline (REST)Ao replayar turns manualmente (REST ou histórico hand-built), eche o id em executableCode e codeExecutionResult, e propague thoughtSignature em cada part emitido pelo modelo. SDKs fazem isso automaticamente.
+
+ +

Bibliotecas suportadas no sandbox

+

Confirmado contra a página oficial de Code Execution em 2026-05-23. O sandbox vem pré-instalado com 37 bibliotecas (lista canônica):

+
+ Lista completa (37 libs) +
    +
  • attrs
  • +
  • chess
  • +
  • contourpy
  • +
  • fpdf
  • +
  • geopandas
  • +
  • imageio
  • +
  • jinja2
  • +
  • joblib
  • +
  • jsonschema
  • +
  • jsonschema-specifications
  • +
  • lxml
  • +
  • matplotlib
  • +
  • mpmath
  • +
  • numpy
  • +
  • opencv-python
  • +
  • openpyxl
  • +
  • packaging
  • +
  • pandas
  • +
  • pillow
  • +
  • protobuf
  • +
  • pylatex
  • +
  • pyparsing
  • +
  • PyPDF2
  • +
  • python-dateutil
  • +
  • python-docx
  • +
  • python-pptx
  • +
  • reportlab
  • +
  • scikit-learn
  • +
  • scipy
  • +
  • seaborn
  • +
  • six
  • +
  • striprtf
  • +
  • sympy
  • +
  • tabulate
  • +
  • tensorflow
  • +
  • toolz
  • +
  • xlrd
  • +
+
+

O modelo pode import qualquer destas mas não pode pip install (sandbox sem rede). Apenas matplotlib é capaz de renderizar charts inline (saem como inlineData PNG/JPEG no response).

+ +

Code execution com imagens (Gemini 3)

+

O Gemini 3 Flash pode escrever Python que manipula a imagem de entrada: croppar, rotacionar, dar zoom para OCR de texto pequeno, anotar com setas, etc.

+
from google import genai
+from google.genai import types
+import requests, io
+from PIL import Image
+
+image_bytes = requests.get("https://goo.gle/instrument-img").content
+image_part = types.Part.from_bytes(data=image_bytes, mime_type="image/jpeg")
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[image_part, "Zoom into the expression pedals and tell me how many pedals are there?"],
+    config=types.GenerateContentConfig(
+        tools=[types.Tool(code_execution=types.ToolCodeExecution)],
+    ),
+)
+
+for part in response.candidates[0].content.parts:
+    if part.text:
+        print(part.text)
+    if getattr(part, "executable_code", None):
+        print(part.executable_code.code)
+    if getattr(part, "code_execution_result", None):
+        print(part.code_execution_result.output)
+    if part.as_image() is not None:  # generated artifact
+        display(Image.open(io.BytesIO(part.as_image().image_bytes)))
+ +

Code execution em chat

+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+chat = client.chats.create(
+    model="gemini-3.5-flash",
+    config=types.GenerateContentConfig(
+        tools=[types.Tool(code_execution=types.ToolCodeExecution)]
+    ),
+)
+chat.send_message("I have a math question for you.")
+response = chat.send_message(
+    "Sum the first 50 primes; show code and answer."
+)
+for part in response.candidates[0].content.parts:
+    if part.text:
+        print(part.text)
+    if part.executable_code:
+        print(part.executable_code.code)
+    if part.code_execution_result:
+        print(part.code_execution_result.output)
+ +

Code execution I/O — pricing

+

Code execution não é cobrado em separado — você paga apenas pelos input + output tokens à taxa do modelo configurado. Especificamente:

+
    +
  • Código gerado conta como output tokens.
  • +
  • Imagens geradas (e.g. charts) contam como output tokens também (output multimodal).
  • +
  • Resultados de code execution (stdout) contam como output tokens.
  • +
  • Thinking tokens são cobrados como output tokens.
  • +
+ + + + +

5.6 Vídeo

+

Vídeo é onde o Gemini se destaca de longe entre os três providers. Aceita inline (curto), Files API (até 2 GB), arquivo registrado em GCS, e — único entre os três — URL do YouTube direto. Aqui consolidamos os caminhos, MIME types, exemplos Python/TS, clipping com videoMetadata, custom FPS, e as tabelas de tokens (Gemini 3 com 70 tok/frame; baseline count_tokens ~300 tok/s).

+ +

Input methods de relance

+
+ + + + + + + + +
MétodoTamanho máxMelhor para
Files API (default)20 GB (paid) / 2 GB (free)Vídeos grandes/longos (≥10 min), arquivos reusáveis.
Cloud Storage registration2 GB por arquivo, sem cap geral de storageJá em GCS; persistente.
Inline (inlineData)< 100 MB total do payload, recomendado < 20 MBClipes curtos (< 1 min).
YouTube URL (fileData.fileUri = "https://www.youtube.com/watch?v=…")N/AVídeos públicos no YouTube. Preview, gratuito.
+
+ +

MIME types suportados

+

video/mp4, video/mpeg, video/quicktime, video/avi, video/x-flv, video/mpg, video/webm, video/wmv, video/3gpp.

+ +

Files API upload + summarize — Python

+
from google import genai
+
+client = genai.Client()
+myfile = client.files.upload(file="path/to/sample.mp4")
+# Large videos start in PROCESSING — wait for ACTIVE.
+import time
+while myfile.state.name == "PROCESSING":
+    time.sleep(2.5)
+    myfile = client.files.get(name=myfile.name)
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        myfile,
+        "Summarize this video. Then create a quiz with an answer key.",
+    ],
+)
+print(response.text)
+ +

Files API upload — TypeScript

+
import { GoogleGenAI, createUserContent, createPartFromUri } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const myfile = await ai.files.upload({
+  file: "path/to/sample.mp4",
+  config: { mimeType: "video/mp4" },
+});
+
+let getFile = await ai.files.get({ name: myfile.name });
+while (getFile.state === "PROCESSING") {
+  await new Promise((r) => setTimeout(r, 5000));
+  getFile = await ai.files.get({ name: myfile.name });
+}
+
+const response = await ai.models.generateContent({
+  model: "gemini-3.5-flash",
+  contents: createUserContent([
+    createPartFromUri(getFile.uri, getFile.mimeType),
+    "Summarize this video.",
+  ]),
+});
+console.log(response.text);
+ +

Vídeo inline — Python (< 20 MB)

+
from google import genai
+from google.genai import types
+
+video_bytes = open("/path/to/video.mp4", "rb").read()
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=types.Content(
+        parts=[
+            types.Part(inline_data=types.Blob(data=video_bytes, mime_type="video/mp4")),
+            types.Part(text="Please summarize the video in 3 sentences."),
+        ]
+    ),
+)
+print(response.text)
+ +

YouTube URL — Python (preview, gratuito)

+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=types.Content(parts=[
+        types.Part(file_data=types.FileData(file_uri="https://www.youtube.com/watch?v=9hE5-98ZeCg")),
+        types.Part(text="Please summarize the video in 3 sentences."),
+    ]),
+)
+print(response.text)
+ +
+ YouTube limits. Tier gratuito: ≤ 8 horas de YouTube por dia. Tier pago: sem limite de comprimento. Apenas vídeos públicos (sem unlisted/private). Até 10 vídeos por request. +
+ +

Timestamps & referências

+

Timestamps no prompt usam o formato MM:SS (e.g. 01:15 para 1 minuto e 15 segundos).

+
prompt = "What are the examples given at 00:05 and 00:10 supposed to show us?"
+ +

Clipping do vídeo (videoMetadata)

+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="models/gemini-3.5-flash",
+    contents=types.Content(parts=[
+        types.Part(
+            file_data=types.FileData(file_uri="https://www.youtube.com/watch?v=XEzRZ35urlk"),
+            video_metadata=types.VideoMetadata(start_offset="1250s", end_offset="1570s"),
+        ),
+        types.Part(text="Please summarize the video in 3 sentences."),
+    ]),
+)
+ +

Frame rate customizado (videoMetadata.fps)

+

Amostragem default = 1 frame por segundo. Você pode sobrescrever:

+
types.VideoMetadata(fps=5)    # 5 FPS — clipes com ação rápida
+types.VideoMetadata(fps=0.2)  # 1 frame a cada 5 segundos — palestras, conteúdo estático
+

FPS mais alto = mais frames amostrados = mais tokens. FPS mais baixo para palestras estáticas longas.

+
+ Safety. Verificações de safety per-frame fazem com que um mesmo vídeo possa ser bloqueado em um FPS e passar em outro (frames diferentes são extraídos). +
+ +

Contagem de tokens para vídeo

+

Em mediaResolution default:

+
+ + + + + + + + +
ComponenteTokens / segundo
Visual frames (1 FPS, 258 tok/frame em default; 66 tok/frame em LOW)258 (default) / 66 (LOW)
Track de áudio (16 Kbps, single channel)32
Metadadosincluído
Total por segundo~ 300 tokens/seg (default) ou ~ 100 tokens/seg (LOW)
+
+ +

Para Gemini 3 com mediaResolution:

+
+ + + + + + + + +
MediaResolutionTokens por frame
UNSPECIFIED (default)70
LOW70
MEDIUM70
HIGH280
+
+

Para Gemini 3, LOW/MEDIUM são tratados identicamente (70 tokens) para otimizar uso de contexto. HIGH só é necessário quando lendo texto pequeno e denso ou detalhe fino em frames.

+ +

Long-context limits

+

Modelos com context window de 1M tokens podem processar vídeos de até:

+
    +
  • 1 hora em media resolution default.
  • +
  • 3 horas em media resolution low.
  • +
+

Quando mediaResolution=LOW, você cabe ~3× mais vídeo na mesma context window.

+ +

Video best practices (das docs)

+
    +
  • Use apenas um vídeo por prompt para resultados ótimos (máx 10 por request).
  • +
  • Coloque texto depois do part de vídeo em contents para prompts de vídeo único.
  • +
  • Sequências de ação rápida podem perder detalhe a 1 FPS — desacelere antes do upload OU suba o FPS.
  • +
  • Use context caching para vídeos > 10 min reusados em múltiplas queries.
  • +
+ +

Files API processing de vídeo

+
    +
  • Armazenado a 1 FPS visual + 1 Kbps single-channel audio.
  • +
  • Timestamps adicionados a cada segundo.
  • +
  • Essas taxas podem mudar no futuro para melhorias de inference.
  • +
+ + + + +

5.7 Áudio

+

Áudio no Gemini é cobrado a 32 tokens por segundo, sempre downsampleado para 16 Kbps mono, e o teto combinado por request é de 9.5 horas. Ele entende fala (transcrição, tradução, emoção) e não-fala (sons ambiente, música, animais). Real-time transcription não é via generateContent — é a Live API.

+ +

MIME types suportados

+

audio/wav, audio/mp3, audio/aiff, audio/aac, audio/ogg (Vorbis), audio/flac.

+
+ audio/mpeg — usado em alguns exemplos JS — é tratado equivalentemente a audio/mp3 para upload. A lista canônica da doc usa audio/mp3. +
+ +

Contagem de tokens

+
    +
  • 32 tokens por segundo de áudio.
  • +
  • 1 minuto → 1 920 tokens. 1 hora → 115 200 tokens.
  • +
  • Áudio multi-channel é mixado para mono.
  • +
  • Source é downsampleada para 16 Kbps.
  • +
  • Tamanho máximo total de áudio por request: 9.5 horas combinadas, sem limite de contagem por arquivo.
  • +
+ +

Capacidades

+
    +
  • Speech-to-text (transcrição) — mas sem real-time transcription; use Google Cloud Speech-to-Text API para isso, ou a Live API para realtime conversacional.
  • +
  • Tradução (no mesmo prompt da transcrição).
  • +
  • Detecção de emoção em fala e música.
  • +
  • Compreensão de não-fala (canto de pássaro, sirenes, estrutura musical).
  • +
  • Respostas ancoradas em timestamp ("Transcribe from 02:30 to 03:29").
  • +
+ +

Files API upload + describe — Python

+
from google import genai
+
+client = genai.Client()
+myfile = client.files.upload(file="path/to/sample.mp3")
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=["Describe this audio clip", myfile],
+)
+print(response.text)
+ +

Files API upload + describe — TypeScript

+
import { GoogleGenAI, createUserContent, createPartFromUri } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const myfile = await ai.files.upload({
+  file: "path/to/sample.mp3",
+  config: { mimeType: "audio/mp3" },
+});
+
+const response = await ai.models.generateContent({
+  model: "gemini-3.5-flash",
+  contents: createUserContent([
+    createPartFromUri(myfile.uri, myfile.mimeType),
+    "Describe this audio clip",
+  ]),
+});
+console.log(response.text);
+ +

Áudio inline (< 20 MB request) — Python

+
from google import genai
+from google.genai import types
+
+with open("path/to/small-sample.mp3", "rb") as f:
+    audio_bytes = f.read()
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        "Describe this audio clip",
+        types.Part.from_bytes(data=audio_bytes, mime_type="audio/mp3"),
+    ],
+)
+print(response.text)
+ +

Transcrição estruturada com timestamps + emoção (JSON Schema)

+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+YOUTUBE_URL = "https://www.youtube.com/watch?v=ku-N-eS1lgM"
+
+prompt = """
+Process the audio file and generate a detailed transcription.
+
+Requirements:
+1. Provide accurate timestamps for each segment (Format: MM:SS).
+2. Detect the primary language of each segment.
+3. If the segment is in a language different than English, also provide the English translation.
+4. Identify the primary emotion of the speaker. Choose: Happy, Sad, Angry, Neutral.
+5. Provide a brief summary of the entire audio at the beginning.
+"""
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        types.Content(parts=[
+            types.Part(file_data=types.FileData(file_uri=YOUTUBE_URL)),
+            types.Part(text=prompt),
+        ])
+    ],
+    config=types.GenerateContentConfig(
+        response_mime_type="application/json",
+        response_schema=types.Schema(
+            type=types.Type.OBJECT,
+            properties={
+                "summary": types.Schema(type=types.Type.STRING),
+                "segments": types.Schema(
+                    type=types.Type.ARRAY,
+                    items=types.Schema(
+                        type=types.Type.OBJECT,
+                        properties={
+                            "timestamp": types.Schema(type=types.Type.STRING),
+                            "content": types.Schema(type=types.Type.STRING),
+                            "language": types.Schema(type=types.Type.STRING),
+                            "language_code": types.Schema(type=types.Type.STRING),
+                            "translation": types.Schema(type=types.Type.STRING),
+                            "emotion": types.Schema(
+                                type=types.Type.STRING,
+                                enum=["happy", "sad", "angry", "neutral"],
+                            ),
+                        },
+                        required=["timestamp", "content", "language", "language_code", "emotion"],
+                    ),
+                ),
+            },
+            required=["summary", "segments"],
+        ),
+    ),
+)
+print(response.text)
+ +

Contar tokens de áudio antes de enviar

+
client.models.count_tokens(model="gemini-3.5-flash", contents=[myfile])
+ +

Áudio realtime (Live API)

+

Para conversa voz+vídeo sub-segundo, use a Live API (gemini-3.1-flash-live-preview). É bidirecional (áudio in → áudio out), suporta tool calls, e não é parte do generateContent. Veja a doc da Live API para o transport WebSocket, session resumption, e configuração de voz.

+
+ Nota. O endpoint generateContent em si não streama áudio de saída — o modelo pode ser pedido para descrever áudio, mas retorna texto ou JSON estruturado, não áudio. Output de áudio requer ou um modelo TTS (gemini-3.1-flash-tts-preview) ou a Live API. +
+ + + + +

5.8 Files API

+

O Files API armazena mídia binária (imagem, áudio, vídeo, PDF etc.) para reuso entre requests, desacoplando o upload da geração. É obrigatório para qualquer payload que excederia os limites inline. Aqui detalhamos limites, upload simples via SDK, REST resumable, list/get/delete, o state machine, GCS registration, External URL, e a tabela comparativa de input methods.

+ +

Limites (atuais, oficiais)

+
+ + + + + + + + + + +
PropriedadeValor
Tamanho máx por arquivo2 GB por arquivo
Cap de storage por projeto20 GB total
Retenção48 horas então auto-deletado
DownloadNão suportado — você sobe + pega metadados apenas
CustoGratuito em todas as regiões do Gemini API
State machinePROCESSING → ACTIVE (ou FAILED) para large media
+
+ +

Upload via SDK (simples) — Python

+
from google import genai
+
+client = genai.Client()
+myfile = client.files.upload(file="path/to/sample.mp3")
+print(myfile.uri, myfile.name, myfile.mime_type)
+ +

Upload via SDK (simples) — TypeScript

+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const myfile = await ai.files.upload({
+  file: "path/to/sample.mp3",
+  config: { mimeType: "audio/mpeg" },
+});
+console.log(myfile.uri, myfile.name, myfile.mimeType);
+ +

Upload via REST (two-step resumable)

+
# 1. Start the resumable session (returns an upload URL in response headers).
+curl "https://generativelanguage.googleapis.com/upload/v1beta/files" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -D upload-header.tmp \
+  -H "X-Goog-Upload-Protocol: resumable" \
+  -H "X-Goog-Upload-Command: start" \
+  -H "X-Goog-Upload-Header-Content-Length: ${NUM_BYTES}" \
+  -H "X-Goog-Upload-Header-Content-Type: ${MIME_TYPE}" \
+  -H "Content-Type: application/json" \
+  -d "{'file': {'display_name': 'MY_FILE'}}"
+
+upload_url=$(grep -i "x-goog-upload-url: " upload-header.tmp \
+  | cut -d" " -f2 | tr -d "\r")
+
+# 2. Upload the bytes and finalize.
+curl "${upload_url}" \
+  -H "Content-Length: ${NUM_BYTES}" \
+  -H "X-Goog-Upload-Offset: 0" \
+  -H "X-Goog-Upload-Command: upload, finalize" \
+  --data-binary "@${FILE_PATH}" > file_info.json
+
+file_uri=$(jq -r ".file.uri" file_info.json)
+ +

Em seguida referencie file_uri em uma chamada generateContent:

+
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash:generateContent" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H 'Content-Type: application/json' \
+  -d '{
+    "contents":[{"parts":[
+      {"file_data":{"mime_type":"'"${MIME_TYPE}"'","file_uri":"'"${file_uri}"'"}},
+      {"text":"Describe this file."}
+    ]}]
+  }'
+ +

List, get, delete — Python

+
for f in client.files.list():
+    print(f.name)
+
+info = client.files.get(name=f.name)
+client.files.delete(name=f.name)
+ +

List, get, delete — TypeScript

+
const pager = await ai.files.list({ config: { pageSize: 10 } });
+for await (const f of pager) console.log(f.name);
+
+await ai.files.get({ name: file.name });
+await ai.files.delete({ name: file.name });
+ +

FileState ENUM

+

Mídia grande (vídeo, PDF grande) começa em PROCESSING. Faça polling em files.get(name=...) até state == ACTIVE. Se FAILED, o arquivo não pode ser usado; delete e re-suba.

+
import time
+while myfile.state.name == "PROCESSING":
+    time.sleep(2.5)
+    myfile = client.files.get(name=myfile.name)
+ +

Valores possíveis do enum:

+
STATE_UNSPECIFIED
+PROCESSING
+ACTIVE
+FAILED
+ +

Google Cloud Storage — dois padrões oficiais

+

Para arquivos já em gs://, o SDK python-genai expõe dois caminhos confirmados em google/genai/files.py:

+ +

Padrão 1 — referência direta via Part.from_uri (simples, sem registro prévio):

+ +
from google import genai
+from google.genai import types
+
+client = genai.Client()  # ADC ou GEMINI_API_KEY + scopes Storage
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        types.Part.from_uri(
+            file_uri="gs://my-bucket/some.pdf",
+            mime_type="application/pdf",
+        ),
+        "Summarize this document.",
+    ],
+)
+print(response.text)
+
+ +

Padrão 2 — register_files para bulk + validade até 30 dias:

+ +

Pré-requisitos

+
    +
  1. Habilitar Gemini API no projeto GCP.
  2. +
  3. Criar o service agent: gcloud beta services identity create --service=generativelanguage.googleapis.com --project=<your_project>.
  4. +
  5. Conceder ao service agent Storage Object Viewer nos buckets.
  6. +
  7. Autenticar (service-account key ou ADC) com os scopes https://www.googleapis.com/auth/devstorage.read_only e https://www.googleapis.com/auth/cloud-platform.
  8. +
+ +
from google.oauth2.service_account import Credentials
+from google import genai
+from google.genai.types import Part
+
+credentials = Credentials.from_service_account_file(
+    "service-account.json",
+    scopes=[
+        "https://www.googleapis.com/auth/devstorage.read_only",
+        "https://www.googleapis.com/auth/cloud-platform",
+    ],
+)
+client = genai.Client()
+registered = client.files.register_files(
+    uris=["gs://my-bucket/some.pdf", "gs://my-bucket/talk.mp4"],
+    auth=credentials,
+)
+for f in registered.files:
+    response = client.models.generate_content(
+        model="gemini-3.5-flash",
+        contents=[Part.from_uri(file_uri=f.uri, mime_type=f.mime_type), "Summarize."],
+    )
+    print(response.text)
+
+ +
+ Atualização (2026-05-23): client.files.register_files(uris=[...], auth=credentials) foi confirmado em google/genai/files.py (keyword-only auth + uris, opcional config). Use Padrão 1 para refs únicas/ad-hoc; Padrão 2 para registrar lote de arquivos com validade de até 30 dias. +
+ +

External HTTPS / signed URLs

+

Passe uma URL HTTPS pública ou um S3 presigned / Azure SAS direto em fileData.fileUri. Limite: 100 MB por payload. O sistema faz uma verificação de moderação; URLs reprovadas retornam url_retrieval_status: URL_RETRIEVAL_STATUS_UNSAFE.

+
from google import genai
+from google.genai.types import Part
+
+client = genai.Client()
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=[
+        Part.from_uri(
+            file_uri="https://example.com/sample.pdf",
+            mime_type="application/pdf",
+        ),
+        "Summarize this file",
+    ],
+)
+print(response.text)
+ +

Comparação de input methods

+
+ + + + + + + + +
MétodoMelhor paraTamanho máxPersistência
Inline dataTestes rápidos, arquivos pequenos100 MB / request (50 MB para PDFs)Nenhuma
Files API uploadArquivos grandes, uso repetido2 GB / arquivo, 20 GB / projeto48 h
Files API GCS registrationArquivos já em GCS2 GB / arquivo, sem cap geralAté 30 dias
External URLsWeb pública / S3/Azure pré-assinado100 MB / requestNenhuma
+
+ + + + +

5.9 Context caching

+

Gemini oferece dois mecanismos de cache, ambos compatíveis com input multimodal. O implícito é automático e free-to-try; o explícito é nomeado, com TTL configurável, e dá desconto garantido em prefixos identicamente reusados.

+ +

Implicit caching (default nos modelos atuais)

+

Habilitado automaticamente, sem setup. O sistema repassa economia de custo se um prefixo bate com uma request previamente cacheada.

+ +

Contagem mínima de tokens de input para ser elegível:

+
+ + + + + + +
ModeloMín tokens para cache hit
Gemini 3 Pro Preview4 096
Gemini 3 Flash Preview1 024
+
+ +

Tips para maximizar cache hits implícitos:

+
    +
  • Coloque conteúdo grande/comum (system instruction, PDF grande, arquivo de vídeo) no início do seu prompt.
  • +
  • Mande requests com prefixos similares perto no tempo.
  • +
+ +

O usage_metadata.cachedContentTokenCount (e campos equivalentes) reporta quantos tokens foram cache hit.

+ +

Explicit caching (client.caches)

+

Crie manualmente um cache nomeado, defina um TTL, e referencie em chamadas subsequentes de generateContent via cached_content=cache.name (Python) / cachedContent: cache.name (JS). Garante economia.

+

TTL: default é 1 hora se não setado. Sem mínimo, sem máximo.

+ +

Cachear um vídeo longo + system instruction — Python

+
import pathlib, time
+import requests
+from google import genai
+from google.genai import types
+
+client = genai.Client()
+path = pathlib.Path("SherlockJr._10min.mp4")
+if not path.exists():
+    path.write_bytes(requests.get(
+        "https://storage.googleapis.com/generativeai-downloads/data/SherlockJr._10min.mp4"
+    ).content)
+
+video_file = client.files.upload(file=path)
+while video_file.state.name == "PROCESSING":
+    time.sleep(2.5)
+    video_file = client.files.get(name=video_file.name)
+
+model = "models/gemini-3.5-flash"
+
+cache = client.caches.create(
+    model=model,
+    config=types.CreateCachedContentConfig(
+        display_name="sherlock jr movie",
+        system_instruction=(
+            "You are an expert video analyzer. Answer based on the cached video."
+        ),
+        contents=[video_file],
+        ttl="300s",  # 5 minutes
+    ),
+)
+
+response = client.models.generate_content(
+    model=model,
+    contents=(
+        "Introduce different characters in the movie by describing their personality, "
+        "looks, and names. Also list the timestamps they were introduced first."
+    ),
+    config=types.GenerateContentConfig(cached_content=cache.name),
+)
+print(response.usage_metadata)
+print(response.text)
+ +

Cachear um PDF grande — Python

+
import io, httpx
+from google import genai
+from google.genai import types
+
+client = genai.Client()
+doc_io = io.BytesIO(httpx.get(
+    "https://sma.nasa.gov/SignificantIncidents/assets/a11_missionreport.pdf"
+).content)
+
+document = client.files.upload(file=doc_io, config={"mime_type": "application/pdf"})
+
+cache = client.caches.create(
+    model="gemini-3.5-flash",
+    config=types.CreateCachedContentConfig(
+        system_instruction="You are an expert analyzing transcripts.",
+        contents=[document],
+    ),
+)
+
+response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents="Please summarize this transcript",
+    config=types.GenerateContentConfig(cached_content=cache.name),
+)
+print(response.usage_metadata, response.text)
+ +

List / update / delete caches

+
# list
+for c in client.caches.list():
+    print(c.name)
+
+# extend TTL
+client.caches.update(
+    name=cache.name,
+    config=types.UpdateCachedContentConfig(ttl="600s"),
+)
+
+# delete
+client.caches.delete(cache.name)
+ +

Modelo de pricing

+
+ + + + + + + +
FactorBilling
Cached input tokensTarifa reduzida quando referenciados em prompts subsequentes (~90% de desconto pela tabela atual).
Storage duration (TTL)Cobrança proporcional de storage do cache.
Non-cached input tokens, output tokensTarifas padrão.
+
+ +

Casos de uso:

+
    +
  • Chatbots com system instructions extensas.
  • +
  • Análise repetitiva de arquivos de vídeo longos.
  • +
  • Queries recorrentes contra grandes conjuntos de documentos.
  • +
  • Análise frequente de code repo ou bug fixing.
  • +
+ +

Quando NÃO cachear

+

Tokens cacheados precisam incluir o prefixo de toda request reusante (é um prefix cache). Se o prefixo muda por request, caching explícito adiciona custo de storage sem economia; confie no implícito.

+ + + + +

5.10 Parâmetros completos

+

Aqui consolidamos os campos relevantes de cada estrutura — Part, GenerationConfig, MediaResolution enum, usage_metadata da response, e o enum FileState. Use estas tabelas como referência rápida ao construir ou desserializar requests.

+ +

Part (por content part)

+
+ + + + + + + + + + + + + + + + + + + + + + +
CampoTipoOndeDescrição
textstringrequest / responseTexto plano.
inlineData.mimeTypestringrequest / responseMIME do inline data; um dos MIMEs suportados de image/audio/video/PDF.
inlineData.database64 stringrequest / responseBytes brutos, base64-encoded (REST). SDKs aceitam raw bytes e base64 transparentemente.
fileData.fileUristringrequest / responseURI de arquivo Files API, GCS-registered, URL HTTPS externa, signed URL, ou YouTube URL.
fileData.mimeTypestringrequestMIME (às vezes opcional quando o URI carrega, mas você deveria sempre passar).
videoMetadata.startOffsetduration string (e.g. "1250s")requestOffset de início do clip; suporta <seconds>s.
videoMetadata.endOffsetduration stringrequestOffset de fim do clip.
videoMetadata.fpsfloatrequestCustom FPS sampling. Default = 1.0. UNVERIFIED (2026-05-23) sobre o range oficial; valores observados: 0.1 – ~24.
mediaResolution.levelenumrequestPer-part MEDIA_RESOLUTION_LOW / MEDIUM / HIGH / ULTRA_HIGH / UNSPECIFIED. Gemini 3 + v1alpha apenas.
executableCode.language"PYTHON"responseSempre Python no sandbox atual.
executableCode.codestringresponsePython emitido pelo modelo.
executableCode.idstringambosId estável para a tool call. Ecoe quando replayar manualmente via REST.
codeExecutionResult.outcomeOUTCOME_OK / OUTCOME_FAILED / OUTCOME_DEADLINE_EXCEEDEDresponseStatus da execução.
codeExecutionResult.outputstringresponsestdout ou error message.
codeExecutionResult.idstringambosPareamento com executableCode.id.
functionCall.name / .argsstring / objectresponseTool call.
functionResponse.name / .responsestring / objectrequestResultado da tool que você fornece de volta.
thoughtSignaturestring (opaca)ambosPreserve ao construir manualmente histórico multi-turn de tool-use (especialmente com code execution).
+
+ +

GenerationConfig / GenerateContentConfig — campos multimodal-relevantes

+
+ + + + + + + + + + + + + + + +
CampoTipo / valoresDescrição
systemInstructionContent ou stringDireciona o comportamento do modelo.
tools[Tool]code_execution, google_search, url_context, function_declarations, etc.
toolConfigobjectForçar / restringir modos de uso de tools.
mediaResolutionenum MEDIA_RESOLUTION_*Media resolution global. Valores per-part (Gemini 3, v1alpha) sobrescrevem.
responseMimeType"application/json" / "text/plain" / "text/x.enum" etc.Forçar structured output.
responseSchemaSchemaTipo similar a JSON Schema ao qual o modelo se conforma.
thinkingConfig.thinkingBudgetintCap de thinking tokens. 0 = desabilitar thinking (usado pesado pelo Robotics-ER 1.6).
safetySettingsarrayThresholds de safety per-category.
temperature, topP, topK, maxOutputTokens, candidateCount, stopSequencessamplingControles padrão de sampling. Com Gemini 3 mantenha temperature=1.0.
cachedContentstring (cache resource name)Usa cache explícito como prefixo.
serviceTierSTANDARD / FLEX / PRIORITYTier de inference síncrono (trade-off custo/latência/reliability).
+
+ +

MediaResolution enum

+
MEDIA_RESOLUTION_UNSPECIFIED   # default para a família do modelo
+MEDIA_RESOLUTION_LOW
+MEDIA_RESOLUTION_MEDIUM
+MEDIA_RESOLUTION_HIGH
+MEDIA_RESOLUTION_ULTRA_HIGH    # per-part apenas (Gemini 3 v1alpha)
+ +

usage_metadata fields (response)

+
+ + + + + + + + + + + +
CampoSignificado
prompt_token_countTokens de input.
candidates_token_countTokens de output.
thoughts_token_countReasoning ("thinking") tokens.
tool_use_prompt_token_countTokens gastos em tool prompts (e.g. URL context retrieval).
cached_content_token_countTokens servidos do cache (implícito ou explícito).
prompt_tokens_details / candidates_tokens_detailsBreakdown per-modalidade (TEXT / IMAGE / VIDEO / AUDIO).
total_token_countSoma de todas as categorias.
+
+ +

FileState enum

+
STATE_UNSPECIFIED
+PROCESSING
+ACTIVE
+FAILED
+ +

usage_metadata — exemplo (response)

+
{
+  "usage_metadata": {
+    "prompt_token_count": 27,
+    "candidates_token_count": 45,
+    "thoughts_token_count": 31,
+    "tool_use_prompt_token_count": 10309,
+    "cached_content_token_count": 1024,
+    "prompt_tokens_details": [
+      {"modality": "TEXT", "token_count": 27}
+    ],
+    "tool_use_prompt_tokens_details": [
+      {"modality": "TEXT", "token_count": 10309}
+    ],
+    "total_token_count": 10412
+  }
+}
+ +

Sempre inspecione usage_metadata para validar (a) de qual modalidade vieram seus tokens e (b) se caching foi efetivo.

+ + + + +

5.11 Limitações & gotchas

+

Catálogo exaustivo de bordas e armadilhas, agrupadas por modalidade. Cada item aqui foi atingido na prática ou está explícito na doc oficial — use como checklist antes de mergulhar em produção.

+ +

Imagem

+
    +
  • Payload inline total (todos os inline data + texto + system instructions) capado em 20 MB; use Files API acima disso.
  • +
  • 3 600 imagens máx por request.
  • +
  • BMP não está na lista nativa de MIME de imagem — converta para PNG/JPEG/WEBP/HEIC/HEIF.
  • +
  • Coordenadas de object detection são normalizadas em [0, 1000]. Sempre desescale.
  • +
  • Para inputs de baixa resolução, suba media_resolution para HIGH ou ULTRA_HIGH antes de assumir que o modelo "não consegue ver" algo.
  • +
+ +

PDF

+
    +
  • 1 000 páginas máx por request, somadas em todos os PDFs.
  • +
  • 50 MB por PDF (seja inline ou via Files API).
  • +
  • Para MIME de documento não-PDF (HTML, Markdown, …), Gemini vê texto puro — sem charts, tabelas, ou fidelidade visual de layout.
  • +
  • Acurácia em página única é melhorada quando o prompt de texto vem depois da página.
  • +
  • Texto vertical / right-to-left e scans muito enviesados ainda podem confundir OCR.
  • +
+ +

Office / spreadsheet

+
    +
  • Vision nativa para .docx / .pptx / .xlsx é UNVERIFIED (2026-05-23). Converta para PDF para documentos; use o sandbox de code execution para analytics em XLSX/CSV/JSON.
  • +
+ +

Vídeo

+
    +
  • Amostragem default de 1 FPS pode perder ação rápida — suba fps (e.g. 5–24).
  • +
  • Vídeo inline precisa manter o request inteiro abaixo de ~20 MB (recomendado) / 100 MB (hard); use Files API para qualquer coisa mais longa.
  • +
  • YouTube preview: 8 horas/dia de cap (free), apenas vídeos públicos, máx 10 por request.
  • +
  • Em media resolution default, uma hora de vídeo ≈ 1.08 M tokens (300 tokens/seg) — próximo a uma janela de 1 M de contexto. Use LOW para vídeos longos.
  • +
  • Re-check de safety por frame: o mesmo vídeo pode ser bloqueado em um FPS e aceito em outro.
  • +
+ +

Áudio

+
    +
  • 9.5 horas de cap combinado por request.
  • +
  • Sempre downsampleado para 16 Kbps, mono.
  • +
  • Sem real-time transcription via generateContent; use Live API ou Cloud Speech-to-Text.
  • +
  • Formatos não-WAV são decodificados de modo confiável apenas quando o MIME bate com a lista oficial (audio/wav, audio/mp3, audio/aiff, audio/aac, audio/ogg, audio/flac).
  • +
+ +

Files API

+
    +
  • 2 GB máx por arquivo, 20 GB por projeto.
  • +
  • 48 h de retenção; não downloadable.
  • +
  • States de arquivo precisam estar ACTIVE antes de referenciar em generateContent.
  • +
+ +

Caching

+
    +
  • Conteúdo de cache explícito não pode ser inspecionado/lido de volta, apenas metadados.
  • +
  • Cache implícito só atua acima de 1 024 / 4 096 tokens dependendo do modelo.
  • +
  • Prefixo de cache precisa ser idêntico entre as chamadas reusantes.
  • +
+ +

Tool combination

+
    +
  • Function calling atualmente não pode ser combinado com built-in tools (URL Context, Google Search) em modelos Gemini mais antigos. Gemini 3 suporta combinar built-in tools + custom function calling — ver doc de tool-combination.
  • +
+ +

Realtime

+
    +
  • Live API é um serviço WebSocket separado (live.connect) — não é o endpoint HTTP generateContent.
  • +
  • Estado da Live API é retido até 24 h se SessionResumptionConfig for usado; opte por opt-out para manter zero-data-retention.
  • +
+ +

Zero Data Retention (pago)

+
    +
  • Grounding com Google Search / Maps sempre armazena 30 dias de prompt+output (sem opt-out).
  • +
  • Storage do File API é independente de ZDR — delete arquivos você mesmo.
  • +
  • Cache implícito em RAM é project-isolated, TTL de 24h — não viola ZDR.
  • +
+ +
+ Resumo prático. Para a maioria das aplicações multimodais Gemini 3: (1) suba arquivos grandes via Files API e cheque state == ACTIVE; (2) coloque mídia antes do texto na lista de parts; (3) ajuste media_resolution com base na densidade de detalhe (LOW para vídeo longo, HIGH para OCR fino); (4) use cache explícito quando o prefixo se repete identicamente; (5) inspecione usage_metadata a cada request para validar token accounting per-modalidade. +
+ +
+
+
Google Gemini · Interactions API · Beta
+

Gemini Interactions API — deep dive

+

A Interactions API é o novo padrão recomendado para aplicações agênticas sobre Gemini 3.x. Mantém estado server-side via previous_interaction_id, expõe uma timeline tipada de steps[] (em vez de candidates[].content.parts[]), suporta tarefas longas em background (Deep Research, Deep Think) via background=true, cancelamento explícito, retomada de SSE via last_event_id, e introduz um modelo de input[] com tipos discriminados (text, image, audio, video, document) que substitui o velho Part. Esta seção destrincha cada superfície, cada limite, cada tipo de step, parâmetros, exemplos rodáveis em Python e curl, gotchas e diferenças cruzadas com generateContent. Tudo verificado em 2026-05-24 contra ai.google.dev/api/interactions-api, ai.google.dev/gemini-api/docs/interactions/*, ai.google.dev/gemini-api/docs/interactions-breaking-changes-may-2026, e os notebooks oficiais do google-gemini/cookbook.

+ +
+ Status Beta — não use em produção crítica. A própria doc oficial recomenda: "para cargas de trabalho de produção, continue usando a API padrão generateContent" (conforme ai.google.dev/gemini-api/docs/interactions). O schema sofreu mudança incompatível (outputs[] → steps[]); o schema legado foi removido em 08/06/2026 — o header Api-Revision passou a ser ignorado, os SDKs google-genai/@google/genai 1.x quebraram para Interactions, e steps[] é o único schema (ver §6.18, confirmado pela página oficial de breaking changes). Disponível no Gemini Developer API (Google AI Studio); até 2026-05-24 a documentação oficial (ai.google.dev/api/interactions-api e ai.google.dev/gemini-api/docs/interactions) descreve a Interactions API apenas no Gemini Developer API e a página de migração do Vertex AI (cloud.google.com/vertex-ai/generative-ai/docs/migrate/migrate-google-ai) não expõe nenhum endpoint interactions — para produção em Vertex hoje, use generateContent. +
+ + + + +

6.1 API surface

+

A Interactions API expõe um único recurso interactions sob https://generativelanguage.googleapis.com/v1beta/interactions. Estado da conversa é persistido no servidor por padrão (store=true): turnos seguintes apenas referenciam previous_interaction_id, sem reenviar todo o histórico. Authentication via header x-goog-api-key: $GEMINI_API_KEY (igual ao generateContent). Durante a janela de migração de maio/2026, o header Api-Revision: 2026-05-20 optava pelo schema novo (steps[]); desde 08/06/2026 o schema legado foi removido, o header é ignorado e steps[] é o único schema (SDK ≥ 2.0.0).

+ +

RPCs e endpoints REST

+
+ + + + + + + + +
OperaçãoMétodoURLNotas
Criar interaçãoPOST/v1beta/interactionsSíncrono ou streaming via ?alt=sse + "stream": true; aceita background=true para fire-and-poll.
Recuperar / retomar SSEGET/v1beta/interactions/{id}Query params: stream, last_event_id, include_input, api_version.
ExcluirDELETE/v1beta/interactions/{id}Remove o estado server-side imediatamente; quebra previous_interaction_id downstream.
Cancelar (background)POST/v1beta/interactions/{id}/cancelSinaliza cancelamento cooperativo; status final cancelled.
+
+

A superfície principal é o recurso interactions (criar / recuperar / excluir / cancelar). Agents pré-construídos (Deep Research, Antigravity) são selecionados pelo campo agent no próprio POST /v1beta/interactions; além disso, a doc oficial de managed agents (ai.google.dev/gemini-api/docs/custom-agents) expõe CRUD de agents customizados via client.agents.create / list / get / delete. Veja §6.13.

+ +

SDKs

+
+ + + + + + + + +
LinguagemPacoteVersão mínimaVersão obrigatória
Pythongoogle-genai>= 1.55.0 (schema legado outputs[])>= 2.0.0 — obrigatório desde 08/06/2026 (schema steps[]; 1.x quebrado)
JavaScript / TypeScript@google/genai>= 1.33.0 (schema legado)>= 2.0.0 — obrigatório desde 08/06/2026 (1.x quebrado)
Gogoogle.golang.org/genaiversão atualversão atual
REST—opt-in via Api-Revision: 2026-05-20padrão desde 26/05/2026; desde 08/06/2026 o header é ignorado (schema legado removido)
+
+ +
+ Discrepância documental — path REST. A página de migração oficial usa em alguns exemplos o path v1beta2/interactions, enquanto a referência oficial (ai.google.dev/api/interactions-api), o quickstart, o changelog, a página de breaking changes, a página de streaming e a página de tokens usam v1beta/interactions. Adote sempre v1beta/interactions — a referência oficial (ai.google.dev/api/interactions-api) é a autoridade primária. Nenhuma entrada do changelog anuncia migração para v1beta2. +
+ +

Construção do client (padrão atual)

+
+
+ + + +
+
+
# pip install "google-genai>=2.0.0"
+from google import genai
+
+# lê GEMINI_API_KEY do ambiente
+client = genai.Client()
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Explique a IA em poucas palavras.",
+)
+print(interaction.output_text)        # atalho: une últimos blocos de texto
+print(interaction.id)                 # use em previous_interaction_id depois
+print(interaction.usage.total_tokens)
+
+
+
// npm i @google/genai@^2
+import { GoogleGenAI } from "@google/genai";
+const ai = new GoogleGenAI({});
+
+const interaction = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  input: "Explique a IA em poucas palavras.",
+});
+console.log(interaction.outputText);
+console.log(interaction.id);
+
+
+
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{
+    "model": "gemini-3.5-flash",
+    "input": "Explique a IA em poucas palavras."
+  }'
+
+
+ +

Retenção do interaction.id

+
+ + + + + + + +
PlanoRetençãoImplicação
Free1 diaApós 24h, previous_interaction_id falha; reanexar histórico do cliente.
Paid55 diasCache implícito eficaz por até ~55d desde que a chain seja referenciada.
store=falsenenhumaAproxima ZDR; desabilita previous_interaction_id e impede background=true.
+
+ +

Comparação rápida com generateContent

+

Resumo de alto nível; a tabela cruzada exaustiva está em §6.20.

+
+ + + + + + + + + + + + + + +
ConceitogenerateContentInteractions API
Estado da conversacliente (contents[])servidor (previous_interaction_id)
Respostacandidates[].content.parts[]steps[] com tipos discriminados
Atalho de textoresponse.textinteraction.output_text
Tarefas longasn/abackground=true
Cancelamenton/aPOST /interactions/{id}/cancel
Cacheexplícito (cachedContent) ou implícitoapenas implícito (via previous_interaction_id)
Métricasusage_metadata.*_countusage.total_*_tokens + *_by_modality
Batchsuportadonão suportado
Auto function calling (Py)suportadonão suportado
safety_settingssuportadoausente (apenas safety_decision runtime em Computer Use)
+
+ + + + +

6.2 Imagem / visão

+

Imagens entram via items do array input[] com type: "image". O Gemini divide cada imagem em blocos 768×768 (258 tokens por bloco); imagens ≤ 384 px usam um único bloco. Tokenização e MIME types são idênticos ao generateContent, mas a forma muda: em vez de inlineData.{mimeType,data} ou fileData.{fileUri,mimeType}, agora é um único objeto com discriminador type.

+ +

Campos do {type:"image"}

+
+ + + + + + + + + +
CampoTipoObrigatoriedadeDescrição
type"image" (literal)obrigatórioDiscriminador.
database64 stringexclusivo com uriBytes brutos da imagem em base64 (inline). Total da request < 20 MB.
uristringexclusivo com dataFiles API (files/...), GCS (gs://...), URL HTTPS pública, signed URL.
mime_typestringrecomendadoMIME explícito; ver tabela de MIMEs aceitos abaixo.
resolutionenumopcionallow, medium, high, ultra_high. Per-part — sobrescreve default da família do modelo.
+
+ +

MIME types aceitos

+

A documentação oficial de visão de imagem (ai.google.dev/gemini-api/docs/interactions/image-understanding) confirma explicitamente:

+
    +
  • image/png
  • +
  • image/jpeg
  • +
  • image/webp
  • +
  • image/heic
  • +
  • image/heif
  • +
+

Os formatos image/gif (estático; primeiro frame para animados), image/bmp e image/tiff são aceitos pela tokenização de imagem do Gemini, mas não constam na lista explícita da página oficial de visão de imagem até 2026-05-24 UNVERIFIED (2026-05-24) — valide amostrando antes de depender deles em produção.

+ +

Quatro caminhos de envio de imagem

+
+ + + + + + + + +
CaminhoQuando usarCampoLimite prático
Inline base64arquivo < ~10 MB, uso únicodatarequest total < 20 MB
Files API URIarquivo reutilizável ou grandeuri: "files/..."2 GB por arquivo, 20 GB por projeto, retenção 48h
GCS URIarquivo já em Cloud Storageuri: "gs://bucket/path.jpg"bucket precisa estar acessível pela API
URL HTTPS públicaarquivo já hosteduri: "https://..."servidor remoto precisa devolver MIME válido
+
+ +

Limites

+
    +
  • 3.600 imagens máx por request (combinado com texto e outras modalidades).
  • +
  • 20 MB total inline (todos os data em base64 + texto + system_instruction).
  • +
  • Tokenização: ≤ 384 px = 258 tokens; > 384 px = ceil(W/768) × ceil(H/768) blocos × 258 tokens cada.
  • +
  • resolution: low reduz custos em ~3× para imagens grandes; high/ultra_high aumentam acurácia em OCR fino.
  • +
+ +

Exemplo Python — imagem inline + URI Files API + GCS

+
+
+ + + + +
+
+
import base64
+from google import genai
+client = genai.Client()
+
+with open("scones.jpg", "rb") as f:
+    image_b64 = base64.b64encode(f.read()).decode("utf-8")
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text",  "text": "Gere uma receita para os scones mostrados."},
+        {"type": "image", "data": image_b64, "mime_type": "image/jpeg"},
+    ],
+)
+print(interaction.output_text)
+
+
+
from google import genai
+client = genai.Client()
+
+img = client.files.upload(file="photo.png")
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Descreva o local da foto."},
+        {"type": "image", "uri": img.uri, "mime_type": img.mime_type},
+    ],
+)
+print(interaction.output_text)
+
+
+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Qual é o estado da carga na foto?"},
+        {
+            "type": "image",
+            "uri": "gs://my-bucket/inspections/load-12.jpg",
+            "mime_type": "image/jpeg",
+            "resolution": "high",
+        },
+    ],
+)
+
+
+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Liste os ingredientes desta receita."},
+        {
+            "type": "image",
+            "uri": "https://storage.googleapis.com/generativeai-downloads/images/scones.jpg",
+        },
+    ],
+)
+print(interaction.output_text)
+
+
+ +

Exemplo REST — imagem inline base64

+
curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -H "Api-Revision: 2026-05-20" \
+  -d '{
+    "model": "gemini-3.5-flash",
+    "input": [
+      {"type": "text",  "text": "Descreva esta imagem."},
+      {"type": "image", "data": "iVBORw0KGgoAAAANSUhEUgAA...", "mime_type": "image/png"}
+    ]
+  }'
+ +

Múltiplas imagens (até 3.600)

+
input = [
+    {"type": "text", "text": "Compare estes 4 prints de UI e aponte a diferença."},
+    {"type": "image", "uri": f1.uri, "mime_type": "image/png"},
+    {"type": "image", "uri": f2.uri, "mime_type": "image/png"},
+    {"type": "image", "uri": f3.uri, "mime_type": "image/png"},
+    {"type": "image", "uri": f4.uri, "mime_type": "image/png"},
+]
+interaction = client.interactions.create(model="gemini-3.5-flash", input=input)
+ +

Geração de imagem (model output)

+

Modelos gemini-3-pro-image (Nano Banana Pro) e gemini-3.1-flash-image (Nano Banana 2) produzem blocos de image dentro de steps[]. No schema novo, leia via interaction.output_image (atalho) ou itere os steps:

+
import base64
+interaction = client.interactions.create(
+    model="gemini-3-pro-image",
+    input="Gere uma ilustração de uma cidade futurista ao pôr do sol.",
+)
+
+# Atalho: último bloco de imagem do model_output
+img = interaction.output_image
+with open("city.png", "wb") as f:
+    f.write(base64.b64decode(img.data))
+
+# Forma explícita: iterar steps no schema novo
+for step in interaction.steps:
+    if step.type == "model_output":
+        for c in step.content:
+            if c.type == "image":
+                print("mime:", c.mime_type, "bytes:", len(c.data))
+ +

Coordenadas de detecção de objetos

+

Quando se pede bounding boxes ou segmentação, o Gemini devolve coordenadas normalizadas em [0, 1000] (mesmo padrão do generateContent). Sempre desescale para a resolução real da imagem antes de plotar ou de usar como input em outro pipeline.

+ + + + +

6.3 PDF / documentos

+

PDFs e outros documentos entram via items {type: "document"}. PDF é a modalidade de documento primária: o modelo recebe a representação visual de cada página em ~768×768 a 3072×3072 px e cobra 258 tokens por página. Em Gemini 3, o texto nativo extraído de cada página é gratuito (não é cobrado quando extraído via OCR nativo).

+ +

MIME types aceitos

+
+ + + + + + + + + +
MIMETratamentoCusto
application/pdfRender visual + OCR nativo258 tokens/página; texto nativo grátis em Gemini 3
text/plainTexto planoTokenização padrão de texto
text/markdown · text/x-markdownTexto planoTokenização padrão (sem render de markdown)
text/htmlTexto plano (tags incluídas)Tokenização padrão; sem render de DOM
application/xml · text/xmlTexto planoTokenização padrão
+
+ +

Campos do {type:"document"}

+
+ + + + + + + + +
CampoTipoNotas
type"document"Discriminador.
database64Inline; total da request < 20 MB.
uristringFiles API (files/...), GCS, URL HTTPS, arXiv etc.
mime_typestringObrigatório quando enviar bytes brutos; geralmente application/pdf.
+
+ +

Limites

+
    +
  • 50 MB por PDF (inline ou Files API).
  • +
  • 1.000 páginas máx por request, somadas em todos os PDFs (confirmado em ai.google.dev/gemini-api/docs/interactions/document-processing).
  • +
  • Cada página renderiza entre 768×768 e 3072×3072 px.
  • +
  • Acurácia em página única é melhor quando o prompt textual vem depois do PDF.
  • +
  • Texto vertical / right-to-left / scans muito enviesados podem confundir o OCR — confira amostrando.
  • +
+ +

Exemplo Python — PDF via Files API

+
from google import genai
+client = genai.Client()
+
+pdf = client.files.upload(file="relatorio.pdf")
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Resuma o relatório em 5 bullets em PT-BR."},
+        {"type": "document", "uri": pdf.uri, "mime_type": pdf.mime_type},
+    ],
+)
+print(interaction.output_text)
+print("input tokens:", interaction.usage.total_input_tokens)
+ +

Exemplo Python — PDF público (arXiv)

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Qual o impacto desse paper?"},
+        {
+            "type": "document",
+            "uri": "https://arxiv.org/pdf/1706.03762",
+            "mime_type": "application/pdf",
+        },
+    ],
+)
+ +

Múltiplos PDFs no mesmo turno

+

Some páginas até no máximo 1.000 entre todos os PDFs da request. Útil para comparativos de relatórios ou prospectos.

+ + + + +

6.4 Office / Excel / CSV

+

A Interactions API não tem conversores nativos para .docx, .pptx, .xlsx, .csv. Há dois caminhos práticos:

+
    +
  1. Pré-converter para PDF (LibreOffice headless, Aspose, scripts) e enviar como {type:"document", mime_type:"application/pdf"} — preserva layout, gráficos e tabelas com fidelidade visual.
  2. +
  3. Usar a tool code_execution (ver §6.5) e deixar o sandbox Python ler o arquivo com openpyxl, pandas, python-docx, python-pptx. Útil para analytics e transformação tabular.
  4. +
+

Vision nativa de .docx / .pptx / .xlsx não é documentada pela página oficial de visão de documentos (ai.google.dev/gemini-api/docs/interactions/document-processing), que lista apenas application/pdf com entendimento visual e TXT/MD/HTML/XML como texto plano UNVERIFIED (2026-05-24) — siga os dois caminhos acima.

+ +

Exemplo — XLSX via code_execution

+
xlsx = client.files.upload(file="vendas_2026.xlsx")
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Gere um gráfico de barras de vendas por região e devolva o PNG."},
+        {"type": "document", "uri": xlsx.uri,
+         "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
+    ],
+    tools=[{"type": "code_execution"}],
+)
+ + + + +

6.5 Code execution

+

A tool {type: "code_execution"} habilita um sandbox Python que o modelo invoca autonomamente para analytics, plotting, parsing, ou validação determinística. No schema novo, os passos da execução são surfaceados como step.type dedicados:

+
+ + + + + + +
step.typeConteúdoQuando
code_execution_callid, arguments.code (Python), arguments.language (python)Modelo emite código.
code_execution_resultcall_id (pareia com code_execution_call.id), is_error, result (string — stdout/stderr)Sandbox executa e devolve.
+
+ +

Exemplo Python — CSV analytics

+
csv_file = client.files.upload(file="transactions.csv")
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Qual o ticket médio por mês no CSV? Retorne uma tabela markdown."},
+        {"type": "document", "uri": csv_file.uri, "mime_type": "text/csv"},
+    ],
+    tools=[{"type": "code_execution"}],
+)
+
+for step in interaction.steps:
+    if step.type == "code_execution_call":
+        print("--- código ---")
+        print(step.arguments.code)
+    elif step.type == "code_execution_result":
+        print("--- resultado (is_error=", step.is_error, ") ---")
+        print(step.result)
+print(interaction.output_text)
+ +

Combine code_execution com outros tools — file_search para RAG, url_context para enriquecer dados, ou function para validar regras de negócio cliente-side.

+ + + + +

6.6 Vídeo

+

Vídeos entram como {type: "video"}. A Interactions API não suporta video_metadata customizado (intervalos startOffset/endOffset, FPS custom) — se você precisa disso, use generateContent. O que sobra é controlar a resolução de processamento via resolution.

+ +

MIME types aceitos

+
    +
  • video/mp4
  • +
  • video/mpeg
  • +
  • video/mov
  • +
  • video/avi
  • +
  • video/x-flv
  • +
  • video/mpg
  • +
  • video/webm
  • +
  • video/wmv
  • +
  • video/3gpp
  • +
+ +

Limites

+
+ + + + + + + + + + +
AspectoValor
Inline (base64)< 100 MB; recomenda-se Files API acima de ~20 MB
Via Files APIaté 20 GB (pago) / 2 GB (gratuito)
Duração máx (contexto 1M)1 hora em resolution padrão; 3 horas em low
Tokens (padrão)~300 tokens/segundo (258 por frame @ 1 FPS + 32/seg de áudio)
Tokens (resolution: low)~100 tokens/segundo (66/frame @ 1 FPS + 32/seg de áudio)
YouTube previewAceita URL pública; 8 horas/dia de cap (free), máx 10 vídeos por request
+
+ +

Exemplo Python — vídeo via Files API + resolução baixa

+
vid = client.files.upload(file="aula_45min.mp4")
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Resuma a aula em capítulos com timestamps."},
+        {
+            "type": "video",
+            "uri": vid.uri,
+            "mime_type": vid.mime_type,
+            "resolution": "low",    # 3h cap, ~100 tok/s
+        },
+    ],
+)
+print(interaction.output_text)
+ +

Exemplo Python — YouTube URL

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Liste os tópicos abordados em ordem."},
+        {"type": "video", "uri": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"},
+    ],
+)
+ +
+ Sem controle fino de FPS / clipes. Para amostrar a 5 FPS, recortar entre 00:15 e 02:30, ou aplicar metadados customizados, use generateContent com videoMetadata. A Interactions API só aceita o vídeo inteiro com resolution aplicada igualmente. +
+ + + + +

6.7 Áudio

+

Áudio entra como {type: "audio"}. Internamente, o Gemini reamostra para 16 kbps em mono (canais combinados); cobra 32 tokens/segundo. 1 minuto = 1.920 tokens; 1 hora ≈ 115.200 tokens.

+ +

MIME types aceitos

+
    +
  • audio/wav
  • +
  • audio/mp3 · audio/mpeg
  • +
  • audio/aiff
  • +
  • audio/aac
  • +
  • audio/ogg
  • +
  • audio/flac
  • +
  • audio/m4a
  • +
  • audio/opus
  • +
  • audio/alaw
  • +
  • audio/mulaw
  • +
+ +

Campos extras

+
+ + + + + + +
CampoNotas
channels1 (mono) ou 2 (stereo); internamente é combinado em mono.
sample_rateHz; default depende do MIME. Internamente é reamostrado para 16 kbps.
+
+ +

Limites

+
    +
  • 9,5 horas combinadas por comando (todos os áudios da request somados; confirmado em ai.google.dev/gemini-api/docs/interactions/audio).
  • +
  • Total inline < 20 MB.
  • +
  • Sem real-time transcription via Interactions — use Live API ou Cloud Speech-to-Text para isso.
  • +
+ +

Exemplo Python — transcrição + sumário

+
audio = client.files.upload(file="reuniao.wav")
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Transcreva e produza um sumário executivo em 3 bullets."},
+        {"type": "audio", "uri": audio.uri, "mime_type": "audio/wav"},
+    ],
+)
+print(interaction.output_text)
+# Tokens: ~32/segundo de áudio + texto do prompt
+ +

Geração de áudio (TTS)

+

O modelo gemini-3.1-flash-tts-preview produz blocos de áudio no model_output. Use response_modalities=["audio"] ou configure generation_config.speech_config com voz/idioma:

+
interaction = client.interactions.create(
+    model="gemini-3.1-flash-tts-preview",
+    input="Boas-vindas em português do Brasil, em tom amigável.",
+    response_modalities=["audio"],
+    generation_config={
+        "speech_config": {
+            "voice_config": {"prebuilt_voice_config": {"voice_name": "Kore"}},
+            "language_code": "pt-BR",
+        }
+    },
+)
+import base64
+with open("saida.wav", "wb") as f:
+    f.write(base64.b64decode(interaction.output_audio.data))
+ + + + +

6.8 Files API

+

A Interactions API usa a mesma Files API do generateContent: upload via host https://generativelanguage.googleapis.com/upload/v1beta/files (resumable), retorno files/{name}, retenção 48h, 2 GB por arquivo, 20 GB por projeto. A diferença prática é o local de referência: agora vai em {type: ..., uri: file.uri, mime_type: file.mime_type} em cada item de input[].

+ +

Estados (FileState) válidos

+
STATE_UNSPECIFIED
+PROCESSING
+ACTIVE
+FAILED
+

Antes de referenciar em interactions.create, confirme que file.state == "ACTIVE". Arquivos de vídeo costumam levar segundos a alguns minutos para processar.

+ +

Padrão de upload + wait

+
import time
+from google import genai
+client = genai.Client()
+
+f = client.files.upload(file="aula.mp4")
+while f.state == "PROCESSING":
+    time.sleep(2)
+    f = client.files.get(name=f.name)
+assert f.state == "ACTIVE", f.state
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Resuma."},
+        {"type": "video", "uri": f.uri, "mime_type": f.mime_type},
+    ],
+)
+ +

Diferenças vs generateContent no uso de Files

+
    +
  • No generateContent: {fileData: {fileUri, mimeType}} dentro de Part.
  • +
  • Na Interactions API: {type: "image|audio|video|document", uri, mime_type} dentro de input[].
  • +
  • O URI é o mesmo (files/...); o wrapper muda.
  • +
  • O ciclo de vida (retenção 48h, gestão via client.files.list/get/delete) não muda.
  • +
+ + + + +

6.9 Cache implícito (não há cache explícito)

+

A Interactions API não suporta cachedContent explícito — esse recurso permanece exclusivo do generateContent. O caching aqui é exclusivamente implícito, ativado automaticamente quando você passa previous_interaction_id em um novo turno. Em hits, os tokens cacheados aparecem em usage.total_cached_tokens e em usage.cached_tokens_by_modality.

+ +

Comparação com generateContent

+
+ + + + + + + + +
AspectogenerateContentInteractions API
Cache implícito≥ 1.024 (Flash) / 4.096 (Pro) tokens de prefixo idênticoAuto via previous_interaction_id
Cache explícito (cachedContent)Sim — TTL customizável; prefixo nomeado reutilizável entre sessõesNão suportado
Cache observableusage_metadata.cached_content_token_countusage.total_cached_tokens + cached_tokens_by_modality
Inspeção do conteúdo cacheadoApenas metadadosEstado da interação inteira via GET /interactions/{id}?include_input=true
+
+ +

Exemplo Python — cache implícito via multi-turn

+
i1 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Leia este edital."},
+        {"type": "document", "uri": edital.uri, "mime_type": "application/pdf"},
+    ],
+)
+print(i1.usage.total_input_tokens, i1.usage.total_cached_tokens)
+# segundo turno: prefixo idêntico cacheado server-side
+i2 = client.interactions.create(
+    model="gemini-3.5-flash",
+    previous_interaction_id=i1.id,
+    input="Qual o objeto da licitação?",
+)
+print(i2.usage.total_cached_tokens)   # > 0 indica hit
+ +

Forking de conversas

+

Aponte previous_interaction_id para qualquer interaction.id anterior — não precisa ser o último turno. Isso permite ramificar a árvore de conversas sem perder o prefixo cacheado, útil para multi-tenant ou A/B em ramos diferentes.

+ + + + +

6.10 Tools server-side completas

+

Tools são passadas em tools: [...] no body da request. Cada tool tem um type discriminador. Tools são interaction-scoped: precisam ser re-declaradas a cada turn que as use; em function-result roundtrips (com previous_interaction_id), você não reenvia o array tools.

+ +

Catálogo

+
+ + + + + + + + + + + + + +
typeFunçãoCampos principais
functionfunção client-side (declara, executa local, devolve)name, description, parameters (JSON Schema)
code_executionsandbox Python (analytics, plotting, parsing)— (sem config; controle por system_instruction)
url_contextservidor faz fetch de URLs citadas no prompt— (URLs vêm do texto do usuário)
file_searchRAG sobre stores da Files APIfile_search_store_names, top_k, metadata_filter
mcp_serverMCP server remoto (no-auth, bearer, OAuth)name, url, headers, allowed_tools
google_searchgrounding com Google Searchsearch_types: web_search, image_search, enterprise_web_search
google_mapsgrounding com Google Mapsenable_widget, latitude, longitude
retrievalVertex AI Searchretrieval_types, vertex_ai_search_config
computer_useagente de UI (browser)environment: "browser", excluded_predefined_functions
+
+ +

mcp_server — MCP remoto

+

O Gemini se conecta a um servidor MCP HTTP e chama as tools listadas em allowed_tools. Suporta autenticação no-auth, bearer e OAuth (token obtido via google-auth ou outro provider).

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Liste meus issues abertos no Linear.",
+    tools=[
+        {
+            "type": "mcp_server",
+            "name": "linear-mcp",
+            "url": "https://mcp.linear.app/v1",
+            "headers": {"Authorization": f"Bearer {LINEAR_TOKEN}"},
+            "allowed_tools": ["list_issues", "get_issue"],
+        }
+    ],
+)
+

Atenção: a documentação oficial de tools (ai.google.dev/gemini-api/docs/interactions/tool-combination) afirma explicitamente que "Gemini 3 não suporta remote MCP, em breve"; o MCP remoto exige servidores Streamable HTTP (SSE não é suportado) e nomes de servidor em snake_case (sem -). Enquanto não chega, use mcp_server local.

+ +

file_search — RAG nativa

+

Crie um store com client.file_search_stores.create e indexe arquivos com add_files; depois passe o nome do store na tool. top_k controla o número de chunks recuperados; metadata_filter permite condicionais.

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="O que diz a cláusula de rescisão?",
+    tools=[
+        {
+            "type": "file_search",
+            "file_search_store_names": ["fileSearchStores/contratos-2026"],
+            "top_k": 5,
+            "metadata_filter": {"type": "contrato", "vigente": True},
+        }
+    ],
+)
+ +

google_search — grounding com web

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Quem ganhou o Nobel de Física em 2024?",
+    tools=[{"type": "google_search"}],
+)
+# Steps incluem google_search_call e google_search_result; annotations referenciam URLs no texto
+for step in interaction.steps:
+    if step.type == "google_search_result":
+        print(step.snippets)
+ +

Combinação de tools

+

Em Gemini 3, é permitido combinar built-in tools entre si e com function custom. Em modelos pré-3 essa combinação é restrita — confira a doc de tool-combination do modelo escolhido antes de assumir compatibilidade.

+ +

tool_choice

+

Vive em generation_config.tool_choice e aceita um ToolChoiceType (enum) ou um ToolChoiceConfig (objeto). Valores do enum confirmados na referência:

+
    +
  • "auto" — modelo decide (default).
  • +
  • "any" — força pelo menos uma chamada de tool.
  • +
  • "none" — proíbe tools nesta resposta.
  • +
  • "validated" — usado também como mode em mcp_server.allowed_tools.
  • +
+ + + + +

6.11 Function calling & state machine

+

Function calling client-side segue um ciclo claro em três passos: (1) modelo recebe input + tools e devolve status: "requires_action" com um step function_call; (2) cliente executa a função; (3) cliente cria nova interaction com previous_interaction_id e passa o resultado como step function_result.

+ +

Estados possíveis de uma interação

+
+ + + + + + + + + + + +
statusSignificado
in_progressInferência em andamento (background ou síncrono interrompido).
requires_actionAguarda function_result ou aprovação de Computer Use.
completedSucesso; usage disponível.
failedErro irrecuperável; ler error.
cancelledCancelada via /cancel.
incompleteInteração terminou sem completar (ex.: limite atingido antes do fim).
budget_exceededOrçamento (tokens/ações) excedido durante a execução.
+
+

Enum completo de status na referência: in_progress, requires_action, completed, failed, cancelled, incomplete, budget_exceeded.

+ +

Exemplo completo — get_weather

+
weather_tool = {
+    "type": "function",
+    "name": "get_weather",
+    "description": "Tempo atual em uma cidade.",
+    "parameters": {
+        "type": "object",
+        "properties": {"location": {"type": "string"}},
+        "required": ["location"],
+    },
+}
+
+i1 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Como está o tempo em Tóquio?",
+    tools=[weather_tool],
+)
+assert i1.status == "requires_action"
+
+# Localizar o step de function_call
+fc = next(s for s in i1.steps if s.type == "function_call")
+result = {"temperature": "22C", "condition": "sunny"}
+
+i2 = client.interactions.create(
+    model="gemini-3.5-flash",
+    previous_interaction_id=i1.id,                # NÃO reenvie tools
+    input={
+        "type": "function_result",
+        "call_id": fc.id,                       # pareia com o function_call
+        "name": fc.name,
+        "result": result,
+    },
+)
+print(i2.output_text)
+ +

Em streaming: delta.type == "arguments"

+

Quando você usa stream=True, os argumentos da função chegam fragmentados via step.delta com delta.type == "arguments"; cada fragmento vem em delta.partial_arguments. Acumule os fragmentos e só faça json.loads() depois de receber o step.stop correspondente (ou no interaction.completed).

+
args_buffer = ""
+for ev in stream:
+    if ev.event_type == "step.delta" and ev.delta.type == "arguments":
+        args_buffer += ev.delta.partial_arguments
+    elif ev.event_type == "step.stop" and args_buffer:
+        import json
+        parsed = json.loads(args_buffer)   # agora é seguro
+        args_buffer = ""
+ +

Auto function calling — não há

+

Em generateContent, o SDK Python pode executar funções automaticamente passando callables. Na Interactions API, essa conveniência não existe: o roundtrip de function_call → function_result sempre é manual no cliente. Para fluxos onde isso pesa, prefira generateContent.

+ + + + +

6.12 Streaming SSE

+

Streaming é ativado com stream=True no SDK ou ?alt=sse + "stream": true no body REST. Os eventos do schema novo formam uma timeline tipada: interaction.created abre, vários step.start / step.delta / step.stop entremeiam, e ao final vem interaction.completed (com usage mas sem steps — você reconstrói via deltas acumulados) ou error, seguido do sentinel [DONE]. Transições intermediárias (incluindo requires_action) chegam como status dentro de interaction.status_update, não como evento próprio — o enum oficial de eventos SSE é apenas interaction.created, interaction.completed, interaction.status_update, error, step.start, step.delta, step.stop.

+ +

Eventos SSE — schema novo

+
+ + + + + + + + + + + + +
EventoQuando disparaPayload chave
interaction.createdimediatoobjeto interaction com id, status: in_progress
interaction.status_updatetransição de statusinteraction_id + novo status (inclui requires_action, in_progress etc.)
step.startinício de cada etapaindex, step.type
step.deltaincremento dentro da etapadelta.type + payload
step.stopfim da etapaindex
interaction.completedsucessoobjeto interaction com usage (sem steps)
errorfalhacode, message
[DONE]sentinel final do SSE—
+
+ +

delta.type possíveis

+
+ + + + + + + + + + + +
delta.typeConteúdo
textfragmento de texto (confirmado)
thought_summaryresumo de raciocínio quando thinking_summaries: "auto" (confirmado)
thought_signatureassinatura opaca de pensamento — não tente parsear (confirmado)
argumentsfragmento de argumentos de function_call em delta.partial_arguments — acumular antes de json.loads (confirmado)
image · audiofragmentos de mídia gerada em model_output (confirmados em ai.google.dev/gemini-api/docs/interactions/streaming; image carrega mime_type + data base64)
video · documentnão nomeados como delta types na página oficial de streaming até 2026-05-24 UNVERIFIED (2026-05-24)
annotation incrementala página oficial de streaming não nomeia um delta.type de annotation incremental até 2026-05-24 UNVERIFIED (2026-05-24)
+
+ +

Exemplo Python — streaming clássico

+
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Conte uma história curta sobre um robô curioso.",
+    stream=True,
+)
+
+for ev in stream:
+    if ev.event_type == "step.delta" and ev.delta.type == "text":
+        print(ev.delta.text, end="", flush=True)
+    elif ev.event_type == "interaction.completed":
+        u = ev.interaction.usage
+        print(f"\n[uso] in={u.total_input_tokens} out={u.total_output_tokens}")
+ +

Retomada via last_event_id (canônico)

+

Se o stream cair, cada chunk recebido carrega um event_id; mantenha o último em uma variável e reconecte via client.interactions.get(id=..., stream=True, last_event_id=...). Funciona apenas com stream=true. Padrão canônico conforme a documentação oficial de streaming (ai.google.dev/gemini-api/docs/interactions/streaming):

+
interaction_id = None
+last_event_id  = None
+done = False
+
+def process(stream):
+    global interaction_id, last_event_id, done
+    for ev in stream:
+        if ev.event_type == "interaction.created":
+            interaction_id = ev.interaction.id
+        if ev.event_id:
+            last_event_id = ev.event_id
+        if ev.event_type == "step.delta" and ev.delta.type == "text":
+            print(ev.delta.text, end="", flush=True)
+        elif ev.event_type in ("interaction.completed", "error"):
+            done = True
+
+stream = client.interactions.create(model="gemini-3.5-flash",
+                                    input="Pesquisa longa...", stream=True,
+                                    background=True)
+process(stream)
+
+while not done and interaction_id:
+    status = client.interactions.get(interaction_id)
+    if status.status != "in_progress":
+        break
+    stream = client.interactions.get(
+        id=interaction_id, stream=True, last_event_id=last_event_id,
+    )
+    process(stream)
+ +

Retomada via curl

+
curl -G "https://generativelanguage.googleapis.com/v1beta/interactions/$ID" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Api-Revision: 2026-05-20" \
+  --data-urlencode "stream=true" \
+  --data-urlencode "last_event_id=$LAST"
+ +

Padrão de output multimodal em stream

+

Imagens e áudio gerados chegam como delta.type dedicado dentro de um step.type == "model_output". Concatene os delta.data base64 entre step.start e step.stop do mesmo index para reconstruir o arquivo final — ou simplesmente leia interaction.output_image / output_audio após o interaction.completed via GET /interactions/{id}.

+ + + + +

6.13 Agents & environment

+

Uma interação usa model (modelo) ou agent (agent pré-construído) — nunca os dois. O endpoint é o mesmo POST /v1beta/interactions. A referência oficial (ai.google.dev/api/interactions-api, enum AgentOption) define três valores aceitos em agent: os dois Deep Research e o Antigravity (antigravity-preview-05-2026). Há dois tipos de agent_config discriminados por type: DeepResearchAgentConfig (type: "deep-research") e DynamicAgentConfig (type: "dynamic"). O Antigravity é tanto o coding agent que suporta skills quanto um agent agêntico da Interactions API (ai.google.dev/gemini-api/docs/antigravity-agent): por padrão tem code_execution, google_search e url_context; não suporta structured output, file_search, computer_use, google_maps, function_calling nem mcp.

+ +

A Interactions API também expõe managed agents customizados (ai.google.dev/gemini-api/docs/custom-agents): via client.agents.create / list / get / delete, salve uma configuração (id, base_agent — hoje só antigravity-preview-05-2026 —, system_instruction, base_environment) e invoque-a depois por ID em client.interactions.create(agent="seu-id", ...). Cada invocação forka o base_environment, então toda run começa limpa.

+ +

Agents pré-construídos aceitos no campo agent

+
+ + + + + + + +
Agent IDTipo
deep-research-preview-04-2026Deep Research rápido
deep-research-max-preview-04-2026Deep Research Max (exaustivo)
antigravity-preview-05-2026Antigravity (agentic workflow / coding agent)
+
+ +

Campo environment (EnvironmentConfig)

+

O campo top-level environment aceita ou uma string referenciando um environment existente, ou um objeto EnvironmentConfig (type: "remote") que provisiona um ambiente remoto com sources[] (GCS, inline, repository, skill_registry) e uma network.allowlist[]. A resposta expõe environment_id (output only) quando um environment é configurado. Os tipos de source válidos são gcs, inline, repository e skill_registry.

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Use os skills carregados para gerar os slides.",
+    environment={
+        "type": "remote",
+        "sources": [
+            {
+                "type": "repository",
+                "source": "https://github.com/my-org/my-skills.git",
+                "target": ".agents/skills",
+            },
+            {
+                "type": "gcs",
+                "source": "gs://my-bucket/my-folder",
+                "target": "/workspace/data",
+            },
+        ],
+    },
+)
+print(interaction.environment_id)   # só populado quando environment é configurado
+ +

Network allowlist com injeção de headers

+

O environment.network.allowlist[] restringe os domínios acessíveis pelo ambiente e pode injetar headers (ex.: tokens) via transform — que é um objeto de pares header→valor (não um array):

+
interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Liste meus repositórios no GitHub.",
+    environment={
+        "type": "remote",
+        "network": {
+            "allowlist": [
+                {
+                    "domain": "api.github.com",
+                    "transform": {"Authorization": "Bearer YOUR_GITHUB_TOKEN"},
+                }
+            ]
+        },
+    },
+)
+ + + + +

6.14 Deep Research / Deep Think

+

Deep Research é um agent dedicado que roda em background com loops de pesquisa estendida, browsing, raciocínio prolongado e (opcionalmente) visualizações. Use sempre com background=true e faça polling via client.interactions.get(id) ou ouça SSE com retomada.

+ +

Variantes

+
+ + + + + + +
Agent IDTrade-off
deep-research-preview-04-2026Rápido; bom para perguntas de média profundidade.
deep-research-max-preview-04-2026Exaustivo; loops longos, melhor para investigações pesadas.
+
+ +

DeepResearchAgentConfig

+
+ + + + + + + + +
CampoValoresFunção
type"deep-research"Discriminador.
collaborative_planningtrue / falseHITL — modelo apresenta plano e aguarda confirmação humana antes de executar.
thinking_summaries"auto" / "none"Streaming de thought_summary com explicações em linguagem natural.
visualization"off" / "auto"Charts e infográficos — só dispara se o prompt pedir explicitamente.
+
+ +

Exemplo — Deep Research com polling

+
import time
+job = client.interactions.create(
+    agent="deep-research-preview-04-2026",
+    input="Histórico das TPUs do Google com foco em specs 2025.",
+    background=True,
+    agent_config={"type": "deep-research", "thinking_summaries": "auto"},
+)
+
+while True:
+    cur = client.interactions.get(job.id)
+    print(cur.status)
+    if cur.status == "completed":
+        print(cur.output_text)
+        break
+    elif cur.status in ("failed", "cancelled"):
+        raise RuntimeError(cur.error)
+    time.sleep(10)
+ +

Collaborative planning (HITL)

+
plan = client.interactions.create(
+    agent="deep-research-preview-04-2026",
+    input="Pesquisar TPUs do Google vs. concorrentes de aceleradores de IA.",
+    agent_config={"type": "deep-research", "collaborative_planning": True},
+    background=True,
+)
+# Cliente revisa o plano apresentado em plan.output_text...
+
+approve = client.interactions.create(
+    agent="deep-research-preview-04-2026",
+    input="Plano aprovado, prossiga.",
+    agent_config={"type": "deep-research", "collaborative_planning": False},
+    previous_interaction_id=plan.id,
+    background=True,
+)
+ +

Webhook em vez de polling

+
job = client.interactions.create(
+    agent="deep-research-max-preview-04-2026",
+    input="Análise comparativa exaustiva sobre mercado de chips de IA.",
+    background=True,
+    webhook_config={
+        "uris": ["https://api.minha-empresa.com/webhooks/deep-research"],
+        "user_metadata": {"jobId": "j-12345", "userId": "u-789"},
+    },
+)
+ +

Deep Think

+

Deep Think aparece na visão geral como caso de uso de "operações longas" mas não existe como string agent= dedicada: o enum AgentOption da referência oficial (ai.google.dev/api/interactions-api) só lista os três Deep Research e o Antigravity. Deep Think é uma capacidade de modelo ativada por generation_config.thinking_level.

+ + + + +

6.15 Parâmetros completos

+ +

Top-level

+
+ + + + + + + + + + + + + + + + + + + + +
CampoTipoObrig.Notas
modelenum stringsim, se agent ausenteID do modelo (ver §6.17).
agentenum stringsim, se model ausenteID do agent (os três deep-research-* e antigravity-preview-05-2026 na referência oficial).
inputstring | Content | Content[] | Step[]simEntrada — string vira texto puro; array suporta multimodal com discriminadores.
system_instructionstringnãoDiretiva de sistema. Interaction-scoped: re-declare a cada turn que precise.
toolsTool[]nãoInteraction-scoped; ver §6.10.
response_formatResponseFormat | ResponseFormat[]nãoPolimórfico com discriminador type (substitui o antigo response_mime_type).
response_modalities("text"|"image"|"audio"|"video"|"document")[]nãoForçar modalidade(s) de saída.
streambooleannãoAtiva SSE.
storebooleannão (default true)false desabilita previous_interaction_id e background.
backgroundbooleannãoAsync; requer polling ou webhook_config.
generation_configGenerationConfignãoMutuamente exclusivo com agent_config.
agent_configDynamicAgentConfig | DeepResearchAgentConfignãoMutuamente exclusivo com generation_config.
previous_interaction_idstringnãoEncadeamento server-side; cache implícito automático.
service_tier"flex" | "standard" | "priority"nãoPriority custa mais e tem 0.3× do limite std.
webhook_config{uris[], user_metadata}nãoPara notificação assíncrona em fluxos background; uris é um array.
environmentEnvironmentConfig | stringnãoAmbiente remoto com sources[] e network.allowlist[]; ver §6.13.
+
+ +

generation_config

+
+ + + + + + + + + + + + + + + +
CampoValoresNotas
temperaturefloatAleatoriedade. Em Gemini 3 manter 1.0.
top_pfloatSampling cumulativo.
seedintReprodutibilidade.
stop_sequencesstring[]Gatilhos de parada.
max_output_tokensintLimite de saída.
thinking_levelminimal | low | medium | highSubstitui thinking_budget em Gemini 3.5+.
thinking_summariesauto | noneStreaming de thought_summary.
speech_configobjetoVoz, idioma, speaker para TTS.
image_config legacyobjetoMigrado para response_format.{type:"image"} após 26/05/2026.
tool_choiceauto | any | none | validated (ou ToolChoiceConfig)Controle de seleção de tool.
response_formatpolimórfico (top-level no schema novo)Antes vivia aqui em legado; agora top-level.
+
+ +

image_config (legado) / response_format.{type:"image"} (novo)

+

Valores válidos:

+
    +
  • aspect_ratio: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:8, 8:1, 1:4, 4:1.
  • +
  • image_size: 512, 1K, 2K, 4K.
  • +
+ +

response_format polimórfico (schema novo)

+
# JSON estruturado
+response_format = {
+    "type": "text",
+    "mime_type": "application/json",
+    "schema": {"type": "object", "properties": {"answer": {"type": "string"}}},
+}
+
+# Imagem
+response_format = {
+    "type": "image",
+    "mime_type": "image/jpeg",
+    "aspect_ratio": "16:9",
+    "image_size": "1K",
+}
+
+# Áudio (formato do output — voz/idioma ficam em generation_config.speech_config)
+response_format = {
+    "type": "audio",
+    "mime_type": "audio/wav",    # audio/mp3 | audio/ogg_opus | audio/l16 | audio/alaw | audio/mulaw
+    "sample_rate": 24000,
+    "delivery": "inline",        # inline | uri
+}
+

Campos do AudioResponseFormat: mime_type, sample_rate, bit_rate (só formatos comprimidos) e delivery. Voz, idioma e speaker vivem em generation_config.speech_config, não no response_format. Você pode passar response_format como array para output multimodal (ex.: texto + imagem). Cada item carrega seu próprio type.

+ +

webhook_config

+
{
+  "uris": ["https://example.com/hooks/gemini"],
+  "user_metadata": {"jobId": "abc", "tenant": "acme"}
+}
+

uris é um array de endpoints; quando presente, esses URIs substituem os webhooks registrados no projeto. O endpoint recebe um POST com o interaction.id e o status final; faça GET para puxar o resultado completo.

+ +

EnvironmentConfig

+
{
+  "type": "remote",
+  "sources": [
+    {"type": "repository", "source": "https://github.com/org/repo.git", "target": ".agents/skills"}
+  ],
+  "network": {
+    "allowlist": [
+      {"domain": "api.exemplo.com", "transform": {"x-api-key": "$KEY"}}
+    ]
+  }
+}
+

Tipos de source válidos: gcs, inline, repository, skill_registry. O transform é um objeto header→valor.

+ + + + +

6.16 Output steps[] — timeline tipada

+

No schema novo (vigente desde 2026-05-20), o response carrega interaction.steps — uma lista de passos tipados que representa toda a timeline da interação. Cada step tem um type discriminador e um payload específico.

+ +

Tipos de step

+
+ + + + + + + + + + + + + + + + + + + +
step.typePayloadNotas
user_inputcontent[] (text/image/audio/video/document)Visível só via GET /interactions/{id}?include_input=true; nunca aparece no POST direto.
model_outputcontent[] tipadoO conteúdo final do modelo. Atalhos: output_text, output_image, output_audio.
thoughtsummary[] (text)Resumos de raciocínio quando thinking_summaries: "auto".
function_callid, name, arguments (object)Aguarda function_result com mesmo call_id.
function_resultcall_id, name, resultPareia com function_call.id.
google_search_callid, arguments.queries[], search_typeEmitido quando o modelo decide buscar.
google_search_resultcall_id, result[] (title/url/snippet), search_suggestionsResultado da busca.
url_context_callid, arguments.urls[]Quando url_context é acionado.
url_context_resultcall_id, result[] (url/status), com status ∈ success|error|paywall|unsafeTexto extraído da URL.
code_execution_callid, arguments.code (Python), arguments.languageSandbox executa.
code_execution_resultcall_id, is_error, result (string)Pareia com code_execution_call.id via call_id.
file_search_callidRAG via Files store.
file_search_resultcall_idTrechos recuperados.
mcp_server_tool_call / mcp_server_tool_resultid/call_id, name, server_name, arguments / resultQuando um mcp_server é invocado.
google_maps_call / google_maps_resultid/call_id, arguments.queries[] / result[].places[]Quando google_maps é acionado.
+
+ +

Atalhos de conveniência

+
+ + + + + + + + +
AtalhoO que retorna
interaction.output_textConcatena últimos blocos text do model_output final.
interaction.output_imageÚltimo bloco image do model_output final.
interaction.output_audioÚltimo bloco audio do model_output final.
interaction.stepsLista completa de steps tipados.
+
+ +

Padrão de iteração

+
for i, step in enumerate(interaction.steps):
+    print(f"--- step {i} [{step.type}] ---")
+    if step.type == "model_output":
+        for c in step.content:
+            if c.type == "text":
+                print("text:", c.text[:200])
+            elif c.type == "image":
+                print("image bytes:", len(c.data))
+    elif step.type == "function_call":
+        print("call:", step.name, step.arguments)
+    elif step.type == "code_execution_result":
+        print("outcome:", step.outcome, "out:", step.output[:200])
+ +

Annotations

+

Em blocos text de model_output, annotations[] referenciam citações. Cada annotation aponta para um intervalo do texto e a fonte (URL, file URI, ou step ID). Use para construir UI com links inline.

+ + + + +

6.17 Modelos e agentes suportados

+ +

Modelos (model)

+
+ + + + + + + + + + + + + + +
Model IDCategoriaNotas
gemini-3.1-pro-previewSOTA reasoningPreview; complexidade alta, código, raciocínio.
gemini-3.5-flashFlash 1M, multimodal, defaultEstável; padrão recomendado para a maioria das aplicações.
gemini-3.1-flash-liteCost-efficientEstável; alto volume.
gemini-3.1-flash-imageGeração de imagem (Nano Banana 2)GA desde 28/05/2026 (saiu de preview). 32k input / 65k output em tokens.
gemini-3-pro-imageImagem (Nano Banana Pro)GA desde 28/05/2026. Geração/edição de imagem de alta fidelidade.
gemini-3.1-flash-tts-previewTTS expressivoBaixa latência.
gemini-3.1-flash-live-previewLive API (áudio/vídeo bidir)Superfície WebSocket separada; ver Live API.
gemini-3.5-live-translate-previewTradução de fala ao vivo (speech-to-speech)Preview (novo); superfície Live, com suporte no SDK via TranslationConfig (google-genai 2.8.0+).
gemini-embedding-2Embeddings3072 dims (recomendado).
gemini-2.5-computer-use-preview-10-2025Agente de UI (Computer Use)Modelo dedicado de Computer Use; gemini-3-flash-preview também tem suporte nativo (verificado 2026-06-03). Usado com a tool computer_use.
+
+

NÃO aceitos como model: gemini-3.1-flash-live-preview e gemini-3.5-live-translate-preview (Live API é superfície separada WebSocket).

+ +

Agentes (agent)

+
+ + + + + + + +
Agent IDTipo
deep-research-preview-04-2026Deep Research rápido
deep-research-max-preview-04-2026Deep Research Max (exaustivo)
antigravity-preview-05-2026Antigravity (agentic workflow / coding agent)
+
+

A referência oficial (ai.google.dev/api/interactions-api) aceita em agent os três Deep Research acima e o Antigravity (enum AgentOption com quatro valores). O antigravity-preview-05-2026 é tanto o coding agent que suporta skills quanto um agent agêntico invocável pela Interactions API (ai.google.dev/gemini-api/docs/antigravity-agent); além disso, managed agents customizados via client.agents.* usam antigravity-preview-05-2026 como base_agent (ver §6.13).

+ +

Vertex AI

+

Até 2026-05-24, a documentação oficial (ai.google.dev/api/interactions-api e ai.google.dev/gemini-api/docs/interactions) só descreve a Interactions API no Gemini Developer API / Google AI Studio (endpoint generativelanguage.googleapis.com); a página de migração do Vertex AI (cloud.google.com/vertex-ai/generative-ai/docs/migrate/migrate-google-ai) não expõe nenhum endpoint interactions. Para Vertex hoje, use generateContent.

+ + + + +

6.18 Migração outputs[] → steps[] (Maio 2026)

+

A v1beta da Interactions API aplicou em maio/2026 duas mudanças incompatíveis: (1) rename de outputs[] → steps[] com novos tipos de etapa; (2) substituição de response_mime_type top-level e generation_config.image_config por um response_format polimórfico. O schema legado foi removido em 08/06/2026 — quem ainda usava o schema legado quebrou nessa data, conforme a página oficial de breaking changes.

+ +
+ Cronograma oficial — confirmado pela página oficial de breaking changes (ai.google.dev/gemini-api/docs/interactions-breaking-changes-may-2026, verificado 2026-05-24). O schema novo (steps[] substituindo outputs[]) é a breaking change; exige-se google-genai >= 2.0.0 / @google/genai >= 2.0.0; em REST, o header Api-Revision: 2026-05-20 optava pelo schema novo durante a janela de migração. Todas as etapas abaixo já se consumaram (re-verificado 2026-06-10). +
    +
  • 07/05/2026 — anúncio da breaking change (entrada nas release notes / changelog).
  • +
  • 20/05/2026 — revisão-alvo do schema novo: valor do header Api-Revision: 2026-05-20 para opt-in via REST.
  • +
  • 26/05/2026 — novo schema virou o padrão no REST (sem o header, a resposta já usa steps[]).
  • +
  • 08/06/2026 — schema legado removido (consumado): SDKs 1.x quebraram e o header Api-Revision de rollback passou a ser ignorado — rollback impossível.
  • +
+
+ +

Schema do response — ANTES vs DEPOIS

+
+ + + + + + + + +
ANTES (legacy)DEPOIS (novo)
{
+  "outputs": [
+    {"type": "text", "text": "..."},
+    {"type": "function_call",
+     "name": "get_weather",
+     "arguments": {...}}
+  ]
+}
{
+  "steps": [
+    {"type": "model_output",
+     "content": [
+       {"type": "text", "text": "..."}
+     ]},
+    {"type": "function_call",
+     "name": "get_weather",
+     "arguments": {...}}
+  ]
+}
+
+ +

Eventos SSE — ANTES vs DEPOIS

+
+ + + + + + + + + + +
ANTES (legacy)DEPOIS (novo)
content.startstep.start
content.deltastep.delta
content.stopstep.stop
interaction.startinteraction.created
interaction.completeinteraction.completed
interaction.status_updateinteraction.status_update (status in_progress / requires_action dentro do payload)
+
+ +

Output format — ANTES vs DEPOIS

+
+ + + + + + + + + + + + + + +
CasoANTESDEPOIS
JSON estruturado
{
+  "response_mime_type": "application/json",
+  "response_format": {
+    "type": "object",
+    "properties": {...}
+  }
+}
{
+  "response_format": {
+    "type": "text",
+    "mime_type": "application/json",
+    "schema": {"type": "object", ...}
+  }
+}
Imagem
{
+  "generation_config": {
+    "image_config": {
+      "aspect_ratio": "1:1",
+      "image_size": "1K"
+    }
+  }
+}
{
+  "response_format": {
+    "type": "image",
+    "mime_type": "image/jpeg",
+    "aspect_ratio": "1:1",
+    "image_size": "1K"
+  }
+}
+
+ +

Código que quebrou em 08/06/2026

+
    +
  • Qualquer leitura de interaction.outputs[...].
  • +
  • Referência a output.type == "function_call" no array outputs.
  • +
  • Campo top-level response_mime_type.
  • +
  • Campo generation_config.image_config.
  • +
  • Listeners SSE em content.delta, content.start, content.stop, interaction.start, interaction.complete.
  • +
  • Python SDK 1.x e JS SDK 1.x.
  • +
+ +

Caminho de migração por cliente

+
+ + + + + + + + + + +
ClienteAção
REST antes de 26/05/2026Opt-in com header Api-Revision: 2026-05-20.
REST entre 26/05 e 08/06/2026Schema novo é default; rollback temporário com Api-Revision: 2026-05-07.
REST após 08/06/2026Sem rollback; header ignorado.
PythonAtualizar para google-genai >= 2.0.0; ler interaction.steps.
JavaScript / TypeScriptAtualizar para @google/genai >= 2.0.0.
Histórico statelessAntes passava outputs[] no input do próximo turno; agora passa steps[] (com o novo turno adicionado como user_input).
+
+

A doc oficial recomenda automatizar a migração com um coding agent que suporte skills (ex.: Antigravity): instale a skill gemini-interactions-api e rode /gemini-interactions-api migrate my app to Gemini 3.5 Flash. A doc também cita renomear o modelo gemini-3-flash-preview → gemini-3.5-flash e substituir thinking_budget por thinking_level como parte da migração.

+ + + + +

6.19 Limitações & gotchas

+ +

Recursos AUSENTES (confirmado)

+
    +
  • safety_settings ausente — não existe em top-level, generation_config, agent_config ou response_format. O único mecanismo de safety na Interactions API é runtime: um safety_decision opcional em Computer Use, que classifica a ação proposta como "regular / allowed" (ou ausência de safety_decision) ou require_confirmation (exige confirmação humana antes de executar), com explicação textual. O conjunto exato de valores enum do safety_decision não é totalmente documentado até 2026-05-24 UNVERIFIED (2026-05-24); a referência oficial (ai.google.dev/api/interactions-api) confirma "regular/allowed" e require_confirmation. Para controle granular por HARM_CATEGORY_*, faça fallback a generateContent. Mitigador prático: em Gemini 3.x o threshold padrão em generateContent já é Off, então comportamentalmente a Interactions API segue o padrão "sem filtros adicionais por categoria".
  • +
  • API Batch ausente — Batch permanece apenas em generateContent (client.batches.create).
  • +
  • Cache explícito (cachedContent) ausente — apenas cache implícito via previous_interaction_id.
  • +
  • Auto function calling em Python ausente — roundtrip de function_call / function_result sempre é manual.
  • +
  • video_metadata customizado ausente — sem startOffset / endOffset / FPS customizado; apenas resolution.
  • +
  • Método nativo count_tokens ausente — para estimar antes da chamada, use client.models.count_tokens(...). Contagem real vem em interaction.usage após a chamada (e em streaming, só no interaction.completed).
  • +
  • Live API não substituída — Live API (WebSocket bidirecional) é superfície independente; Interactions é request/response (com SSE).
  • +
+ +

Limites quantitativos

+
    +
  • Total inline da request < 20 MB (todos os data em base64 + texto + system_instruction). (confirmado)
  • +
  • Imagens: 3.600 máx por request. (confirmado)
  • +
  • Áudio: 9,5 horas combinadas (confirmado em ai.google.dev/gemini-api/docs/interactions/audio); downsampleado para 16 kbps mono; 32 tokens/segundo (confirmado).
  • +
  • Vídeo: inline < 100 MB; Files API até 20 GB pago / 2 GB free; 1 hora em resolução padrão ou 3 horas em low.
  • +
  • PDF: 50 MB e 1.000 páginas (confirmado em ai.google.dev/gemini-api/docs/interactions/document-processing); render entre 768×768 e 3072×3072.
  • +
  • Files API: retenção 48h; 2 GB por arquivo, 20 GB por projeto.
  • +
  • Retenção de interaction.id: 55 dias pago / 1 dia free.
  • +
+ +

Edge cases e gotchas

+
    +
  • store=false bloqueia previous_interaction_id e background=true — combinação impossível.
  • +
  • Em streaming, o evento interaction.completed traz usage mas não traz steps; reconstrua via deltas acumulados ou faça GET /interactions/{id}.
  • +
  • Argumentos de function_call em streaming chegam em delta.partial_arguments (com delta.type == "arguments") — sempre acumular antes de json.loads().
  • +
  • thought_signature é opaco; não tente parsear — usado para integridade do modelo.
  • +
  • MCP remoto em Gemini 3: não suportado segundo a doc oficial de tools (ai.google.dev/gemini-api/docs/interactions/tool-combination, "coming soon") — use mcp_server local enquanto isso.
  • +
  • Vertex AI parity: até 2026-05-24 a página de migração do Vertex AI (cloud.google.com/vertex-ai/generative-ai/docs/migrate/migrate-google-ai) não expõe endpoint interactions; disponível só no Gemini Developer API.
  • +
  • Regiões / data residency: não documentado oficialmente até 2026-05-24 UNVERIFIED (2026-05-24) — Google AI Studio é infra global sem region-pinning explícito; ZDR formal só em Vertex (que ainda não tem Interactions).
  • +
  • Endpoint path: usar sempre v1beta/interactions (não v1beta2) — conforme a referência oficial (ai.google.dev/api/interactions-api).
  • +
  • Tools são interaction-scoped: re-declare a cada turn que use; não reenvie em function_result roundtrip.
  • +
  • Visualization em Deep Research só dispara se o prompt pedir explicitamente — controle via agent_config.visualization não basta.
  • +
  • Grounding com Google Search / Maps: política de retenção/armazenamento específica de prompt+output não é documentada oficialmente até 2026-05-24 UNVERIFIED (2026-05-24) — a referência oficial (ai.google.dev/api/interactions-api) só confirma grounding_tool_count em usage e os steps google_search_* / google_maps_*.
  • +
+ +

ZDR (Zero Data Retention)

+
    +
  • ZDR formal é capability do Vertex AI (via emenda à DPA). Interactions ainda não está no Vertex.
  • +
  • No Developer API, aproxime ZDR com store=false. Custo: perde previous_interaction_id e background; reanexe histórico do cliente.
  • +
  • File API e cache implícito (RAM, TTL 24h) seguem regras independentes — confira ai.google.dev/gemini-api/docs/zdr.
  • +
+ + + + +

6.20 Diferenças vs generateContent — tabela cruzada

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectogenerateContentInteractions API
Path RESTPOST /v1beta/models/{model}:generateContentPOST /v1beta/interactions
Streaming REST:streamGenerateContentmesmo endpoint + "stream": true + ?alt=sse
Estado da conversacliente (reenvia contents[])servidor (previous_interaction_id)
Respostacandidates[].content.parts[]steps[] com tipos discriminados
Atalho de textoresponse.textinteraction.output_text
Imagem finaliterar parts em busca de inlineData com MIME image/*interaction.output_image
Áudio finaliterar parts em busca de inlineData com MIME audio/*interaction.output_audio
Function callparts[].functionCallstep {type: "function_call"}
Function result no inputfunctionResponse partstep {type: "function_result", call_id, name, result}
Status pendenten/astatus: "requires_action"
Streaming function argsbloco únicodelta.partial_arguments (acumular)
MIME imagemPNG, JPEG, WEBP, HEIC, HEIFPNG, JPEG, WEBP, HEIC, HEIF (oficial); GIF/BMP/TIFF aceitos mas não listados UNVERIFIED (2026-05-24)
MIME áudioWAV, MP3, AIFF, AAC, OGG, FLACWAV, MP3/MPEG, AIFF, AAC, OGG, FLAC, M4A, OPUS, ALAW, MULAW
MIME vídeoMP4, MPEG, MOV, AVI, FLV, MPG, WEBM, WMV, 3GPPidêntico
MIME documentoapplication/pdf + TXT/MD/HTML/XML como textoidêntico
Controle de vídeovideoMetadata.{startOffset,endOffset,fps}não — só resolution
Grounding (Search)groundingMetadata separadoannotations[] inline + steps google_search_call/google_search_result
Background tasksn/abackground=true + polling ou webhook
Cancelamenton/aPOST /interactions/{id}/cancel
Retomada de streamn/a (refazer request inteira)GET /interactions/{id}?stream=true&last_event_id=...
Cache explícito (cachedContent)suportadonão
Cache implícito≥ 1024 / 4096 tokens de prefixo idênticoauto via previous_interaction_id
Batchsuportadonão
Auto function calling (Py)suportadonão
safety_settingssuportadoausente (apenas safety_decision runtime)
Métricas de tokensusage_metadata.*_countusage.total_*_tokens + *_by_modality
Agents pré-construídosn/acampo agent (Deep Research + Antigravity) + environment opcional
Deep Researchn/aagent="deep-research-*" + agent_config
Webhookn/awebhook_config para background
Service tierserviceTierservice_tier idêntico
Vertex AIsuportadonão em 2026-05-24 (roadmap)
+
+ +
+ Resumo prático. Use Interactions API quando precisa de: estado server-side, tarefas longas (Deep Research / Deep Think via background=true), function call com state machine explícito, retomada de SSE, ou ambientes remotos via environment. Continue em generateContent quando precisa de: Batch, cachedContent explícito, auto function calling em Python, video_metadata customizado, safety_settings por categoria, ou execução em Vertex AI hoje. +
+
+ +
+
Anthropic Claude
+

Anthropic — deep dive

+

+ Anthropic Claude trata multimodalidade de forma deliberadamente enxuta: visão (JPEG/PNG/GIF/WebP) e PDF são nativos no + endpoint POST /v1/messages; CSV/XLSX/DOCX/PPTX entram pelo Code Execution tool (sandbox Python 3.11); + áudio e vídeo não têm bloco de conteúdo nativo — o caminho oficial é pré-processar (transcrição, extração de frames) e mandar o + resultado como blocos text/image. A Files API (beta header files-api-2025-04-14) substitui o + base64 em todas as superfícies acima e é o único modo de carregar arquivos para dentro do sandbox de Code Execution via blocos + container_upload. +

+ +

7.1 API surface

+

+ Todo o trabalho multimodal flui por um único endpoint síncrono: +

+
POST https://api.anthropic.com/v1/messages
+

Cabeçalhos relevantes para multimodal:

+
+ + + + + + + + + + + +
HeaderValorQuando
x-api-key$ANTHROPIC_API_KEYSempre
anthropic-version2023-06-01Sempre (ainda válido em 2026-05-23 mesmo após várias adições à API)
content-typeapplication/jsonTodas as requisições JSON
anthropic-betafiles-api-2025-04-14Obrigatório em /v1/files, em source.type=file e em blocos container_upload
anthropic-betacode-execution-2025-08-25SDKs Python/TS aceitam o tool code_execution_20250825 diretamente em messages.create() sem cabeçalho extra; explícito no Go SDK
anthropic-betacode-execution-2026-01-20 UNVERIFIED (2026-05-23)Valor inferido do padrão de versionamento; use client.beta.messages.create(..., betas=["code-execution-2026-01-20"])
anthropic-betaoutput-300k-2026-03-24Opcional, somente no Message Batches API, para liberar 300k tokens de output em Opus 4.8 e Sonnet 4.6
+
+

+ Vários cabeçalhos beta podem ser combinados com vírgula, ex.: anthropic-beta: files-api-2025-04-14,code-execution-2025-08-25. Nos SDKs + isso é exposto como o parâmetro betas=[...] no namespace beta.*. +

+ +

Taxonomia de content blocks (lado request)

+

O campo content é uma lista de blocos tipados. Os tipos relevantes para multimodal são:

+
+ + + + + + + + + + +
Block typePara que serveSources / campos
textTexto puro (instruções, transcrições, CSV inline)text: string
imageEntrada de visãosource: { type: "base64" | "url" | "file", ... }
documentPDF, texto puro, custom citation contentsource: { type: "base64" | "url" | "file" | "text" | "content", ... }, opcional title, context, citations: { enabled: bool }
container_uploadMonta um arquivo da Files API dentro do sandbox de Code Executionfile_id: string
tool_use / tool_resultRound-trips de tool callingProtocolo Anthropic padrão de tool use
thinkingBlocos de raciocínio adaptativo (lado response)Retornado pelo modelo; devolva inalterado em turnos seguintes
+
+

+ A resposta também pode conter server-tool blocks (server_tool_use, bash_code_execution_tool_result, + text_editor_code_execution_tool_result, code_execution_tool_result) quando code execution, web search ou web fetch estão habilitados. +

+ +

Compatibilidade modelo × modalidade (geração atual, maio de 2026)

+

Fonte: models/overview + a tabela de compatibilidade do Code Execution (ambos verificados em 2026-05-23).

+
+ + + + + + + + + +
ModeloAPI IDAliasContextOutput (sync)VisãoPDF nativo…20250825…20260120
Claude Opus 4.8claude-opus-4-8claude-opus-4-81M128kSim (hi-res 2576 px)SimSimSim
Claude Sonnet 4.6claude-sonnet-4-6claude-sonnet-4-61M64kSimSimSimSim
Claude Haiku 4.5claude-haiku-4-5-20251001claude-haiku-4-5200k64kSimSimSimNão
+
+
+ Modelos atuais. Use claude-opus-4-8 (frontier), claude-sonnet-4-6 (balanceado) e claude-haiku-4-5 (baixo custo). +
+

+ Visão e PDF são universais entre todos os modelos ativos — escolha por throughput/custo, não por modalidade. Code Execution + não roda em Amazon Bedrock nem Vertex AI hoje; está disponível na API first-party da Claude, na Claude Platform on AWS e no Microsoft Foundry. +

+ +

7.2 Imagem / visão

+ +

Source types (três, mais um caso especial)

+

+ Um bloco image aceita três valores para source.type. Eles são intercambiáveis no que Claude "vê" — diferem em payload, latência e reutilização: +

+
+ + + + + + + +
source.typeCampos obrigatóriosQuando usar
base64media_type, data (bytes em base64)Arquivos locais, pipelines offline, Amazon Bedrock / Vertex AI (que hoje só aceitam base64)
urlurl (HTTPS para imagem buscável)Imagens públicas, fastest to author — Claude busca o arquivo no servidor
filefile_id (vindo da Files API)Imagens reutilizadas entre turnos ou requisições; mantém o payload pequeno em agents multi-turno
+
+
+ Em Amazon Bedrock e Vertex AI, somente base64 está disponível como source no momento. +
+ +

MIME types suportados

+
image/jpeg
+image/png
+image/gif    (animações não suportadas — apenas o primeiro frame é lido)
+image/webp   (WebP lossy pode degradar OCR; teste antes de comprimir)
+ +

Limites de tamanho, contagem e resolução

+

Números retirados da página vision (verificada em 2026-05-23):

+
+ + + + + + + + + + + +
LimiteValorNotas
Máx. imagens por turno no claude.ai20Superfície UI, não API
Máx. imagens por request em modelos de 200k ctx100Haiku 4.5 (contexto 200k)
Máx. imagens por request em modelos 1M ctx600Opus 4.8, Sonnet 4.6
Dimensões máximas8000 × 8000 px em geralSe >20 imagens no mesmo request, o teto cai para 2000 × 2000 px
Tamanho de arquivo via API5 MB por imagemRejeição imediata acima disso
Tamanho de arquivo via claude.ai10 MBUI
Tamanho total do request (endpoints padrão)32 MBUse Files API quando o número de imagens for grande
+
+ +

Resolução nativa e tokenização

+
    +
  • Modelos padrão (Sonnet 4.6, Haiku 4.5): nativo ≈ 1568 tokens por imagem, no máximo 1568 px no lado longo.
  • +
  • Claude Opus 4.8 (hi-res): nativo ≈ 4784 tokens por imagem, até 2576 px no lado longo. Hi-res é automático no Opus 4.8 — sem cabeçalho beta.
  • +
+

+ Inputs maiores são downscaled preservando aspect ratio e padded no fundo/direita até um múltiplo de 28 px. Coordenadas que o modelo retorna + (bounding boxes, pontos) referem-se à imagem já redimensionada e paddada — reescale no cliente antes de desenhar sobre o original. +

+

Fórmula de estimativa:

+
tokens ≈ (width × height) / 750
+ +

Custos com exemplos (input, maio/2026)

+
+ + + + + + + + + +
Tamanho da imagemTokens (padrão)Sonnet 4.6 ($3/MTok)Tokens (Opus 4.8)Opus 4.8 ($5/MTok)
200 × 200 px~54~$0.00016~54~$0.00027
1000 × 1000 px (1 MP)~1334~$0.0040~1334~$0.0067
1092 × 1092 px (~1.19 MP, "sweet spot")~1568~$0.0047~1590~$0.0080
1920 × 1080 px (~2 MP, downscaled no padrão)~1568~$0.0047~2765~$0.014
2000 × 1500 px (3 MP, downscaled no padrão)~1568~$0.0047~4000~$0.020
+
+
+ Regra prática: em modelos não-Opus-4.8, mire ~1.15 MP (~1100 px no lado longo) — acima disso o servidor faz downsample mas você já pagou latência. Em Opus 4.8, dimensione conforme a fidelidade real necessária; o multiplicador de ~3× em tokens para ≥2 MP é dinheiro real. +
+ +

Exemplos — Python e TypeScript

+

Instalação: pip install anthropic httpx · npm i @anthropic-ai/sdk

+ +

Base64

+
+
+ + +
+
+
import anthropic, base64, httpx, os
+
+client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
+
+url = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
+img_bytes = httpx.get(url).content
+img_b64 = base64.standard_b64encode(img_bytes).decode("utf-8")
+
+msg = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "image", "source": {
+                "type": "base64",
+                "media_type": "image/jpeg",
+                "data": img_b64,
+            }},
+            {"type": "text", "text": "Describe this image in one sentence."},
+        ],
+    }],
+)
+print(msg.content[0].text)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+import fs from "fs";
+
+const client = new Anthropic();
+const data = fs.readFileSync("photo.jpg").toString("base64");
+
+const r = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "image", source: { type: "base64", media_type: "image/jpeg", data } },
+      { type: "text", text: "What's in this photo?" },
+    ],
+  }],
+});
+console.log(r.content[0].text);
+
+
+ +

URL

+
+
+ + +
+
+
msg = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "image", "source": {
+                "type": "url",
+                "url": "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg",
+            }},
+            {"type": "text", "text": "Describe this image."},
+        ],
+    }],
+)
+
+
+
const r = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "image", source: { type: "url", url: "https://example.com/x.png" } },
+      { type: "text", text: "Describe this image." },
+    ],
+  }],
+});
+
+
+ +

Files API (file_id)

+
+
+ + +
+
+
with open("photo.jpg", "rb") as f:
+    upload = client.beta.files.upload(file=("photo.jpg", f, "image/jpeg"))
+
+msg = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    betas=["files-api-2025-04-14"],
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "image", "source": {"type": "file", "file_id": upload.id}},
+            {"type": "text", "text": "Describe this image."},
+        ],
+    }],
+)
+
+
+
import Anthropic, { toFile } from "@anthropic-ai/sdk";
+import fs from "fs";
+
+const client = new Anthropic();
+const up = await client.beta.files.upload({
+  file: await toFile(fs.createReadStream("photo.jpg"), undefined, { type: "image/jpeg" }),
+});
+
+const r = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  betas: ["files-api-2025-04-14"],
+  messages: [{
+    role: "user",
+    content: [
+      { type: "image", source: { type: "file", file_id: up.id } },
+      { type: "text", text: "Describe this image." },
+    ],
+  }],
+});
+
+
+ +

Múltiplas imagens com rótulos (best practice: rotule cada imagem; coloque o texto da pergunta depois das imagens)

+
+
+ + +
+
+
msg = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text", "text": "Image 1:"},
+            {"type": "image", "source": {"type": "url", "url": URL_ANT}},
+            {"type": "text", "text": "Image 2:"},
+            {"type": "image", "source": {"type": "url", "url": URL_BEE}},
+            {"type": "text", "text": "How are these images different?"},
+        ],
+    }],
+)
+
+
+
const r = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "text", text: "Image 1:" },
+      { type: "image", source: { type: "url", url: URL_ANT } },
+      { type: "text", text: "Image 2:" },
+      { type: "image", source: { type: "url", url: URL_BEE } },
+      { type: "text", text: "How are these images different?" },
+    ],
+  }],
+});
+
+
+ +

Limitações de visão (verbatim do guia oficial)

+
    +
  • Identificação de pessoas: Claude não nomeia pessoas em imagens e recusa fazê-lo (Acceptable Use Policy).
  • +
  • Precisão: alucinações/erros em imagens de baixa qualidade, rotacionadas ou abaixo de 200 px.
  • +
  • Raciocínio espacial limitado: relógios, posições de peças de xadrez, layouts finos.
  • +
  • Contagem: aproximada para grandes quantidades de objetos pequenos.
  • +
  • Detecção de imagem gerada por IA: Claude não detecta de forma confiável imagens sintéticas — não use como detector de fake.
  • +
  • Conteúdo impróprio é recusado por AUP.
  • +
  • Saúde: pode analisar imagens médicas gerais, mas não é ferramenta de diagnóstico para CT/MRI; jamais substitua aconselhamento médico.
  • +
  • Metadados: Claude não lê EXIF nem metadados de imagem.
  • +
  • Persistência: uploads via base64/URL são efêmeros, descartados após a request; imagens via Files API persistem até serem deletadas.
  • +
  • Geração/edição: Claude é image-understanding only. Não gera nem edita imagens — use OpenAI gpt-image-2, Gemini gemini-3.1-flash-image, Stability etc.
  • +
+ +

7.3 PDF

+ +

Source types aceitos em um bloco document

+

Fonte: pdf-support + files (ambos verificados em 2026-05-23).

+
+ + + + + + + + + +
source.typeCamposNota
base64media_type: "application/pdf", dataArquivos locais
urlurl (HTTPS apontando para o PDF)Fetch server-side
filefile_id (Files API), exige beta files-api-2025-04-14Reusável, payload pequeno
textUNVERIFIED (2026-05-23) — referenciado em typings antigos como modo de passar texto puro como document. Hoje o padrão é inline em bloco text ou upload via Files API.—
contentUNVERIFIED (2026-05-23) — source "custom content" para passar blocos pré-extraídos com hooks de citação. Confirme no guia de citations antes de usar em produção.—
+
+ +

Limites atuais (2026-05-23)

+
+ + + + + + + + + +
RequisitoLimite
Tamanho máximo do request32 MB (varia por plataforma — Bedrock/Vertex podem ser menores)
Páginas por request600 (ou 100 em modelos com janela de 200k tokens)
FormatoPDF padrão, sem senha/encriptação
Files API — máximo por arquivo500 MB
Files API — storage por organização500 GB
+
+
+ Os limites de páginas e de tamanho de request aplicam-se ao payload inteiro, incluindo outros conteúdos. PDFs densos (fontes pequenas, tabelas complexas, gráficos pesados) podem encher o context window antes de atingir o teto de páginas, mesmo via Files API. Particione, reduza imagens ou use prompt caching. +
+ +

Beta header status

+

+ Suporte a PDF é GA na API e não exige cabeçalho beta por si só. Você só precisa do files-api-2025-04-14 se subir o PDF pela Files API e referenciar por file_id. +

+ +

Citations

+

+ Passe citations: { enabled: true } em um bloco document para que o modelo retorne spans citados de páginas/segmentos. Obrigatório se você quer entendimento visual completo de PDF via Bedrock Converse — sem citations habilitado, o Converse silenciosamente faz fallback para extração text-only. +

+
{
+  "type": "document",
+  "source": { "type": "url", "url": "https://example.com/report.pdf" },
+  "title": "Q1 Report",
+  "context": "Financial filing for review",
+  "citations": { "enabled": true }
+}
+ +

Tokenização interna

+

Cada página é processada como texto E como imagem:

+
    +
  • Custo de texto: tipicamente 1.500–3.000 tokens por página, dependendo da densidade. Tarifa padrão de input — sem sobretaxa.
  • +
  • Custo de imagem: cada página é renderizada como imagem e cobrada pela fórmula padrão de image tokens.
  • +
+ +

Exemplos — Python e TypeScript

+

URL, base64 (com cache) e Files API com citations

+
+
+ + +
+
+
import anthropic, base64, httpx
+
+client = anthropic.Anthropic()
+
+# Option 1: URL
+msg = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {
+                "type": "url",
+                "url": "https://assets.anthropic.com/m/1cd9d098ac3e6467/original/Claude-3-Model-Card-October-Addendum.pdf",
+            }},
+            {"type": "text", "text": "What are the key findings?"},
+        ],
+    }],
+)
+
+# Option 2: Base64 + prompt cache
+with open("report.pdf", "rb") as f:
+    pdf_b64 = base64.standard_b64encode(f.read()).decode("utf-8")
+
+msg = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {
+                "type": "base64",
+                "media_type": "application/pdf",
+                "data": pdf_b64,
+            }, "cache_control": {"type": "ephemeral"}},
+            {"type": "text", "text": "Summarize chapter 3."},
+        ],
+    }],
+)
+
+# Option 3: Files API + citations
+with open("report.pdf", "rb") as f:
+    up = client.beta.files.upload(file=("report.pdf", f, "application/pdf"))
+
+msg = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    betas=["files-api-2025-04-14"],
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {"type": "file", "file_id": up.id},
+             "citations": {"enabled": True}, "title": "Q1 report"},
+            {"type": "text", "text": "List every cited figure."},
+        ],
+    }],
+)
+
+
+
import Anthropic, { toFile } from "@anthropic-ai/sdk";
+import fs from "fs";
+const client = new Anthropic();
+
+// URL
+await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "document",
+        source: { type: "url", url: "https://example.com/report.pdf" } },
+      { type: "text", text: "Key findings?" },
+    ],
+  }],
+});
+
+// Files API + citations
+const up = await client.beta.files.upload({
+  file: await toFile(fs.createReadStream("report.pdf"), undefined,
+                     { type: "application/pdf" }),
+});
+
+await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  betas: ["files-api-2025-04-14"],
+  messages: [{
+    role: "user",
+    content: [
+      { type: "document",
+        source: { type: "file", file_id: up.id },
+        citations: { enabled: true } },
+      { type: "text", text: "Cite the section on safety evals." },
+    ],
+  }],
+});
+
+
+ +

Best practices para PDF

+
    +
  • Coloque PDFs antes do texto no array content.
  • +
  • Use fontes padrão; rotacione páginas para cima; garanta legibilidade.
  • +
  • Use números de página do PDF viewer nos prompts ("na página 12, …").
  • +
  • Particione PDFs muito grandes em seções.
  • +
  • Habilite prompt caching com cache_control: { type: "ephemeral" } no bloco document para queries repetidas.
  • +
  • Em jobs em batch, use client.messages.batches.create({...}) — mesmos blocos, 50% de desconto, SLA 24h.
  • +
+ +

7.4 Office / Excel / CSV

+

+ A Messages API tem três caminhos diretos para documentos não-PDF: +

+
    +
  1. Inline como texto (bloco text) — recomendado para CSV/TXT/MD pequenos.
  2. +
  3. Upload como documento Files API (source.type=file) — para PDF e text/plain.
  4. +
  5. Mount no sandbox via container_upload — para XLSX, DOCX, PPTX, CSVs grandes.
  6. +
+ +

1. Inline como bloco text (CSV/TXT/MD)

+

Caminho mais barato e rápido para documentos estruturados pequenos. Não preserva formatos binários (XLSX, DOCX, PPTX) — esses exigem pré-extração ou Code Execution.

+
+
+ + +
+
+
import csv, anthropic
+client = anthropic.Anthropic()
+
+with open("sales.csv", newline="", encoding="utf-8") as f:
+    rows = list(csv.reader(f))
+csv_dump = "\n".join(",".join(r) for r in rows[:200])  # cap context
+
+msg = client.messages.create(
+    model="claude-sonnet-4-6",
+    max_tokens=2048,
+    messages=[{
+        "role": "user",
+        "content": [{
+            "type": "text",
+            "text": f"Here is the first 200 rows of a sales CSV.\n\n```csv\n{csv_dump}\n```\n\nWhat are the top 5 SKUs by revenue?",
+        }],
+    }],
+)
+print(msg.content[0].text)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+import { readFileSync } from "fs";
+
+const client = new Anthropic();
+const csv = readFileSync("sales.csv", "utf-8")
+  .split("\n").slice(0, 200).join("\n");
+
+const r = await client.messages.create({
+  model: "claude-sonnet-4-6",
+  max_tokens: 2048,
+  messages: [{
+    role: "user",
+    content: [{
+      type: "text",
+      text: `Here is the first 200 rows of a sales CSV.\n\n\`\`\`csv\n${csv}\n\`\`\`\n\nWhat are the top 5 SKUs by revenue?`,
+    }],
+  }],
+});
+
+
+ +

2. Upload como Files API document

+

A Files API trata dois MIME types como blocos document:

+
+ + + + + + +
MIMEBlocoUso
application/pdfdocumentAnálise visual + textual do PDF
text/plaindocumentAnálise textual sem inlining
+
+
+ Para DOCX com imagens, a doc recomenda converter para PDF primeiro e usar o caminho de PDF — assim você mantém parsing de imagens e suporte a citations. +
+ +

3. Mount no sandbox de Code Execution (container_upload) — XLSX/DOCX/PPTX/CSVs grandes

+

+ Suba o binário pela Files API e referencie em um bloco container_upload junto do tool code_execution_20250825 (ou _20260120). Claude pode então + import pandas as pd; pd.read_excel("/mnt/user-data/..."), rodar pivots, gerar gráficos e devolver outputs. As libs pré-instaladas — openpyxl, + xlrd, python-docx, python-pptx, pypdf, pdfplumber, tabula-py — cobrem todos os formatos Office canônicos. +

+ +

Exemplo mínimo — XLSX via Code Execution

+
+
+ + +
+
+
import anthropic
+client = anthropic.Anthropic()
+
+with open("Q1.xlsx", "rb") as f:
+    up = client.beta.files.upload(
+        file=("Q1.xlsx", f,
+              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
+
+resp = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=8192,
+    betas=["files-api-2025-04-14"],
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text",
+             "text": "Build a pivot of revenue by product family and export to CSV."},
+            {"type": "container_upload", "file_id": up.id},
+        ],
+    }],
+    tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
+)
+
+for block in resp.content:
+    if block.type == "text":
+        print(block.text)
+
+
+
import Anthropic, { toFile } from "@anthropic-ai/sdk";
+import { createReadStream } from "fs";
+
+const client = new Anthropic();
+
+const up = await client.beta.files.upload({
+  file: await toFile(createReadStream("Q1.xlsx"), undefined, {
+    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+  }),
+});
+
+const resp = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  betas: ["files-api-2025-04-14"],
+  max_tokens: 8192,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "text",
+        text: "Build a pivot of revenue by product family and export to CSV." },
+      { type: "container_upload", file_id: up.id },
+    ],
+  }],
+  tools: [{ type: "code_execution_20250825", name: "code_execution" }],
+});
+
+
+ +
+ DOCX → PDF caveat: para apresentar um DOCX rico em imagens ao modelo com visão, converta para PDF antes (LibreOffice, Pandoc, ou no próprio sandbox via python-docx → reportlab) e use o caminho de document. Para extração tabular simples, ler o DOCX no sandbox e gerar CSV é mais barato. +
+ +

7.5 Code Execution

+ +

O que é

+

+ Runtime Python + Bash server-side sandboxado que a Anthropic provisiona por workspace. Claude planeja, escreve, roda e itera código; + monta seus arquivos da Files API; produz gráficos, CSVs e ZIPs; e devolve novos file_ids que você baixa. A versão atual do tool expõe dois sub-tools que + Claude chama automaticamente: +

+
    +
  • bash_code_execution — comandos shell (instalar pacote, file ops, qualquer POSIX).
  • +
  • text_editor_code_execution — view, create, str_replace, insert em arquivos.
  • +
+ +

Versões do tool e cabeçalhos beta

+
+ + + + + + + + + + + + + + + + + + + + + + +
Tool typeCabeçalho betaCapacidadesDisponível em
code_execution_20260120code-execution-2026-01-20 UNVERIFIED (2026-05-23)Tudo de 20250825 + persistência de estado REPL dentro do turno e chamadas programáticas a tools de dentro do sandboxOpus 4.8, Sonnet 4.6
code_execution_20250825code-execution-2025-08-25Bash + file ops + PythonTodos os modelos ativos (Opus 4.8, Sonnet 4.6, Haiku 4.5)
code_execution_20250522 (legacy)code-execution-2025-05-22Apenas Python; sem Bash, sem file opsMantido para back-compat; migre via guia "Upgrade to latest tool version"
+
+
+ Escolha a versão mais nova compatível com o modelo. Versões antigas não têm garantia de compatibilidade com modelos novos. +
+ +

Quickstart

+
+
+ + +
+
+
import anthropic
+client = anthropic.Anthropic()
+
+resp = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=4096,
+    messages=[{
+        "role": "user",
+        "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]",
+    }],
+    tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
+)
+print(resp)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+const client = new Anthropic();
+
+const resp = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 4096,
+  messages: [{
+    role: "user",
+    content: "Calculate the mean and standard deviation of [1,2,3,4,5,6,7,8,9,10]",
+  }],
+  tools: [{ type: "code_execution_20250825", name: "code_execution" }],
+});
+console.log(resp);
+
+
+ +

Runtime do sandbox

+
+ + + + + + + + + + + + + + + +
PropriedadeValor
Python3.11.12
OSLinux container
Arquiteturax86_64 (AMD64)
Memória5 GiB de RAM
Disco5 GiB de workspace
CPU1 vCPU
InternetDesabilitada (sem rede outbound)
IsolamentoSandbox completo, isolado do host e de outros containers
Acesso a arquivosApenas o diretório de workspace
Escopo do containerVinculado ao workspace da API key
Vida útil do container30 dias após criação
+
+ +

Bibliotecas Python pré-instaladas

+

Verbatim da doc (verificada em 2026-05-23):

+
    +
  • Data science: pandas, numpy, scipy, scikit-learn, statsmodels
  • +
  • Visualization: matplotlib, seaborn
  • +
  • File processing: pyarrow, openpyxl, xlsxwriter, xlrd, pillow, python-pptx, python-docx, pypdf, pdfplumber, pypdfium2, pdf2image, pdfkit, tabula-py, reportlab[pycairo], Img2pdf
  • +
  • Math & computing: sympy, mpmath
  • +
  • Utilities: tqdm, python-dateutil, pytz, joblib, unzip, unrar, 7zip, bc, rg (ripgrep), fd, sqlite
  • +
+
+ Qualquer outra lib pode ser instalada em runtime — mas somente se você fizer stage dos wheels antes: a rede outbound é bloqueada. Na prática, prefira o que já vem pré-instalado. +
+ +

File input — container_upload

+

Para montar um arquivo da Files API dentro do sandbox, envie um bloco container_upload referenciando o file_id, junto do tool code_execution_*:

+
+
+ + +
+
+
file_obj = client.beta.files.upload(file=open("data.csv", "rb"))
+
+resp = client.beta.messages.create(
+    model="claude-opus-4-8",
+    betas=["files-api-2025-04-14"],
+    max_tokens=4096,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text", "text": "Analyze this CSV data"},
+            {"type": "container_upload", "file_id": file_obj.id},
+        ],
+    }],
+    tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
+)
+
+
+
const up = await client.beta.files.upload({
+  file: await toFile(createReadStream("data.csv"), undefined, { type: "text/csv" }),
+});
+
+const resp = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  betas: ["files-api-2025-04-14"],
+  max_tokens: 4096,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "text", text: "Analyze this CSV data" },
+      { type: "container_upload", file_id: up.id },
+    ],
+  }],
+  tools: [{ type: "code_execution_20250825", name: "code_execution" }],
+});
+
+
+

Dentro do sandbox o arquivo aparece no workspace; o primeiro movimento típico de Claude é um bash_code_execution com ls para descobrir o path, depois pd.read_csv(...).

+ +

Output handling — baixando arquivos que Claude criou

+

Arquivos que Claude escreve são expostos como file_ids aninhados em bash_code_execution_tool_result.content.content[]:

+
+
+ + +
+
+
def extract_file_ids(response):
+    ids = []
+    for item in response.content:
+        if item.type == "bash_code_execution_tool_result":
+            ci = item.content
+            if ci.type == "bash_code_execution_result":
+                for f in ci.content:
+                    ids.append(f.file_id)
+    return ids
+
+for fid in extract_file_ids(resp):
+    meta = client.beta.files.retrieve_metadata(fid)
+    content = client.beta.files.download(fid)
+    content.write_to_file(meta.filename)
+    print("Downloaded", meta.filename)
+
+
+
import { writeFile } from "fs/promises";
+
+for (const item of response.content) {
+  if (item.type === "bash_code_execution_tool_result") {
+    const ci = item.content;
+    if (ci.type === "bash_code_execution_result" && ci.content) {
+      for (const f of ci.content) {
+        const meta = await client.beta.files.retrieveMetadata(f.file_id);
+        const bytes = Buffer.from(
+          await (await client.beta.files.download(f.file_id)).arrayBuffer()
+        );
+        await writeFile(meta.filename, bytes);
+        console.log(`Downloaded ${meta.filename}`);
+      }
+    }
+  }
+}
+
+
+ +

Reuso do container (estado entre chamadas)

+

Passe container=<id> na próxima request para reusar o mesmo sandbox e preservar /tmp e wheels instalados por até 30 dias:

+
container_id = resp.container.id
+
+resp2 = client.messages.create(
+    container=container_id,
+    model="claude-opus-4-8",
+    max_tokens=4096,
+    messages=[{"role": "user",
+               "content": "Read /tmp/number.txt and compute its square."}],
+    tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
+)
+ +

Eventos de streaming

+

Em streaming, você recebe eventos incrementais content_block_* para cada chamada de tool:

+
content_block_start  → { type: "server_tool_use", name: "code_execution", ... }
+content_block_delta  → input_json_delta com o payload Python/bash
+(pausa enquanto o sandbox roda)
+content_block_start  → { type: "code_execution_tool_result",
+                         content: { stdout, stderr } }
+ +

Erros

+

Cada tool pode retornar códigos específicos dentro de *_tool_result_error:

+
+ + + + + + + + + + + + +
ToolCódigoSignificado
AllunavailableTool temporariamente fora
Allexecution_time_exceededExcedeu o tempo limite por chamada
Allcontainer_expiredContainer com mais de 30 dias
Allinvalid_tool_inputInput inválido pelo schema
Alltoo_many_requestsRate-limited
bashoutput_file_too_largestdout/stderr muito grande
text_editorfile_not_foundArquivo ausente em view/edit
text_editorstring_not_foundold_str ausente no arquivo (em str_replace)
+
+

A resposta pode incluir stop_reason="pause_turn" para turnos longos — devolva a resposta inalterada para continuar.

+ +

Exemplo — gráfico a partir de CSV

+
+
+ + +
+
+
import anthropic
+client = anthropic.Anthropic()
+
+up = client.beta.files.upload(file=open("sales.csv", "rb"))
+
+resp = client.beta.messages.create(
+    model="claude-opus-4-8",
+    betas=["files-api-2025-04-14"],
+    max_tokens=8192,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text",
+             "text": "Plot monthly revenue as a line chart and save as output.png. Then summarize the trend."},
+            {"type": "container_upload", "file_id": up.id},
+        ],
+    }],
+    tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
+)
+
+# Download output.png back
+for item in resp.content:
+    if item.type == "bash_code_execution_tool_result":
+        ci = item.content
+        if ci.type == "bash_code_execution_result":
+            for f in ci.content:
+                meta = client.beta.files.retrieve_metadata(f.file_id)
+                client.beta.files.download(f.file_id).write_to_file(meta.filename)
+
+
+
import Anthropic, { toFile } from "@anthropic-ai/sdk";
+import { createReadStream, promises as fsp } from "fs";
+
+const client = new Anthropic();
+const up = await client.beta.files.upload({
+  file: await toFile(createReadStream("sales.csv"), undefined, { type: "text/csv" }),
+});
+
+const resp = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  betas: ["files-api-2025-04-14"],
+  max_tokens: 8192,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "text",
+        text: "Plot monthly revenue as a line chart and save as output.png." },
+      { type: "container_upload", file_id: up.id },
+    ],
+  }],
+  tools: [{ type: "code_execution_20250825", name: "code_execution" }],
+});
+
+for (const item of resp.content) {
+  if (item.type === "bash_code_execution_tool_result") {
+    const ci = item.content;
+    if (ci.type === "bash_code_execution_result" && ci.content) {
+      for (const f of ci.content) {
+        const meta = await client.beta.files.retrieveMetadata(f.file_id);
+        const bytes = Buffer.from(
+          await (await client.beta.files.download(f.file_id)).arrayBuffer()
+        );
+        await fsp.writeFile(meta.filename, bytes);
+      }
+    }
+  }
+}
+
+
+ +

Exemplo — pivot a partir de XLSX (TypeScript)

+
import Anthropic, { toFile } from "@anthropic-ai/sdk";
+import { createReadStream, promises as fsp } from "fs";
+
+const client = new Anthropic();
+
+const up = await client.beta.files.upload({
+  file: await toFile(createReadStream("Q1.xlsx"), undefined, {
+    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+  }),
+});
+
+const resp = await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  betas: ["files-api-2025-04-14"],
+  max_tokens: 8192,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "text",
+        text: "Build a pivot of total revenue by product_family x quarter. Output CSV." },
+      { type: "container_upload", file_id: up.id },
+    ],
+  }],
+  tools: [{ type: "code_execution_20250825", name: "code_execution" }],
+});
+
+for (const item of resp.content) {
+  if (item.type === "bash_code_execution_tool_result") {
+    const ci = item.content;
+    if (ci.type === "bash_code_execution_result" && ci.content) {
+      for (const f of ci.content) {
+        const meta = await client.beta.files.retrieveMetadata(f.file_id);
+        const bytes = Buffer.from(
+          await (await client.beta.files.download(f.file_id)).arrayBuffer()
+        );
+        await fsp.writeFile(meta.filename, bytes);
+      }
+    }
+  }
+}
+ +

Pricing do Code Execution

+
    +
  • Free quando usado junto de web_search_20260209 ou web_fetch_20260209 — sem custo por execução, apenas tokens normais.
  • +
  • Sem essas tools: cobrado por tempo de execução por container, mínimo de 5 minutos por sessão.
  • +
  • 1.550 horas grátis por organização por mês.
  • +
  • Acima da cota: $0.05 por hora, por container.
  • +
  • Se há blocos container_upload, o tempo é cobrado mesmo que Claude nunca invoque o tool, porque os arquivos são pré-carregados.
  • +
  • Uso aparece em response.usage.server_tool_use.code_execution_requests.
  • +
  • Batches API: mesmo preço de code execution que o sync API.
  • +
  • ZDR: Code Execution não é elegível para ZDR. Dados do container (uploads e outputs) são retidos por até 30 dias.
  • +
+ +

7.6 Vídeo

+ +

Estado atual (2026-05-23)

+

+ Claude não ingere vídeo nativamente na Messages API. Não existe content block video na spec pública. A documentação multimodal oficial cobre apenas visão (imagens) e PDF. + UNVERIFIED (2026-05-23) — nenhuma oferta beta de vídeo foi encontrada em platform.claude.com na data da pesquisa. +

+ +

Workaround recomendado — frame extraction

+

+ Sub-amostre o vídeo em frames estáticos (tipicamente 0.5–2 FPS dependendo do movimento) e envie como sequência de blocos image. Com Opus 4.8 cabem até 600 imagens por request + (modelos de 200k: 100), o que cobre alguns minutos de footage em uma chamada se os frames forem modestos. +

+
+
+ + +
+
+
# ffmpeg -i input.mp4 -vf fps=1 frames/frame_%04d.jpg
+import os, base64, glob, anthropic
+client = anthropic.Anthropic()
+
+frames = sorted(glob.glob("frames/frame_*.jpg"))[:60]  # 60 frames
+
+content = [{"type": "text",
+            "text": "These are frames at 1 FPS from a short clip. Summarize what happens."}]
+for i, path in enumerate(frames, 1):
+    with open(path, "rb") as f:
+        b64 = base64.standard_b64encode(f.read()).decode()
+    content.append({"type": "text", "text": f"Frame {i}:"})
+    content.append({"type": "image", "source": {
+        "type": "base64", "media_type": "image/jpeg", "data": b64,
+    }})
+
+msg = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=2048,
+    messages=[{"role": "user", "content": content}],
+)
+print(msg.content[0].text)
+
+
+
// ffmpeg -i input.mp4 -vf fps=1 frames/frame_%04d.jpg
+import Anthropic from "@anthropic-ai/sdk";
+import { readFileSync, readdirSync } from "fs";
+
+const client = new Anthropic();
+const frames = readdirSync("frames").filter(f => f.endsWith(".jpg")).sort().slice(0, 60);
+
+const content: any[] = [{
+  type: "text",
+  text: "These are frames at 1 FPS from a short clip. Summarize what happens.",
+}];
+frames.forEach((p, i) => {
+  const data = readFileSync(`frames/${p}`).toString("base64");
+  content.push({ type: "text", text: `Frame ${i + 1}:` });
+  content.push({
+    type: "image",
+    source: { type: "base64", media_type: "image/jpeg", data },
+  });
+});
+
+const msg = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 2048,
+  messages: [{ role: "user", content }],
+});
+
+
+
+ Para vídeos mais longos, faça upload dos frames uma vez via Files API e referencie por file_id para manter requests pequenos enquanto itera. +
+ +

Trilha de áudio do vídeo

+

+ Se você também precisa do conteúdo falado, transcreva o áudio externamente (Whisper, Gemini gemini-3.5-flash, Deepgram etc.) e prepende o transcript + como bloco text antes dos frames. +

+ +

7.7 Áudio

+ +

Estado atual (2026-05-23)

+

+ A Messages API não tem bloco de conteúdo de áudio nativo. UNVERIFIED (2026-05-23) — nenhuma oferta beta pública de ingestão de áudio foi encontrada em platform.claude.com na data da pesquisa. +

+ +

Padrão recomendado — pré-transcrever

+
    +
  1. Transcreva externamente: +
      +
    • OpenAI gpt-4o-transcribe / gpt-4o-mini-transcribe via Responses API.
    • +
    • Google Gemini gemini-3.5-flash (áudio nativo in/out).
    • +
    • Whisper self-hosted.
    • +
    +
  2. +
  3. Envie o transcript como bloco text, opcionalmente com speaker labels e timestamps.
  4. +
+
+
+ + +
+
+
import anthropic
+client = anthropic.Anthropic()
+
+transcript = """[00:00:01] Speaker A: Welcome to the call.
+[00:00:04] Speaker B: Thanks. Quick update on the migration...
+..."""
+
+msg = client.messages.create(
+    model="claude-sonnet-4-6",
+    max_tokens=2048,
+    messages=[{
+        "role": "user",
+        "content": [{
+            "type": "text",
+            "text": f"Here is a meeting transcript:\n\n{transcript}\n\n"
+                    f"Produce action items with owners and due dates.",
+        }],
+    }],
+)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+const client = new Anthropic();
+
+const transcript = `[00:00:01] Speaker A: Welcome to the call.
+[00:00:04] Speaker B: Thanks. Quick update on the migration...`;
+
+const msg = await client.messages.create({
+  model: "claude-sonnet-4-6",
+  max_tokens: 2048,
+  messages: [{
+    role: "user",
+    content: [{
+      type: "text",
+      text: `Here is a meeting transcript:\n\n${transcript}\n\nProduce action items with owners and due dates.`,
+    }],
+  }],
+});
+
+
+
+ Se você também precisa de diarização ou análise de áudio não-fala (música, ambiência), Claude não ajuda diretamente — pré-processe com um modelo de áudio especializado e injete os achados estruturados como bloco text. +
+ +

7.8 Files API

+ +

Beta header

+
anthropic-beta: files-api-2025-04-14
+

+ Obrigatório em todo endpoint da Files API e em toda request Messages que referencie um file_id (image source type=file, document source type=file ou container_upload). +

+ +

Endpoints

+
+ + + + + + + + + +
MétodoPathPropósito
POST/v1/filesUpload (multipart file=@...)
GET/v1/filesList files do workspace
GET/v1/files/{file_id}Metadados
GET/v1/files/{file_id}/contentDownload dos bytes — só funciona para arquivos criados por skills ou Code Execution; arquivos enviados pelo usuário não podem ser baixados
DELETE/v1/files/{file_id}Delete
+
+ +

Response shape (upload)

+
{
+  "id": "file_011CNha8iCJcU1wXNR6q4V8w",
+  "type": "file",
+  "filename": "document.pdf",
+  "mime_type": "application/pdf",
+  "size_bytes": 1024000,
+  "created_at": "2025-01-01T00:00:00Z",
+  "downloadable": false
+}
+

downloadable: true aparece apenas em arquivos que Claude produziu via skills ou Code Execution.

+ +

Limites

+
+ + + + + + + + + + + +
LimiteValor
Tamanho máximo por arquivo500 MB
Storage total500 GB por organização
Tamanho do filename1–255 caracteres; sem < > : " | ? * \ / nem unicode 0–31
Rate limit (beta)~100 requests / minuto
LifecyclePersistem até serem deletados
EscopoWorkspace — visível para qualquer API key do mesmo workspace
ZDR elegívelNão para a Files API em si (separado do PDF support, que é ZDR-elegível)
+
+ +

Mapeamento file type → content block

+
+ + + + + + + + +
TipoMIMEContent block
PDFapplication/pdfdocument
Texto purotext/plaindocument
Imagensimage/jpeg, image/png, image/gif, image/webpimage
Datasets, Office docs, código, outros bináriosQualquer coisa suportada pelo sandboxcontainer_upload
+
+ +

Error map

+
+ + + + + + + + +
HTTPMotivo
400Block type errado para o MIME, filename inválido, ou documento excede o context window
403Cota de storage do workspace excedida
404file_id não encontrado / inacessível
413Arquivo excede o limite de 500 MB
+
+ +

Exemplos — Python, TypeScript e cURL

+

Upload + referência + cleanup

+
+
+ + +
+
+
import anthropic
+client = anthropic.Anthropic()
+
+up = client.beta.files.upload(
+    file=("report.pdf", open("report.pdf", "rb"), "application/pdf"),
+)
+print(up.id, up.mime_type, up.size_bytes)
+
+# List
+print([f.id for f in client.beta.files.list().data])
+
+# Use in a message
+msg = client.beta.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=512,
+    betas=["files-api-2025-04-14"],
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {"type": "file", "file_id": up.id}},
+            {"type": "text", "text": "Title and TL;DR?"},
+        ],
+    }],
+)
+
+# Metadata
+print(client.beta.files.retrieve_metadata(up.id).filename)
+
+# Delete
+client.beta.files.delete(up.id)
+
+
+
import Anthropic, { toFile } from "@anthropic-ai/sdk";
+import fs from "fs";
+const client = new Anthropic();
+
+const up = await client.beta.files.upload({
+  file: await toFile(fs.createReadStream("report.pdf"), undefined,
+                     { type: "application/pdf" }),
+});
+
+await client.beta.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 512,
+  betas: ["files-api-2025-04-14"],
+  messages: [{
+    role: "user",
+    content: [
+      { type: "document", source: { type: "file", file_id: up.id } },
+      { type: "text", text: "Title and TL;DR?" },
+    ],
+  }],
+});
+
+await client.beta.files.delete(up.id);
+
+
+ +

cURL

+
# Upload
+curl -X POST https://api.anthropic.com/v1/files \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: files-api-2025-04-14" \
+  -F "file=@report.pdf"
+
+# List
+curl https://api.anthropic.com/v1/files \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: files-api-2025-04-14"
+
+# Metadata
+curl https://api.anthropic.com/v1/files/$FILE_ID \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: files-api-2025-04-14"
+
+# Download (apenas para arquivos criados por Claude)
+curl https://api.anthropic.com/v1/files/$FILE_ID/content \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: files-api-2025-04-14" \
+  --output out.bin
+
+# Delete
+curl -X DELETE https://api.anthropic.com/v1/files/$FILE_ID \
+  -H "x-api-key: $ANTHROPIC_API_KEY" \
+  -H "anthropic-version: 2023-06-01" \
+  -H "anthropic-beta: files-api-2025-04-14"
+ +

Billing

+
    +
  • Todas as operações da Files API (upload/download/list/metadata/delete) são gratuitas.
  • +
  • O conteúdo de arquivo usado em messages.create é cobrado pelas tarifas padrão de input por modalidade (image tokens para imagens, image+text tokens para PDF, text tokens para text/plain).
  • +
+ +

7.9 Prompt caching com imagens / PDFs

+

+ O prompt caching da Anthropic permite marcar conteúdo de prefixo caro (system prompt, imagens grandes, PDFs grandes) com cache_control para que requests + subsequentes que baterem no mesmo prefixo paguem uma tarifa reduzida de cache-read. +

+ +

Uso

+

+ Anexe cache_control: { type: "ephemeral", ttl: "5m" | "1h" } em um bloco image, document, text, definição de tool, ou tool result. + Ordem importa — a Anthropic cacheia prefixos, então coloque conteúdo estável (system → tools → docs grandes → imagens) antes do turno dinâmico do usuário. +

+
+
+ + +
+
+
msg = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document",
+             "source": {"type": "base64", "media_type": "application/pdf", "data": pdf_b64},
+             "cache_control": {"type": "ephemeral", "ttl": "1h"}},
+            {"type": "text", "text": "Which model has the highest win rate?"},
+        ],
+    }],
+)
+# Inspect: msg.usage.cache_creation_input_tokens / cache_read_input_tokens
+
+
+
const msg = await client.messages.create({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{
+    role: "user",
+    content: [
+      { type: "document",
+        source: { type: "base64", media_type: "application/pdf", data: pdf_b64 },
+        cache_control: { type: "ephemeral", ttl: "1h" } },
+      { type: "text", text: "Which model has the highest win rate?" },
+    ],
+  }],
+});
+// msg.usage.cache_creation_input_tokens / cache_read_input_tokens
+
+
+ +

Constraints

+
    +
  • Até 4 breakpoints cache_control por request.
  • +
  • TTL: "5m" (default) ou "1h".
  • +
  • Cache é chaveado por prefixo: qualquer mudança mais cedo no prefixo invalida tudo o que vem depois.
  • +
  • Tamanho mínimo cacheável (corrigido 2026-05-23): diverge por modelo. Opus 4.8 / Haiku 4.5 = 4.096 tokens; Sonnet 4.6 = 1.024 tokens. Sem isto, o cache não é criado e você paga input cheio.
  • +
  • Pricing multiplicadores (verificados 2026-05-23): write 5m = 1,25× base input; write 1h = 2× base input; read = 0,1× base input. Em Opus 4.8 ($5/MTok): cache read = $0,50/MTok.
  • +
  • Image caching: bytes da imagem + representação tokenizada são cacheados — Opus 4.8 com hi-res é quem mais ganha.
  • +
  • PDF caching: cada página é cacheada como image + text tokens — economia escala linearmente com o doc.
  • +
+ +

Quando compensa

+
    +
  • Mesmo PDF, muitas perguntas (Q&A estilo analista).
  • +
  • Mesmo screenshot, muitos prompts diagnósticos.
  • +
  • Documento de referência grande sendo chunked em muitos turnos.
  • +
  • Loops de tool use repetidos onde o schema do tool é grande.
  • +
+ +

7.10 Parâmetros completos

+ +

Bloco image

+
+ + + + + + + + + + + +
CampoTipoObrigatórioNotas
typeconst "image"sim—
source.type"base64" | "url" | "file"simfile exige Files API beta
source.media_typestringsim p/ base64image/jpeg, image/png, image/gif, image/webp
source.datastringsim p/ base64Bytes em base64 (sem prefixo data URL)
source.urlstringsim p/ urlHTTPS
source.file_idstringsim p/ fileVindo da Files API
cache_controlobjectnão{ type: "ephemeral", ttl: "5m" | "1h" }
+
+ +

Bloco document

+
+ + + + + + + + + + + + + + +
CampoTipoObrigatórioNotas
typeconst "document"sim—
source.type"base64" | "url" | "file" | "text" | "content"simtext = PlainTextSource, content = ContentBlockSource — agora formalmente documentados (verificado 2026-05-23). Usados principalmente no fluxo de citations.
source.media_typestringsim p/ base64application/pdf, text/plain
source.datastringsim p/ base64Bytes em base64
source.urlstringsim p/ urlHTTPS apontando para o PDF
source.file_idstringsim p/ fileVindo da Files API
titlestringnãoRótulo, usado em citations
contextstringnãoContexto livre concatenado ao doc
citations.enabledbooleannãoLiga citations inline em spans do doc
cache_controlobjectnãoIgual ao de imagem
+
+ +

Bloco container_upload

+
+ + + + + + + +
CampoTipoObrigatórioNotas
typeconst "container_upload"sim—
file_idstringsimVindo da Files API
cache_controlobjectnãoCaching raro nesse bloco
+
+ +

Definição do Code Execution tool

+
{
+  "type": "code_execution_20250825",
+  "name": "code_execution"
+}
+

Para os modelos atuais (Opus 4.8, Sonnet 4.6):

+
{
+  "type": "code_execution_20260120",
+  "name": "code_execution"
+}
+

O tool em si não exige parâmetros; o comportamento é governado pelo modelo e pelo prompt.

+ +

Parâmetros top-level da Messages API (relevantes para multimodal)

+
+ + + + + + + + + + + + + +
CampoTipoNotas
modelstringVer tabela de modelos
messagesarrayTurnos alternados user/assistant
max_tokensintObrigatório
systemstring | arraySystem prompt (top-level, fora de messages)
toolsarrayInclua code_execution_*, web search, etc.
betasarray<string>["files-api-2025-04-14"], ["code-execution-2025-08-25"]
containerstringReuso de sandbox pelo container ID
thinkingobject{ type: "adaptive" | "enabled" | "disabled", budget_tokens?: N } — Opus 4.8 é adaptive only
output_config.formatobjectStructured output nativo via JSON schema
+
+ +

7.11 Limitações & gotchas

+ +

Visão

+
    +
  • Sem identificação de pessoas, sem conteúdo que viola AUP, sem diagnóstico CT/MRI.
  • +
  • Artefatos de compressão lossy podem quebrar OCR — verifique seu downscaler.
  • +
  • Coordenadas retornadas pelo modelo referem-se à imagem pós-resize e pós-pad. Reescale antes de desenhar no original.
  • +
  • Imagens via base64/URL são efêmeras; descartadas após a response. Para "lembrar" entre turnos, use Files API com o mesmo file_id.
  • +
  • Animações: apenas o primeiro frame de GIF/WebP.
  • +
+ +

PDF

+
    +
  • Sem PDFs com senha/encriptados.
  • +
  • Teto de 600 páginas em modelos 1M ctx, 100 em 200k ctx — mas request size (32 MB) e context window podem bater antes.
  • +
  • Cada página é texto + imagem; PDFs de 100 páginas podem consumir 200k+ tokens facilmente.
  • +
  • Análise visual via Amazon Bedrock Converse exige citations.enabled=true, ou você perde silenciosamente entendimento de gráficos/diagramas.
  • +
+ +

Code Execution

+
    +
  • Sem rede outbound. Qualquer pip install ou urllib.request.urlopen falha. Pré-instaladas cobrem a maior parte; para o resto, stage wheels via container_upload.
  • +
  • Container expira em 30 dias; container_id serve para workflows curtos, não storage durável.
  • +
  • Sessões concorrentes são cobradas por container — 10 containers paralelos × 10 min = 10 × min(5 min, real).
  • +
  • Bash output_file_too_large trip em stdout multi-MB (ex.: imprimir DataFrames inteiros). Pipe para arquivo e baixe.
  • +
  • Code Execution não é ZDR-elegível.
  • +
+ +

Files API

+
    +
  • 500 MB por arquivo, 500 GB por org. No teto de org os uploads retornam 403.
  • +
  • Rate limit beta ~100 RPM. Não é bus de ingestão high-volume.
  • +
  • Arquivos enviados não podem ser baixados. Apenas arquivos que Claude produziu (skills ou Code Execution) têm downloadable: true.
  • +
  • Arquivos persistem até serem deletados — limpe periodicamente ou veja o storage encher.
  • +
  • Escopo de workspace: qualquer API key do mesmo workspace pode usar/deletar qualquer arquivo. Trate como compartilhado.
  • +
+ +

Geral

+
    +
  • Blocos multimodais contam para o mesmo limite de 32 MB por request; muitas imagens grandes → Files API.
  • +
  • Blocos image e document só existem dentro de mensagens com role: "user".
  • +
  • O chain-of-thought do modelo (quando thinking está habilitado) não faz streaming da imagem. Não espere "ver" Claude olhando a imagem passo-a-passo em adaptive thinking.
  • +
  • Bedrock e Vertex AI são subsets limitados — sources somente base64, sem Code Execution, Bedrock Converse exige citations para PDF visual.
  • +
+ +

7.12 Pricing & token accounting

+

Referência (maio/2026, de models/overview e da doc de code-execution):

+
+ + + + + + + + + + + + + + + + +
SuperfícieCusto
Opus 4.8$5 / 1M input · $25 / 1M output
Sonnet 4.6$3 / 1M input · $15 / 1M output
Haiku 4.5$1 / 1M input · $5 / 1M output
Image tokens≈ (W × H) / 750 por imagem, cobrados como input
PDF — texto~1.500–3.000 tokens / página de input
PDF — imagensPela fórmula de image tokens, por página, input
Files API — opsGrátis (upload/list/metadata/download/delete)
Files API — conteúdo em requestTarifa padrão de input por modalidade
Code Execution (sem web search/fetch)$0.05/h/container após 1.550 h grátis/org/mês
Code Execution (com web search/fetch)Grátis além de tokens normais
Batches API50% off; mesmo preço multimodal
Prompt cachingCache-read em tarifa reduzida — ver doc canônica do caching
+
+ +

Inspecionando uso

+
{
+  "input_tokens": 105,
+  "output_tokens": 239,
+  "cache_creation_input_tokens": 0,
+  "cache_read_input_tokens": 0,
+  "server_tool_use": { "code_execution_requests": 1 }
+}
+

+ Track de image tokens é melhor feito comparando input_tokens em A/B tests, ou usando o endpoint Token Counting (/v1/messages/count_tokens) para estimar custo + antes de bater em /v1/messages. +

+ +
+ UNVERIFIED consolidado (2026-05-23): (1) valor exato do header code-execution-2026-01-20 — inferido do padrão de versionamento; confirme com a release do SDK que você pina. + (2) document.source.type=="text" e "content" — referenciados em typings antigos, presentes no fluxo de citations, não exaustivamente documentados na página atual de PDF. + (3) Nenhuma oferta nativa de áudio ou vídeo encontrada em platform.claude.com em 2026-05-23 — frame-extraction + transcrição externa permanecem os workarounds suportados. + (4) Mínimo exato de tokens cacheáveis para blocos image/document (o skill prompt-caching mantém a matriz multi-provider atualizada). +
+
+ + +
+

8. Receitas práticas

+

+ Padrões reais resolvidos lado a lado nos três providers. Cada cartão traz o + problema, os trade-offs e snippets compactos por API. Os blocos extensos + ficam expansíveis em <details>; para o pipeline completo, + seguir o link para a seção deep-dive do provider. +

+ +
+ + +
+

R1 — Q&A em PDF longo com citações por trecho

+

Problema: usuário sobe um PDF de centenas de páginas e quer + respostas com o trecho exato citado. Apenas o Anthropic tem citation + primitive nativo; OpenAI usa File Search annotations; Gemini cita via prompt.

+ +
+ OpenAI File Search + Responses (annotations) +
from openai import OpenAI
+client = OpenAI()
+
+# 1) Criar vector store e anexar o PDF (50 MB+ via Files)
+vs = client.vector_stores.create(name="kb")
+up = client.files.create(file=open("manual.pdf","rb"), purpose="assistants")
+client.vector_stores.files.create(vector_store_id=vs.id, file_id=up.id)
+
+# 2) Perguntar com a tool file_search habilitada
+resp = client.responses.create(
+    model="gpt-5.5",
+    tools=[{"type":"file_search","vector_store_ids":[vs.id]}],
+    input="Quais cláusulas tratam de rescisão? Cite o trecho."
+)
+for item in resp.output:
+    for ann in getattr(item, "annotations", []) or []:
+        if ann.type == "file_citation":
+            print(ann.file_id, ann.quote)  # citação por trecho
+
+

+ Detalhe completo em §4.3 e §4.8. +

+
+ +
+ Gemini PDF nativo + prompt para citar +
from google import genai
+client = genai.Client()
+
+f = client.files.upload(file="manual.pdf")  # ≤50 MB, ≤1000 páginas
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=[
+        f,
+        "Quais cláusulas tratam de rescisão? "
+        "Responda citando o nº da página e o trecho literal entre aspas."
+    ],
+)
+print(resp.text)
+
+

+ Gemini lê layout e charts; nº da página vem do próprio modelo. Ver §5.3. +

+
+ +
+ Anthropic citations.enabled: true (nativo) +
import anthropic, base64
+client = anthropic.Anthropic()
+
+pdf_b64 = base64.standard_b64encode(open("manual.pdf","rb").read()).decode()
+msg = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role":"user","content":[
+        {"type":"document",
+         "source":{"type":"base64","media_type":"application/pdf","data":pdf_b64},
+         "citations":{"enabled":True}},
+        {"type":"text","text":"Quais cláusulas tratam de rescisão?"}
+    ]}],
+)
+for block in msg.content:
+    if block.type == "text":
+        for c in (block.citations or []):
+            print(c.cited_text, "→ pg", c.start_page_number)
+
+

+ Único com citações estruturadas no payload — ver §7.3. +

+
+
+ + +
+

R2 — Extrair tabela de uma imagem para CSV

+

Problema: screenshot de um relatório com tabela tabulada; + quer JSON ou CSV estruturado. OpenAI/Anthropic se saem bem com hi-res; + Gemini se beneficia de media_resolution: HIGH.

+ +
# OpenAI — Responses + structured outputs
+from openai import OpenAI
+client = OpenAI()
+resp = client.responses.create(
+    model="gpt-5.5",
+    input=[{"role":"user","content":[
+        {"type":"input_text","text":"Devolva CSV (cabeçalho na 1ª linha)."},
+        {"type":"input_image","image_url":"https://exemplo.com/tabela.png",
+         "detail":"original"}
+    ]}],
+)
+print(resp.output_text)
+
+ +
# Gemini — eleva resolução por parte
+from google import genai
+from google.genai import types
+client = genai.Client()
+img = client.files.upload(file="tabela.png")
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=[
+        types.Part.from_uri(file_uri=img.uri, mime_type="image/png",
+                            media_resolution="HIGH"),
+        "Extraia a tabela em CSV."
+    ],
+)
+print(resp.text)
+
+ +
# Anthropic — Claude lê imagens, devolve CSV puro
+import anthropic, base64
+b = base64.standard_b64encode(open("tabela.png","rb").read()).decode()
+msg = anthropic.Anthropic().messages.create(
+    model="claude-opus-4-8", max_tokens=2048,
+    messages=[{"role":"user","content":[
+        {"type":"image","source":{"type":"base64","media_type":"image/png","data":b}},
+        {"type":"text","text":"Devolva apenas o CSV, sem comentários."}
+    ]}])
+print(msg.content[0].text)
+
+

Detalhes de tokenização em §4.2, §5.2, §7.2.

+
+ + +
+

R3 — Análise estatística de XLSX (pivot + gráfico)

+

Problema: arquivo Excel com 50 mil linhas; quer pivot por + categoria e um gráfico salvo como PNG. Visão nativa em XLSX é fraca em + todos — a saída é code execution com pandas.

+ +
+ OpenAI Code Interpreter (memory_limit 4g) +
from openai import OpenAI
+client = OpenAI()
+up = client.files.create(file=open("vendas.xlsx","rb"), purpose="user_data")
+resp = client.responses.create(
+    model="gpt-5.5",
+    tools=[{"type":"code_interpreter",
+            "container":{"type":"auto","memory_limit":"4g","file_ids":[up.id]}}],
+    input="Faça pivot vendas por região e gere PNG do gráfico."
+)
+# baixar arquivos gerados via container_file_citation
+
+
+ +
+ Gemini code_execution tool +
from google import genai
+client = genai.Client()
+f = client.files.upload(file="vendas.xlsx")
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=[f, "Pivot por região + matplotlib PNG do total mensal."],
+    config={"tools":[{"code_execution":{}}]},
+)
+# parts com executableCode + codeExecutionResult + inlineData (PNG)
+
+
+ +
+ Anthropic container_upload + code execution +
import anthropic
+client = anthropic.Anthropic()
+up = client.beta.files.upload(file=("vendas.xlsx", open("vendas.xlsx","rb"),
+                                    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
+msg = client.beta.messages.create(
+    model="claude-opus-4-8", max_tokens=4096,
+    betas=["code-execution-2025-08-25","files-api-2025-04-14"],
+    tools=[{"type":"code_execution_20250825","name":"code_execution"}],
+    messages=[{"role":"user","content":[
+        {"type":"container_upload","file_id":up.id},
+        {"type":"text","text":"Pivot por região + PNG do gráfico."}
+    ]}],
+)
+
+
+

Spreadsheet patterns: §4.4, §5.4, §7.4.

+
+ + +
+

R4 — Resumo de vídeo de 30 min com timestamps

+

Problema: palestra MP4 de 30 minutos; quer bullets com + timestamps. Só Gemini tem ingestão de vídeo nativa — OpenAI e Anthropic + precisam de extração de frames + transcript.

+ +
+ Gemini Files API + 1 FPS (caminho recomendado) +
from google import genai
+client = genai.Client()
+v = client.files.upload(file="palestra.mp4")  # ≤2 GB
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=[
+        v,
+        "Resuma em bullets. Para cada ponto, mostre o timestamp [mm:ss]."
+    ],
+)
+print(resp.text)
+
+

Default 1 FPS · 258 tok/frame · clipping via video_metadata.start_offset.

+
+ +
+ OpenAI Frames @ 1 FPS + Whisper +
# 1) ffmpeg -i palestra.mp4 -vf fps=1 frames/%04d.jpg
+# 2) whisper -> transcript com timestamps
+from openai import OpenAI
+client = OpenAI()
+tx = client.audio.transcriptions.create(
+    model="gpt-4o-transcribe", file=open("palestra.mp3","rb"),
+    response_format="verbose_json", timestamp_granularities=["segment"])
+# 3) responses.create com input_image[] dos frames + tx.text
+
+

Frame-extraction pattern em §4.6.

+
+ +
+ Anthropic Frames + transcript externo +
# Mesmo pipeline: ffmpeg para frames, Whisper/Gemini para transcript.
+# Depois mandar pra Claude com blocos image[] intercalados.
+# Ver §7.6 para template completo.
+
+
+
+ + +
+

R5 — Transcrição de áudio + extração de action items

+

Problema: reunião de 1h gravada em .m4a; quer + transcript + lista de tarefas com responsável e prazo. Claude + não tem áudio nativo — pipeline híbrido.

+ +
# OpenAI puro — gpt-4o-transcribe + structured output
+from openai import OpenAI
+c = OpenAI()
+tx = c.audio.transcriptions.create(
+    model="gpt-4o-transcribe", file=open("reuniao.m4a","rb"))
+plan = c.responses.create(
+    model="gpt-5.5",
+    input=f"Transcript:\n{tx.text}\n\nLista action items (JSON: owner, task, due).",
+)
+print(plan.output_text)
+
+ +
# Gemini — áudio nativo (até 9.5h por request)
+from google import genai
+client = genai.Client()
+a = client.files.upload(file="reuniao.m4a")
+r = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=[a, "Transcreva + JSON com action items (owner, task, due)."],
+)
+print(r.text)
+
+ +
# Anthropic — usar Whisper/Gemini para transcript e mandar texto para Claude
+# (sem áudio nativo na Messages API em 2026-05-23)
+
+

Ver áudio: §4.7, §5.7, §7.7.

+
+ + +
+

R6 — OCR de documento manuscrito digitalizado

+

Problema: formulário preenchido a mão, scan em JPG. Manuscrito + é caso difícil; subir resolução ajuda muito mais do que prompt.

+ +
# OpenAI — gpt-5.5 + detail:"original"
+from openai import OpenAI
+c = OpenAI()
+r = c.responses.create(model="gpt-5.5",
+    input=[{"role":"user","content":[
+        {"type":"input_text","text":"Transcreva o manuscrito. Marque [?] para incerto."},
+        {"type":"input_image","image_url":"https://x/scan.jpg","detail":"original"},
+    ]}])
+
+ +
# Gemini — media_resolution ULTRA_HIGH (Gemini 3)
+from google import genai
+from google.genai import types
+client = genai.Client()
+img = client.files.upload(file="scan.jpg")
+r = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=[
+        types.Part.from_uri(file_uri=img.uri, mime_type="image/jpeg",
+                            media_resolution="ULTRA_HIGH"),
+        "Transcreva o manuscrito."
+    ])
+
+ +
# Anthropic — Opus 4.8 hi-res (até 2576 px lado maior)
+import anthropic, base64
+b = base64.standard_b64encode(open("scan.jpg","rb").read()).decode()
+m = anthropic.Anthropic().messages.create(model="claude-opus-4-8", max_tokens=2048,
+    messages=[{"role":"user","content":[
+        {"type":"image","source":{"type":"base64","media_type":"image/jpeg","data":b}},
+        {"type":"text","text":"Transcreva. [?] para incerto."}]}])
+
+

Limitações de OCR: §4.10, §5.11, §7.11.

+
+ + +
+

R7 — Comparar dois prints de UI (o que mudou?)

+

Problema: regressão visual ou QA — duas screenshots, + quer diff descrito. Mandar as duas imagens no mesmo turno.

+ +
# OpenAI
+from openai import OpenAI
+c = OpenAI()
+r = c.responses.create(model="gpt-5.5", input=[{"role":"user","content":[
+    {"type":"input_text","text":"Liste diferenças visuais entre A e B."},
+    {"type":"input_image","image_url":"https://x/a.png","detail":"high"},
+    {"type":"input_image","image_url":"https://x/b.png","detail":"high"}]}])
+
+ +
# Gemini
+from google import genai
+client = genai.Client()
+a = client.files.upload(file="a.png"); b = client.files.upload(file="b.png")
+r = client.models.generate_content(model="gemini-3.1-pro-preview",
+    contents=[a, b, "Diga as diferenças visuais entre A (1ª) e B (2ª)."])
+
+ +
# Anthropic — bloco image por imagem
+import anthropic, base64
+def img(p):
+    b = base64.standard_b64encode(open(p,"rb").read()).decode()
+    return {"type":"image","source":{"type":"base64","media_type":"image/png","data":b}}
+m = anthropic.Anthropic().messages.create(model="claude-opus-4-8", max_tokens=1024,
+    messages=[{"role":"user","content":[
+        img("a.png"), img("b.png"),
+        {"type":"text","text":"Liste diferenças visuais entre A e B."}]}])
+
+
+ + +
+

R8 — Geração de imagem a partir de briefing visual

+

Problema: tem um briefing textual e referência visual; quer + uma nova imagem coerente. Claude indisponível — + Claude só entende imagens. OpenAI vs Gemini se dividem em estilo e + licenciamento; ambos suportam edição com referência.

+ +
# OpenAI — gpt-image-2 via Responses tool ou Images API
+from openai import OpenAI
+c = OpenAI()
+r = c.responses.create(model="gpt-5.5",
+    tools=[{"type":"image_generation"}],
+    input="Capa: paisagem futurista, neon ciano, estilo da imagem de referência.",
+    # opcional: anexar input_image como referência
+)
+# r.output traz blocks image_generation.result com data URL ou file_id
+
+ +
# Gemini — gemini-3.1-flash-image (Nano Banana 2)
+from google import genai
+client = genai.Client()
+r = client.models.generate_content(
+    model="gemini-3.1-flash-image",
+    contents=["Capa: paisagem futurista, neon ciano."]
+)
+# r.candidates[0].content.parts inclui inlineData PNG
+
+ +
Anthropic Claude: não gera imagens. Use OpenAI ou Gemini e
+mande o resultado para Claude apenas para revisão/descrição.
+

Catálogo completo em §4.2 e §5.2.

+
+ + +
+

R9 — Cachear PDF grande para muitas perguntas

+

Problema: mesmo PDF de 200 páginas, 50 perguntas diferentes. + Cache reduz custo drasticamente — mas a API é diferente em cada provider.

+ +
# OpenAI — prompt caching automático em system+input estáveis
+# (basta repetir o mesmo prefix; cache hit é cobrado a 50% input)
+from openai import OpenAI
+c = OpenAI()
+up = c.files.create(file=open("manual.pdf","rb"), purpose="user_data")
+r = c.responses.create(model="gpt-5.5",
+    input=[{"role":"user","content":[
+        {"type":"input_file","file_id":up.id},
+        {"type":"input_text","text":"Q1: ..."}]}])
+# 2ª chamada com o mesmo file_id e mesmo system reusa o prefix.
+
+ +
# Gemini — explicit context caching (TTL configurável)
+from google import genai
+client = genai.Client()
+f = client.files.upload(file="manual.pdf")
+cache = client.caches.create(
+    model="gemini-3.1-pro-preview",
+    config={"contents":[f], "ttl":"3600s"})
+r = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=["Q1: ..."],
+    config={"cached_content": cache.name},
+)
+
+ +
# Anthropic — cache_control: ephemeral nos blocks pesados
+import anthropic, base64
+b = base64.standard_b64encode(open("manual.pdf","rb").read()).decode()
+client = anthropic.Anthropic()
+m = client.messages.create(model="claude-opus-4-8", max_tokens=512,
+    messages=[{"role":"user","content":[
+        {"type":"document",
+         "source":{"type":"base64","media_type":"application/pdf","data":b},
+         "cache_control":{"type":"ephemeral"}},
+        {"type":"text","text":"Q1: ..."}]}])
+
+

Caching: §3.10, §5.9, §7.9.

+
+ + +
+

R10 — Batch de 1000 documentos para classificação multimodal

+

Problema: 1.000 PDFs ou imagens para classificar com + categoria + confiança. Os três providers oferecem batch com desconto + (~50%); cada um tem formato e SLA distintos.

+ +
# OpenAI Batch API — JSONL, /v1/responses, output em 24h
+{"custom_id":"doc-001","method":"POST","url":"/v1/responses",
+ "body":{"model":"gpt-5.5","input":[{"role":"user","content":[
+   {"type":"input_file","file_id":"file-abc1"},
+   {"type":"input_text","text":"Classifique em [contrato, fatura, outro]."}]}]}}
+{"custom_id":"doc-002", ...}
+# client.batches.create(input_file_id=..., endpoint="/v1/responses",
+#                       completion_window="24h")
+
+ +
# Gemini Batch — google-genai batches endpoint, desconto 50%
+from google import genai
+client = genai.Client()
+batch = client.batches.create(
+    model="gemini-3.1-pro-preview",
+    src=[{"contents":[uploaded_pdf, "Classifique..."]} for uploaded_pdf in lst],
+    config={"display_name":"classify-docs"},
+)
+
+ +
# Anthropic Message Batches — até 100k req, 24h SLA, 50% off
+import anthropic
+client = anthropic.Anthropic()
+requests = [{"custom_id":f"doc-{i:04d}","params":{
+    "model":"claude-opus-4-8","max_tokens":256,
+    "messages":[{"role":"user","content":[
+        {"type":"document","source":{"type":"file","file_id":fid}},
+        {"type":"text","text":"Classifique em [contrato, fatura, outro]."}]}]}}
+    for i,fid in enumerate(file_ids)]
+batch = client.messages.batches.create(requests=requests)
+
+

Files API por provider: §4.8, §5.8, §7.8.

+
+ +
+
+ + + +
+

9. Catálogo de limitações cruzadas

+

+ Linhas em UNVERIFIED indicam item presente nos docs em + 2026-05-23 mas com valor exato ainda a re-confirmar nos verifiers. + Valores são da documentação oficial pública na data de corte. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CategoriaOpenAIGoogle GeminiAnthropic Claude
Tamanho máximo de imagem por request8 MB (Chat image_url · acima é descartado) · 50 MB via Responses input_image com file_idInline ≤20 MB total · 100 MB via Files API por imagem5 MB por imagem via API · 10 MB pela UI claude.ai
Nº de imagens por requestSem limite documentado além do total de 512 MB de payload e do orçamento de patches/tilesLimitado pelos 20 MB inline ou pelo orçamento de tokens; sem cap rígidoAté 100 imagens por request
Tamanho máximo de PDF50 MB por arquivo e por request combinado50 MB (inline ou Files API)32 MB (payload total)
Páginas de PDF por documentoUNVERIFIED — só 50 MB documentado; "100 pgs" não consta no guide atualAté 1000 páginasAté 600 páginas (1M ctx Opus/Sonnet) · 100 páginas (Haiku 4.5)
Formatos de vídeo aceitosNão há ingestão de vídeo nativa — frame extraction (JPEG/PNG)mp4, mpeg, mov, avi, x-flv, mpg, webm, wmv, 3gppNão há ingestão de vídeo nativa — frame extraction
FPS de vídeoN/A (frames extraídos manualmente)1 FPS default · ajustável via video_metadata.fps (intervalo exato UNVERIFIED)N/A (frames extraídos manualmente)
Duração máxima de vídeoN/A para análise · Geração Sora 2: até 20 sAté ~3h em LOW resolution / ~45 min em default · YouTube URL como inputN/A
Tamanho máximo de áudio25 MB por arquivo em /v1/audio/transcriptions · 512 MB via Files API20 MB inline · 2 GB via Files APINão suporta áudio nativo
Duração máxima de áudioWhisper/4o-transcribe: limite por tamanho (25 MB) · Realtime ilimitado em sessão9,5 horas combinadas por request · 32 tokens/segundoN/A — usar STT externo
Formatos de áudio aceitosmp3, mp4, mpeg, mpga, m4a, wav, webm, flac, ogg (Whisper) · wav, mp3 em input_audio de Chatwav, mp3, mp4, aiff, aac, ogg, flac (audio/mpeg aceito na prática) UNVERIFIEDN/A
Sandbox — memóriaCode Interpreter: 1g default · 4g · 16g · 64g (tier billing)Code execution: não documentado publicamente; suficiente para pandas/matplotlibCode Execution: 5 GiB RAM fixos
Sandbox — discoNão documentado explicitamente (associado ao memory_limit)Não documentado publicamente5 GiB workspace em /mnt/user-data/
Sandbox — CPUNão documentado por tierNão documentado publicamente1 vCPU
Sandbox — networkSem network outboundSem network outbound (não há pip install)Sem network outbound por padrão
Sandbox — lifetime20 min idle · qualquer operação no container reseta last_active_atPor chamada (sandbox efêmero, sem persistência entre requests)REPL persiste no turno (_20260120) · container expira após inatividade
Files API — tamanho por arquivoAté 512 MB por arquivo (purposes: assistants/vision/batch/fine-tune/user_data/evals)2 GB por arquivo500 MB por arquivo
Files API — quota por projeto/org2,5 TB por projeto · 1.000 uploads/min/usuário20 GB (paid) / 2 GB (free) por projeto500 GB por organização
Files API — retençãoPersistem até deleção explícita · arquivos de batch retidos 30 d (output) / 24 h (vídeos)48 horas e auto-deletadosPersistem até deleção explícita
Gerar imagemSim gpt-image-2 (Responses tool ou /v1/images)Sim gemini-3.1-flash-image (Nano Banana 2)Não
Gerar vídeoSim Sora 2 / Sora 2-Pro (até 20s)Sim família Veo 3 (API separada)Não
Gerar áudio (TTS)Sim gpt-realtime-2, gpt-audio-1.5, Voice/Speech APIsSim via Live API e modelos TTS GeminiNão
Identificar pessoas pelo rostoBloqueado por safetyBloqueado por safetyBloqueado por safety
Ler CAPTCHAsBloqueado por safetyBloqueado por safetyBloqueado por safety
Detectar imagem AI-geradaNão confiável; sem garantia documentadaNão confiável; sem garantia documentadaNão confiável ("do not use as a fake-image detector" nos docs)
Diagnóstico médicoNão substitui parecer médico; CT/MRI fora do escopoNão substitui parecer médicoNão é ferramenta diagnóstica; nunca substituir avaliação clínica
EXIF / metadados de imagemNão lê (apenas pixels)Não lê (apenas pixels) · tokens via media_resolutionNão lê (apenas pixels)
Rotação automáticaNão corrige rotação fora de EXIF — pré-processarNão corrige — pré-processarNão corrige — pré-processar (Opus 4.8 tolera melhor)
Texto não-latino pequenoCaso difícil; usar detail:"original"Caso difícil; media_resolution: ULTRA_HIGHCaso difícil; preferir hi-res Opus 4.8
Citações por trecho em PDFVia File Search annotations (file_citation.quote)Apenas via prompt — sem citation primitiveNativo citations.enabled: true
Batch — desconto~50% off · output em 24h · JSONL ≤200 MB~50% off · SLA típico 24h50% off · até 100k requests · 24h SLA
+
+
+ + + +
+

10. Fontes & verificação

+

+ Todas as URLs abaixo foram consultadas em 2026-05-23 pelos + agentes de pesquisa via MCP (openaiDeveloperDocs, + geminiApiDocs) ou fetch direto do platform.claude.com. + Itens marcados UNVERIFIED nos deep-dives + passam por re-confirmação em arquivos de verificação dedicados — ver final + desta seção. +

+ + +

10.1 OpenAI — developers.openai.com

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProviderTítuloURLData
OpenAIImages and visiondevelopers.openai.com/.../images-vision2026-05-23
OpenAIImages and vision — Patch-based tokenization…#patch-based-image-tokenization2026-05-23
OpenAIImages and vision — Tile-based tokenization…#tile-based-image-tokenization2026-05-23
OpenAIImages and vision — Limitations…#limitations2026-05-23
OpenAIFile inputsdevelopers.openai.com/.../file-inputs2026-05-23
OpenAICounting tokens — files…/token-counting#count-tokens-with-files2026-05-23
OpenAICode Interpreterdevelopers.openai.com/.../tools-code-interpreter2026-05-23
OpenAICode Interpreter — Work with files…#work-with-files2026-05-23
OpenAIAudio and speechdevelopers.openai.com/.../audio2026-05-23
OpenAISpeech to textdevelopers.openai.com/.../speech-to-text2026-05-23
OpenAIRealtime conversationsdevelopers.openai.com/.../realtime-conversations2026-05-23
OpenAIRealtime transcriptiondevelopers.openai.com/.../realtime-transcription2026-05-23
OpenAIVideo generation with Soradevelopers.openai.com/.../video-generation2026-05-23
OpenAIFiles — Upload (reference)developers.openai.com/.../files/methods/create2026-05-23
OpenAIRate limitsdevelopers.openai.com/.../rate-limits2026-05-23
OpenAIGuia — Images & vision (frame pattern p/ vídeo)developers.openai.com/api/docs/guides/images-vision2026-05-23
OpenAIImage generationdevelopers.openai.com/.../image-generation2026-05-23
OpenAIMigrate to the Responses APIdevelopers.openai.com/.../migrate-to-responses2026-05-23
OpenAICookbook — GPT-5.4 vision tips…/document_and_multimodal_understanding_tips2026-05-23
OpenAIBatch APIdevelopers.openai.com/.../batch2026-05-23
OpenAIAssistants API deep divedevelopers.openai.com/.../assistants/deep-dive2026-05-23
OpenAIData controls in the OpenAI platformdevelopers.openai.com/.../your-data2026-05-23
OpenAICookbook — Sora 2 Prompting Guidedevelopers.openai.com/cookbook/.../sora2_prompting_guide2026-05-23
OpenAIChat completions (reference)…/chat/.../completions/methods/create2026-05-23
OpenAITranscriptions (reference)…/audio/.../transcriptions/methods/create2026-05-23
OpenAIRealtime server events (reference)…/realtime/server-events2026-05-23
OpenAIChangelog (Feb 2026 — input_file expansion)developers.openai.com/.../changelog2026-05-23
OpenAIUsing GPT-5.5 / latest-modeldevelopers.openai.com/.../latest-model2026-05-23
+
+ + +

10.2 Google Gemini — ai.google.dev

+
+ + + + + + + + + + + + + + + + + + + + +
ProviderTítuloURLData
GeminiImage understandingai.google.dev/gemini-api/docs/image-understanding2026-05-23
GeminiMedia resolutionai.google.dev/gemini-api/docs/media-resolution2026-05-23
GeminiDocument processing (PDF)ai.google.dev/gemini-api/docs/document-processing2026-05-23
GeminiFile input methodsai.google.dev/gemini-api/docs/file-input-methods2026-05-23
GeminiFiles APIai.google.dev/gemini-api/docs/files2026-05-23
GeminiCode executionai.google.dev/gemini-api/docs/code-execution2026-05-23
GeminiVideo understandingai.google.dev/gemini-api/docs/video-understanding2026-05-23
GeminiAudio understandingai.google.dev/gemini-api/docs/audio2026-05-23
GeminiContext cachingai.google.dev/gemini-api/docs/caching2026-05-23
GeminiURL context toolai.google.dev/gemini-api/docs/url-context2026-05-23
GeminiInference tiers & optimizationai.google.dev/gemini-api/docs/optimization2026-05-23
GeminiZero data retentionai.google.dev/gemini-api/docs/zdr2026-05-23
GeminiModels indexai.google.dev/gemini-api/docs/models2026-05-23
GeminiGemini Robotics-ER 1.6 overviewai.google.dev/gemini-api/docs/robotics-overview2026-05-23
GeminiLive APIai.google.dev/gemini-api/docs/live2026-05-23
GeminiPricingai.google.dev/gemini-api/docs/pricing2026-05-23
+
+ + +

10.3 Anthropic — platform.claude.com

+
+ + + + + + + + + + +
ProviderTítuloURLData
AnthropicVisionplatform.claude.com/.../build-with-claude/vision2026-05-23
AnthropicPDF supportplatform.claude.com/.../pdf-support2026-05-23
AnthropicFiles APIplatform.claude.com/.../files2026-05-23
AnthropicCode execution toolplatform.claude.com/.../code-execution-tool2026-05-23
AnthropicModels overviewplatform.claude.com/.../models/overview2026-05-23
AnthropicFiles API — create endpointplatform.claude.com/.../api/files-create2026-05-23 (redirect)
+
+ + +
+ Verificação cruzada: os itens marcados UNVERIFIED + nos deep-dives são aqueles que, na data de verificação, não puderam ser confirmados + de forma inequívoca contra a documentação oficial pública dos providers. Pontos + re-confirmados contra as páginas oficiais incluem, por exemplo: o FPS range, os MIME + de áudio e o suporte nativo a OOXML no Gemini (ai.google.dev); e, na Anthropic + (platform.claude.com / docs.claude.com), o header + code-execution-2026-01-20, document.source.type="text", a ausência + de áudio/vídeo nativo e o mínimo de tokens cacheáveis. Itens ainda marcados + UNVERIFIED devem ser substituídos pelos valores oficiais + quando a fonte oficial os documentar; até lá, valem como notas de pesquisa. +
+
+ + + +
+

11. Sumário para IA (JSON-LD)

+

+ Bloco abaixo é um resumo legível por máquina (schema.org/TechArticle + + additionalProperty) com os fatos canônicos por provider e + modalidade. Um scraper / agente pode ingerir apenas este bloco para popular + uma matriz de capacidades sem reler o guia inteiro. O mesmo conteúdo aparece + em <pre> abaixo para diff manual. +

+ + + +

Mesmo JSON, legível:

+
{
+  "@context": "https://schema.org",
+  "@type": "TechArticle",
+  "name": "Guia Multimodal — OpenAI, Gemini e Anthropic",
+  "datePublished": "2026-05-23",
+  "author": "Referência técnica — documentação oficial OpenAI, Google Gemini e Anthropic",
+  "about": "OpenAI / Google Gemini / Anthropic Claude multimodal APIs",
+  "additionalProperty": [
+    { "propertyID": "openai.vision",
+      "value": "Patch-based (mini/nano) + tile-based (4o/4.1). image_url 8 MB Chat; input_image (URL/base64/file_id) Responses. CAPTCHA/face ID bloqueados." },
+    { "propertyID": "openai.pdf",
+      "value": "input_file 50 MB combinado. OCR + page-image por página. File Search para PDFs grandes." },
+    { "propertyID": "openai.office",
+      "value": "Spreadsheets 1000 rows; analytics = code_interpreter (1g/4g/16g/64g)." },
+    { "propertyID": "openai.video",
+      "value": "Sem nativo; frames + Whisper. Sora 2 gera até 20 s." },
+    { "propertyID": "openai.audio",
+      "value": "STT 25 MB; gpt-audio-1.5 input_audio; Realtime WS/WebRTC." },
+    { "propertyID": "openai.files",
+      "value": "512 MB/arquivo; 2,5 TB/projeto; purposes documentados." },
+
+    { "propertyID": "gemini.vision",
+      "value": "inline 20 MB / Files 100 MB. 258 tok/tile. media_resolution LOW..ULTRA_HIGH." },
+    { "propertyID": "gemini.pdf",
+      "value": "50 MB, 1000 pgs. Gemini 3 inclui texto + render." },
+    { "propertyID": "gemini.office",
+      "value": "XLSX/DOCX nativo UNVERIFIED; converter para PDF ou code_execution." },
+    { "propertyID": "gemini.video",
+      "value": "Nativo. 1 FPS default, 258 tok/frame, até ~3h em LOW. YouTube URL." },
+    { "propertyID": "gemini.audio",
+      "value": "Nativo, 32 tok/seg, até 9,5 h combinadas." },
+    { "propertyID": "gemini.files",
+      "value": "2 GB/arquivo; 20 GB/projeto; retenção 48 h." },
+    { "propertyID": "gemini.cache",
+      "value": "Implícito + explícito; ttl configurável; multimodal." },
+
+    { "propertyID": "anthropic.vision",
+      "value": "image block. Opus 4.8 hi-res 2576 px / 4784 tok. 100 imagens/request. 5 MB/imagem." },
+    { "propertyID": "anthropic.pdf",
+      "value": "document block. 600 pgs (1M ctx). citations.enabled nativo (único provider)." },
+    { "propertyID": "anthropic.office",
+      "value": "container_upload + code_execution; openpyxl/python-docx/pptx/pdfplumber." },
+    { "propertyID": "anthropic.video",
+      "value": "Sem nativo; frames + transcript externo." },
+    { "propertyID": "anthropic.audio",
+      "value": "Sem áudio nativo; STT externo + text." },
+    { "propertyID": "anthropic.code",
+      "value": "5 GiB RAM, 5 GiB disk, 1 vCPU, sem network. _20250825 e _20260120." },
+    { "propertyID": "anthropic.files",
+      "value": "Beta files-api-2025-04-14. 500 MB/arquivo; 500 GB/org." },
+    { "propertyID": "anthropic.cache",
+      "value": "cache_control: ephemeral. 5 min / 1 h opcional." },
+
+    { "propertyID": "cross.image_generation",
+      "value": "OpenAI gpt-image-2; Gemini Nano Banana 2; Anthropic NÃO." },
+    { "propertyID": "cross.video_generation",
+      "value": "OpenAI Sora 2 (≤20s); Gemini Veo 3; Anthropic NÃO." },
+    { "propertyID": "cross.safety_blocks",
+      "value": "Face ID, CAPTCHA, diagnóstico médico definitivo, detecção de IA-gerado: não suportados em nenhum." }
+  ]
+}
+
+ +
+ Como usar este bloco: um scraper / agente pode pular direto + para script[type="application/ld+json"] e tratar + additionalProperty como uma matriz provider × modalidade. + Os propertyID seguem o padrão <provider>.<capability> + (com cross.* para fatos cross-provider) para facilitar mapping + a YAML/JSONSchema downstream. +
+
+ + +
+
+ + +
+
+
+
Guia Multimodal OpenAI · Gemini · Anthropic
+

+ Referência técnica comparativa construída a partir de docs oficiais públicas + dos três providers (developers.openai.com, ai.google.dev, platform.claude.com / docs.claude.com) + em 2026-06-10. Itens marcados + UNVERIFIED precisam de re-verificação antes + de citar publicamente. +

+
+
+
Fontes
+
Documentação oficial de OpenAI, Google Gemini e Anthropic
+
Verificado · 2026-06-10
+
+ OpenAI + Gemini + Claude +
+
+
+
Navegação rápida
+ + + + +
+
+
+ + + diff --git a/references/agents_tools_best_guides/guia_openai_modelos.html b/references/agents_tools_best_guides/guia_openai_modelos.html new file mode 100644 index 0000000..eb43e0a --- /dev/null +++ b/references/agents_tools_best_guides/guia_openai_modelos.html @@ -0,0 +1,5963 @@ + + + + + +Guia OpenAI — Modelos mais recentes & API (Responses, Realtime, Imagem, Áudio) + + + + + + + + +
+
+
Guia OpenAI PT-BR · Modelos mais recentes & API
+
+ Verificado em 2026-06-25 + SDK openai + SOTA + +
+
+
+ +
+ + +
+ +
+

Guia OpenAI — Modelos mais recentes & API

+

+ Referência técnica exaustiva, em PT-BR, dos modelos OpenAI mais recentes e de + como usá-los: gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano (texto e raciocínio pela + Responses API), gpt-image-2 (geração e edição de imagens, visão), + áudio e tempo real (gpt-realtime-2, gpt-realtime-translate, + gpt-realtime-whisper, gpt-4o-transcribe, + gpt-4o-mini-tts, gpt-audio-1.5), além de embeddings, + moderation, preços, limites e operação. Feito para leitura por humanos e por IA. +

+
+ SDK openai · Python & JavaScript + Responses API + SOTA · 2026-06-25 +
+
+ +
+

Sobre este guia

+

+ Este documento reúne, de forma estruturada e navegável, a documentação dos modelos OpenAI + mais recentes e das APIs usadas para acessá-los. O foco é a + Responses API (a interface recomendada para texto, raciocínio, multimodal e + ferramentas), complementada pelas APIs dedicadas de imagem, áudio/realtime, + embeddings e moderation. +

+

+ O guia é deliberadamente centrado nos modelos atuais: descreve apenas os modelos + de ponta e como utilizá-los, sem comparativos com versões anteriores. Cada seção termina com a + fonte oficial correspondente — para fatos perecíveis (IDs de modelo, parâmetros, + preços e limites), consulte sempre a documentação oficial, pois mudam com frequência. +

+
+ Como navegar: a barra lateral é um sumário fixo. A Parte A cobre os + modelos de texto/raciocínio e a Responses API; a Parte B, imagem e visão; a + Parte C, áudio e tempo real; e a Parte D, embeddings, moderation, + preços e operação. O apêndice traz uma referência rápida de endpoints e a tabela de IDs de modelo. +
+
+ Convenções de código: exemplos em Python e JavaScript + usam o SDK oficial openai; exemplos REST usam curl contra + https://api.openai.com/v1/… com Authorization: Bearer $OPENAI_API_KEY. + Use os botões de aba para alternar a linguagem. +
+
+ +
+

Fontes oficiais

+

Todo o conteúdo deste guia é derivado da documentação pública oficial da OpenAI, verificada em 2026-06-10:

+
+ + + + + + + + + + +
RecursoOnde
Documentação de plataformaplatform.openai.com/docs
Documentação para desenvolvedoresdevelopers.openai.com
Referência da APIplatform.openai.com/docs/api-reference
Modelosplatform.openai.com/docs/models
Preçosplatform.openai.com/docs/pricing
Cookbookcookbook.openai.com
+
+ +
+ +

Parte A — Modelos, Texto & Responses API

Os modelos de raciocínio gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano e como usá-los pela Responses API: texto, reasoning, ferramentas, streaming, estado e caching.

+ + + +
+

2. Seleção de modelo

+

O princípio é simples: otimize primeiro a acurácia até bater sua meta de qualidade; só então otimize custo e latência mantendo essa acurácia. Comece com o modelo mais capaz, defina uma meta clara, monte um conjunto de evals e só desça para um modelo menor quando ele preservar a qualidade no ponto de custo/latência que você precisa.

+ +

2.1 Quando usar cada modelo

+
+ + + + + + + +
Se você precisa de…Comece comPor quê
Qualidade máxima em coding, agentes e raciocínio multi-etapagpt-5.5Linha de base de fronteira; melhor seleção e uso de ferramentas, planejamento e execução.
Bom equilíbrio com custo menorgpt-5.4-miniMantém raciocínio e ferramentas com latência e custo reduzidos para volume alto.
Latência/custo mínimos em tarefas simplesgpt-5.4-nanoIdeal para classificação, extração e respostas curtas onde a tarefa é bem definida.
+
+ +
Dica: num mesmo fluxo, misture modelos por especialista — um agente de triagem rápido em gpt-5.4-mini e um especialista profundo em gpt-5.5 podem coexistir. Defina o modelo explicitamente em produção em vez de depender do default do SDK.
+ +

Antes de escalar o reasoning.effort, lembre que o gpt-5.5 raciocina de forma mais eficiente, usando menos tokens de raciocínio no mesmo nível de esforço. Em fluxos sensíveis à latência, reavalie low antes de subir para medium/high.

+ + +
+ +
+

3. Quickstart & SDKs

+

Instale o SDK oficial openai, defina a variável de ambiente OPENAI_API_KEY e faça a primeira chamada com client.responses.create(...). O SDK lê a chave do ambiente automaticamente.

+ +

3.1 Instalação

+
+
+ + + +
+
+
pip install openai
+export OPENAI_API_KEY="sk-..."
+
+
+
npm install openai
+export OPENAI_API_KEY="sk-..."
+
+
+
# Nenhum SDK necessário; basta a chave no ambiente:
+export OPENAI_API_KEY="sk-..."
+
+
+ +

3.2 Primeira chamada

+
+
+ + + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input="Escreva um haicai sobre IA confiável.",
+)
+
+print(response.output_text)
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Escreva um haicai sobre IA confiável.",
+});
+
+console.log(response.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "Escreva um haicai sobre IA confiável."
+  }'
+
+
+ +
Atenção: o array output costuma ter mais de um item (chamadas de ferramenta, itens de reasoning, etc.). Não assuma que o texto está em output[0].content[0].text. Use o atalho output_text dos SDKs, que agrega todo o texto da resposta.
+ + +
+ +
+

4. Anatomia da Responses API

+

A Responses API (POST /v1/responses) é a primitiva recomendada para todo projeto novo. Ela é um loop agêntico por padrão: numa única requisição o modelo pode chamar várias ferramentas (web search, file search, code interpreter, MCP, suas funções) antes de responder. Trabalha com itens (cada um — message, function_call, reasoning, etc. — é uma unidade distinta de contexto), em vez de mensagens monolíticas.

+ +

4.1 Campos principais da requisição

+
+ + + + + + + + + + + + + + + + + + + + + + + +
CampoTipoDescrição
modelstringSlug do modelo, ex.: gpt-5.5. Em produção, fixe um snapshot quando precisar de comportamento estável.
inputstring | arrayO prompt. Pode ser uma string simples ou um array de itens com role (developer/user/assistant) e conteúdo (texto, imagem, arquivo).
instructionsstringInstruções de alto nível (tom, metas, regras). Têm prioridade sobre o input e valem só para a geração atual.
reasoningobject{ "effort": "...", "summary": "..." }. Controla o esforço de raciocínio e o resumo de raciocínio. Ver §6.
textobject{ "verbosity": "...", "format": {...} }. Controla concisão da saída e o formato (Structured Outputs). Ver §7 e §9.
toolsarrayFerramentas disponíveis: funções suas, ferramentas integradas (web_search, file_search, code_interpreter, mcp, shell, computer, apply_patch, image_generation) e tool_search. Ver §11.
tool_choicestring | objectauto (padrão), required, none, função forçada, ou allowed_tools. Ver §10.
previous_response_idstringEncadeia a resposta anterior para conversa multi-turno com estado preservado. Ver §13.
conversationstringID de um objeto da Conversations API para persistir estado de forma durável.
storebooleanSe a resposta é armazenada (padrão true; respostas ficam 30 dias). Defina false para fluxos stateless/ZDR.
streambooleanSe true, transmite eventos SSE conforme a geração avança. Ver §12.
backgroundbooleanExecuta a tarefa de forma assíncrona (requer store=true). Ver §14.
max_output_tokensintegerLimita o total de tokens gerados (visíveis + raciocínio), controlando custo.
includearrayInclui dados extras na saída, ex.: "reasoning.encrypted_content" para fluxos stateless.
prompt_cache_keystringMelhora o roteamento de cache para requisições com prefixo comum. Ver §15.
promptobjectUsa um prompt reutilizável salvo no dashboard (id, version, variables). Ver §5.
metadataobjectAté 16 pares chave-valor para anotar a resposta (chaves ≤ 64 chars, valores ≤ 512 chars).
safety_identifierstringIdentificador estável e opaco do seu usuário final (ex.: hash do ID), usado pela OpenAI para monitorar abuso e preservar seu acesso caso um usuário viole políticas. Não envie e-mail/nome em claro. (Equivale ao header OpenAI-Safety-Identifier no Realtime — ver §22.)
moderationobject{ "model": "omni-moderation-latest" }. Retorna scores de moderação da entrada e da saída na mesma resposta, sem chamada separada (novidade de jun/2026; também em Chat Completions). Ver §30.5.
+
+ +

4.2 O objeto de resposta

+

A resposta traz um objeto tipado com id, status (completed, incomplete, queued, in_progress, failed), output (array de itens), output_text (atalho dos SDKs) e usage. O bloco usage detalha o consumo:

+
{
+  "usage": {
+    "input_tokens": 75,
+    "input_tokens_details": { "cached_tokens": 0 },
+    "output_tokens": 1186,
+    "output_tokens_details": { "reasoning_tokens": 1024 },
+    "total_tokens": 1261
+  }
+}
+

Quando a resposta excede o limite, status volta incomplete com incomplete_details.reason = "max_output_tokens" — possivelmente antes de qualquer texto visível, já consumindo tokens de entrada e raciocínio.

+ + +
+ +
+

5. Geração de texto

+

Texto é o caso de uso primário. Você fornece um prompt e o modelo gera a resposta no array output; o atalho output_text agrega todo o texto produzido.

+ +

5.1 Roles e instructions

+

Você dirige o modelo com níveis de autoridade. O parâmetro instructions dá orientação de alto nível (tom, metas, exemplos) e tem prioridade sobre o input. Como alternativa, use mensagens com role:

+
    +
  • developer — regras e lógica de negócio da aplicação (como a definição de uma função). Prioridade acima de user.
  • +
  • user — instruções/entradas do usuário final (como os argumentos da função).
  • +
  • assistant — mensagens geradas pelo modelo.
  • +
+ +
+
+ + + +
+
+
from openai import OpenAI
+client = OpenAI()
+
+response = client.responses.create(
+    model="gpt-5.5",
+    reasoning={"effort": "low"},
+    instructions="Você é um assistente técnico. Responda em PT-BR, conciso.",
+    input="Explique embeddings em duas frases.",
+)
+
+print(response.output_text)
+
+
+
import OpenAI from "openai";
+const client = new OpenAI();
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  reasoning: { effort: "low" },
+  instructions: "Você é um assistente técnico. Responda em PT-BR, conciso.",
+  input: "Explique embeddings em duas frases.",
+});
+
+console.log(response.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "reasoning": { "effort": "low" },
+    "instructions": "Você é um assistente técnico. Responda em PT-BR, conciso.",
+    "input": "Explique embeddings em duas frases."
+  }'
+
+
+ +
Nota: instructions vale só para a geração atual. Se você gerencia estado com previous_response_id, as instruções de turnos anteriores não ficam no contexto — reenvie quando necessário.
+ +

5.2 Prompts reutilizáveis

+

Em vez de embutir o prompt no código, crie um prompt reutilizável no dashboard com placeholders como {{customer_name}} e referencie-o via parâmetro prompt (id, version opcional, e variables). Isso facilita iterar e versionar prompts sem mudar o código de integração.

+
+
+ + + +
+
+
response = client.responses.create(
+    model="gpt-5.5",
+    prompt={
+        "id": "pmpt_abc123",
+        "version": "2",
+        "variables": {"customer_name": "Jane Doe", "product": "caixa de suco 1,2L"},
+    },
+)
+print(response.output_text)
+
+
+
const response = await client.responses.create({
+  model: "gpt-5.5",
+  prompt: {
+    id: "pmpt_abc123",
+    version: "2",
+    variables: { customer_name: "Jane Doe", product: "caixa de suco 1,2L" },
+  },
+});
+console.log(response.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "prompt": {
+      "id": "pmpt_abc123",
+      "version": "2",
+      "variables": { "customer_name": "Jane Doe", "product": "caixa de suco 1,2L" }
+    }
+  }'
+
+
+ + +
+ +
+

6. Reasoning (reasoning.effort)

+

Modelos de raciocínio usam reasoning tokens para planejar antes de responder. Esses tokens não são visíveis pela API, mas ocupam espaço na janela de contexto e são cobrados como tokens de saída. O gpt-5.5 suporta interleaved thinking: pode gerar saída visível antes, entre e depois de pensar, inclusive entre chamadas de ferramenta.

+ +

6.1 Níveis de esforço

+

O gpt-5.5 aceita none, low, medium, high e xhigh, com padrão medium. Subconjuntos variam por modelo — confira a página de cada modelo.

+
+ + + + + + + + + +
EsforçoMelhor para…
nonePiso de esforço (gera pouco ou nenhum reasoning token; ocupa o lugar do antigo nível mínimo). Mesmo em none as ferramentas hospedadas (web/file search) e o function calling continuam funcionando. Tarefas latency-critical sem benefício de raciocínio: voz, recuperação rápida, classificação. Para casos sensíveis à latência, comece em low e desça para none só se necessário; com none, peça ao modelo para "planejar antes de cada chamada de função" para compensar a ausência de tokens de raciocínio.
lowRaciocínio eficiente com aumento modesto de latência: análise de dados, drafting, coding de execução, suporte/chat. Ideal quando há uso de ferramentas, planejamento ou decisão multi-etapa, otimizando velocidade e custo.
mediumPadrão. Quando qualidade e confiabilidade importam e há planejamento/julgamento: coding agêntico, pesquisa, planilhas e slides, trabalho de horizonte longo. Ponto bem equilibrado de latência × performance × custo.
highRaciocínio difícil, debugging complexo, planejamento profundo e tarefas de alto valor onde qualidade importa mais que latência. Avalie medium e high.
xhighPesquisa profunda, fluxos assíncronos e tarefas agênticas de rollout muito longo: revisão de segurança/código, produtividade corporativa, coding desafiador. Use só quando os evals justificarem a latência/custo extra.
+
+ +
Dica: para melhor time to first token em aplicações sensíveis à latência, peça ao modelo um preâmbulo curto antes de continuar com raciocínio mais profundo. Controle o tamanho da resposta com max_output_tokens — a OpenAI recomenda reservar ao menos ~25.000 tokens para raciocínio + saída ao começar.
+ +

6.2 Resumos de raciocínio

+

Os tokens brutos de raciocínio não são expostos, mas você pode pedir um resumo com reasoning.summary. Use "auto" para o resumidor mais detalhado disponível. O resumo aparece no array summary dentro do item de reasoning na saída.

+
+
+ + + +
+
+
response = client.responses.create(
+    model="gpt-5.5",
+    input="Qual é a capital da França?",
+    reasoning={"effort": "low", "summary": "auto"},
+)
+print(response.output)
+
+
+
const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Qual é a capital da França?",
+  reasoning: { effort: "low", summary: "auto" },
+});
+console.log(response.output);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "Qual é a capital da França?",
+    "reasoning": { "effort": "low", "summary": "auto" }
+  }'
+
+
+
Nota: antes de usar resumidores com os modelos de raciocínio mais recentes, pode ser necessário concluir a verificação de organização nas configurações da plataforma.
+ +

6.3 Manter itens de reasoning no contexto

+

Ao fazer function calling com modelo de raciocínio na Responses API, reenvie os itens de reasoning retornados junto com a última chamada de função (além da saída da função). Se o modelo chamou várias funções em sequência, devolva todos os itens de reasoning, function_call e function_call_output desde a última mensagem user. O jeito mais simples é encadear com previous_response_id; o sistema ignora de forma inteligente itens irrelevantes.

+ +

6.4 Itens de reasoning criptografados (encrypted_content)

+

Em modo stateless (store=false) ou sob Zero Data Retention, você ainda precisa manter os itens de reasoning entre turnos. Para isso, adicione "reasoning.encrypted_content" ao parâmetro include. Os itens de reasoning na saída passam a ter encrypted_content, que você devolve intacto nas próximas requisições — sua aplicação não precisa entender o valor.

+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "reasoning": { "effort": "medium" },
+    "input": "Como está o tempo hoje?",
+    "tools": [ /* config de função */ ],
+    "include": [ "reasoning.encrypted_content" ]
+  }'
+ + +
+ +
+

7. Verbosity & phase

+ +

7.1 text.verbosity

+

O text.verbosity é a alavanca principal para equilibrar concisão × completude da resposta. Valores suportados: low, medium (padrão) e high. Verbosidade menor gera menos tokens de saída e responde mais rápido; maior produz explicações mais ricas e estruturadas. No gpt-5.5, defina low quando quiser respostas mais curtas e diretas.

+
Dica: trate o tamanho da resposta como separado da qualidade do raciocínio. Combine verbosity com instruções explícitas — orçamento de palavras, número de seções, largura de tabelas ou saída só em JSON — quando precisar de um artefato estável.
+
+
+ + + +
+
+
response = client.responses.create(
+    model="gpt-5.5",
+    input="Resuma a arquitetura de microsserviços.",
+    text={"verbosity": "low"},
+)
+print(response.output_text)
+
+
+
const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Resuma a arquitetura de microsserviços.",
+  text: { verbosity: "low" },
+});
+console.log(response.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "Resuma a arquitetura de microsserviços.",
+    "text": { "verbosity": "low" }
+  }'
+
+
+ +

7.2 Parâmetro phase

+

Em fluxos longos ou tool-heavy, o campo phase nas mensagens assistant distingue atualizações intermediárias da resposta final. É opcional, mas recomendado:

+
    +
  • phase: "commentary" — atualizações intermediárias, como preâmbulos antes de chamadas de ferramenta.
  • +
  • phase: "final_answer" — a resposta concluída.
  • +
  • Não adicione phase em mensagens user.
  • +
+

Com previous_response_id, o estado do assistant é preservado automaticamente. Se você reproduz o histórico manualmente, preserve cada valor original de phase e devolva-o sem alteração. phase faltante ou descartado pode fazer um preâmbulo ser tratado como resposta final, causando parada precoce.

+
Atenção: se o modelo trata uma atualização intermediária como resposta final em workflows tool-heavy, verifique primeiro se sua integração preserva o campo phase corretamente.
+ + +
+ +
+

8. Prompting GPT-5.5

+

O gpt-5.5 rende melhor com prompts outcome-first: descreva o resultado esperado, critérios de sucesso, restrições e contexto disponível, deixando o modelo escolher o caminho. Evite carregar todo o stack de prompts antigo: instruções que super-especificam o processo viram ruído e estreitam o espaço de busca.

+ +

8.1 Preâmbulo (time to first token)

+

Em streaming, peça um preâmbulo curto antes de chamadas de ferramenta para melhorar a responsividade percebida sem mudar a tarefa.

+
Antes de qualquer chamada de ferramenta numa tarefa multi-etapa, envie uma
+atualização curta e visível ao usuário que reconheça o pedido e indique o
+primeiro passo. Mantenha em uma ou duas frases.
+ +

8.2 Outcome-first e critérios de parada

+

Descreva o destino, não cada passo. Reserve palavras absolutas (ALWAYS, NEVER, must) para invariantes reais (segurança, campos obrigatórios). Para julgamentos (quando buscar, perguntar, usar ferramenta, iterar), prefira regras de decisão. Adicione critérios de parada explícitos:

+
Resolva o pedido do usuário no menor número útil de loops de ferramenta, mas
+não deixe a minimização de loops superar correção, evidência ou citações
+obrigatórias para afirmações factuais.
+
+Após cada resultado, pergunte: "Já consigo responder o pedido central com
+evidência útil e citações?" Se sim, responda.
+ +

8.3 Formatação e personalidade

+

O gpt-5.5 é altamente direcionável em formato. Por padrão é eficiente e direto; para produtos conversacionais, defina personalidade (tom, calor, formalidade) e estilo de colaboração (quando perguntar, quando assumir, quanto contexto dar) — sempre curtos. Use text.verbosity e indique público e tamanho:

+
Escreva para um público sênior de negócios. Mantenha a resposta abaixo de 400
+palavras. Use parágrafos curtos e bullets só quando melhorarem a leitura.
+Priorize a conclusão primeiro, depois o raciocínio, depois ressalvas.
+ +

8.4 Orçamento de retrieval e checagem

+

Orçamentos de retrieval são regras de parada para busca: dizem ao modelo quando há evidência suficiente. Para tarefas com validação, dê ferramentas para o modelo checar o próprio trabalho (testes, type/lint checks, build, ou inspeção do artefato renderizado em UI). Para drafting, separe fatos que precisam de fonte de partes que podem ser escritas criativamente.

+
Para Q&A comum, comece com uma busca ampla usando palavras-chave curtas e
+discriminativas. Se os melhores resultados já dão suporte citável ao pedido
+central, responda a partir deles em vez de buscar de novo.
+
+Faça nova chamada de retrieval só quando: faltar fato/parâmetro/data/ID/fonte
+exigidos, o usuário pedir cobertura exaustiva, ou houver afirmação factual
+importante sem suporte.
+ +
Nota: o gpt-5.5 já conhece a data atual em UTC — não inclua a data nas instruções, salvo quando precisar de um fuso/política específica do negócio. Prefira definir o schema de saída via Structured Outputs em vez de descrevê-lo no prompt.
+ + +
+ +
+

9. Saída estruturada

+

Structured Outputs garante que a resposta siga exatamente um JSON Schema fornecido — sem chaves faltando nem enums inválidos. Benefícios: type-safety confiável, recusas explícitas e prompting mais simples. Na Responses API, configure via text.format com type: "json_schema" e strict: true.

+ +

9.1 Definindo o schema

+

Os SDKs facilitam definir o schema em código com Pydantic (Python) e Zod (JavaScript), via os helpers responses.parse / text_format / zodTextFormat.

+
+
+ + + +
+
+
from pydantic import BaseModel
+from openai import OpenAI
+
+client = OpenAI()
+
+class Passo(BaseModel):
+    explicacao: str
+    saida: str
+
+class Raciocinio(BaseModel):
+    passos: list[Passo]
+    resposta_final: str
+
+response = client.responses.parse(
+    model="gpt-5.5",
+    input=[
+        {"role": "system", "content": "Você é um tutor de matemática. Guie passo a passo."},
+        {"role": "user", "content": "Como resolvo 8x + 7 = -23?"},
+    ],
+    text_format=Raciocinio,
+)
+
+for output in response.output:
+    if output.type != "message":
+        continue
+    for item in output.content:
+        if item.type == "refusal":
+            print(item.refusal)   # recusa de segurança
+        elif item.parsed:
+            print(item.parsed)
+
+
+
import OpenAI from "openai";
+import { z } from "zod";
+import { zodTextFormat } from "openai/helpers/zod";
+
+const client = new OpenAI();
+
+const Passo = z.object({ explicacao: z.string(), saida: z.string() });
+const Raciocinio = z.object({ passos: z.array(Passo), resposta_final: z.string() });
+
+const response = await client.responses.parse({
+  model: "gpt-5.5",
+  input: [
+    { role: "system", content: "Você é um tutor de matemática. Guie passo a passo." },
+    { role: "user", content: "Como resolvo 8x + 7 = -23?" },
+  ],
+  text: { format: zodTextFormat(Raciocinio, "raciocinio") },
+});
+
+for (const output of response.output) {
+  if (output.type !== "message") continue;
+  for (const item of output.content) {
+    if (item.type === "refusal") console.log(item.refusal);
+    else if (item.parsed) console.log(item.parsed);
+  }
+}
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": [
+      { "role": "system", "content": "Você é um tutor de matemática. Guie passo a passo." },
+      { "role": "user", "content": "Como resolvo 8x + 7 = -23?" }
+    ],
+    "text": {
+      "format": {
+        "type": "json_schema",
+        "name": "raciocinio",
+        "strict": true,
+        "schema": {
+          "type": "object",
+          "properties": {
+            "passos": {
+              "type": "array",
+              "items": {
+                "type": "object",
+                "properties": { "explicacao": {"type":"string"}, "saida": {"type":"string"} },
+                "required": ["explicacao", "saida"],
+                "additionalProperties": false
+              }
+            },
+            "resposta_final": { "type": "string" }
+          },
+          "required": ["passos", "resposta_final"],
+          "additionalProperties": false
+        }
+      }
+    }
+  }'
+
+
+ +

9.2 Recusas (refusals)

+

Com entrada gerada por usuário, o modelo pode recusar por segurança. Como a recusa não segue o schema, a resposta inclui um campo refusal em vez do conteúdo estruturado. Detecte-o programaticamente e trate na sua UI/lógica.

+
{
+  "type": "message",
+  "role": "assistant",
+  "content": [
+    { "type": "refusal", "refusal": "Desculpe, não posso ajudar com isso." }
+  ]
+}
+ +
Dica: use text.format quando quiser estruturar a resposta ao usuário; use function calling (com strict) quando estiver conectando o modelo a ferramentas e dados do seu sistema. Para evitar divergência, prefira o suporte nativo de Pydantic/Zod a escrever o JSON Schema à mão.
+ +
Atenção: existe ainda o JSON mode (text.format = {"type": "json_object"}), que garante JSON válido mas não adesão a schema. Prefira Structured Outputs sempre que possível; ao usar JSON mode, instrua explicitamente o modelo a gerar JSON.
+ + +
+ +
+

10. Function calling

+

Function calling (ou tool calling) conecta o modelo a sistemas e dados externos. Você declara funções por JSON Schema; o modelo decide quando chamá-las, emite uma function_call com argumentos, sua aplicação executa e devolve o function_call_output, e o modelo produz a resposta final (ou mais chamadas).

+ +

10.1 Definindo funções

+

Cada função tem type: "function", name, description (quando e como usar), parameters (JSON Schema) e strict.

+
{
+  "type": "function",
+  "name": "get_weather",
+  "description": "Retorna o tempo atual para a localização dada.",
+  "parameters": {
+    "type": "object",
+    "properties": {
+      "location": { "type": "string", "description": "Cidade e país, ex.: Bogotá, Colômbia" },
+      "units": { "type": "string", "enum": ["celsius", "fahrenheit"] }
+    },
+    "required": ["location", "units"],
+    "additionalProperties": false
+  },
+  "strict": true
+}
+ +

10.2 Loop de execução

+
+
+ + + +
+
+
import json
+from openai import OpenAI
+
+client = OpenAI()
+
+tools = [{
+    "type": "function",
+    "name": "get_weather",
+    "description": "Retorna o tempo atual para a localização dada.",
+    "parameters": {
+        "type": "object",
+        "properties": {
+            "location": {"type": "string"},
+            "units": {"type": "string", "enum": ["celsius", "fahrenheit"]},
+        },
+        "required": ["location", "units"],
+        "additionalProperties": False,
+    },
+    "strict": True,
+}]
+
+resp = client.responses.create(
+    model="gpt-5.5",
+    input=[{"role": "user", "content": "Qual o tempo em Paris?"}],
+    tools=tools,
+)
+
+# 1) Detectar e executar chamadas (assuma 0..N)
+inputs = []
+for item in resp.output:
+    if item.type == "function_call":
+        args = json.loads(item.arguments)
+        result = {"temperature": "25", "unit": "C"}  # sua lógica real
+        inputs.append({
+            "type": "function_call_output",
+            "call_id": item.call_id,
+            "output": json.dumps(result),
+        })
+
+# 2) Reenviar reasoning + chamadas + saídas; encadeie com previous_response_id
+final = client.responses.create(
+    model="gpt-5.5",
+    previous_response_id=resp.id,
+    input=inputs,
+    tools=tools,
+)
+print(final.output_text)
+
+
+
import OpenAI from "openai";
+const client = new OpenAI();
+
+const tools = [{
+  type: "function",
+  name: "get_weather",
+  description: "Retorna o tempo atual para a localização dada.",
+  parameters: {
+    type: "object",
+    properties: {
+      location: { type: "string" },
+      units: { type: "string", enum: ["celsius", "fahrenheit"] },
+    },
+    required: ["location", "units"],
+    additionalProperties: false,
+  },
+  strict: true,
+}];
+
+const resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{ role: "user", content: "Qual o tempo em Paris?" }],
+  tools,
+});
+
+const inputs = [];
+for (const item of resp.output) {
+  if (item.type === "function_call") {
+    const args = JSON.parse(item.arguments);
+    const result = { temperature: "25", unit: "C" }; // sua lógica real
+    inputs.push({
+      type: "function_call_output",
+      call_id: item.call_id,
+      output: JSON.stringify(result),
+    });
+  }
+}
+
+const final = await client.responses.create({
+  model: "gpt-5.5",
+  previous_response_id: resp.id,
+  input: inputs,
+  tools,
+});
+console.log(final.output_text);
+
+
+
# 1) Primeira chamada com a definição da ferramenta
+curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": [{ "role": "user", "content": "Qual o tempo em Paris?" }],
+    "tools": [{
+      "type": "function", "name": "get_weather", "strict": true,
+      "description": "Retorna o tempo atual para a localização dada.",
+      "parameters": {
+        "type": "object",
+        "properties": {
+          "location": {"type":"string"},
+          "units": {"type":"string","enum":["celsius","fahrenheit"]}
+        },
+        "required": ["location","units"], "additionalProperties": false
+      }
+    }]
+  }'
+
+# 2) Devolva o resultado encadeando previous_response_id
+curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "previous_response_id": "resp_123",
+    "input": [{
+      "type": "function_call_output",
+      "call_id": "call_abc",
+      "output": "{\"temperature\":\"25\",\"unit\":\"C\"}"
+    }]
+  }'
+
+
+ +

10.3 tool_choice e parallel calls

+
+ + + + + + + + + +
tool_choiceComportamento
"auto" (padrão)O modelo chama zero, uma ou várias funções.
"required"O modelo deve chamar uma ou mais funções.
{"type":"function","name":"..."}Força exatamente uma função específica.
{"type":"allowed_tools","mode":"auto","tools":[...]}Restringe a um subconjunto sem remover ferramentas — útil para preservar prompt caching.
"none"Imita o comportamento de não passar funções.
+
+

O modelo pode chamar várias funções no mesmo turno (parallel tool calls). Desative com parallel_tool_calls: false para garantir zero ou uma chamada. Parallel calls não se aplicam a ferramentas integradas.

+ +
Dica: habilite sempre strict: true — ele usa Structured Outputs para garantir aderência ao schema (exige additionalProperties: false e todos os campos em required; campos opcionais via tipo null). Mantenha menos de ~20 funções disponíveis no início de um turno; para catálogos grandes, use tool search.
+ +
Nota: na Responses API o type: "function" fica no topo da definição (ao lado de name/parameters), diferente do Chat Completions, que aninha tudo sob uma chave "function". Da mesma forma, tool_choice específico aqui é {"type":"function","name":"..."} — sem aninhamento.
+ +

10.4 Custom tools & gramáticas (CFG)

+

Quando a entrada da ferramenta é texto livre (código, um comando, uma consulta) em vez de um objeto JSON, use uma custom tool (type: "custom"). O modelo emite um item custom_tool_call com o campo input em texto puro. Custom tools não suportam parallel tool calls — passe parallel_tool_calls: false.

+

Para garantir que esse texto seja sintaticamente válido (um dialeto SQL, uma DSL), anexe uma gramática livre de contexto (CFG) via bloco format, com syntax "lark" ou "regex". A amostragem é restringida à gramática, então a saída sempre casa com ela.

+
mssql_grammar = r"""
+start: "SELECT" column "FROM" table
+column: "id" | "name" | "email"
+table: "users" | "orders"
+"""
+
+resp = client.responses.create(
+    model="gpt-5.5",
+    input="Liste os e-mails de todos os usuários.",
+    tools=[{
+        "type": "custom",
+        "name": "mssql_query",
+        "description": "Gera uma consulta SQL válida no dialeto suportado.",
+        "format": {"type": "grammar", "syntax": "lark", "definition": mssql_grammar},
+    }],
+    parallel_tool_calls=False,
+)
+# A resposta traz um item custom_tool_call com .input em texto restrito pela gramática.
+
Atenção: mantenha a gramática o mais simples possível — gramáticas complexas podem ser rejeitadas. O dialeto Lark não suporta lookaround, modificadores lazy (*?, +?), prioridades de terminal, templates nem %import (exceto %import common); o mesmo vale para lookaround/lazy em regex.
+ + +
+ +
+

11. Ferramentas integradas

+

Além das suas funções, a Responses API oferece ferramentas integradas (hosted tools), ativadas pelo array tools. Elas estão in-distribution para o pós-treino dos modelos, então tendem a ter melhor seleção e execução do que ferramentas customizadas equivalentes. O modelo decide quando usá-las com base no prompt; você guia com tool_choice.

+ +

11.1 Web search

+

Permite acesso a informação atualizada da internet com citações. Para integrações novas, use { "type": "web_search" } (suporta controles como filters, sources, external_web_access e return_token_budget). A saída inclui um item web_search_call (com a ação: search, open_page ou find_in_page) e uma message com texto e anotações url_citation. Desde jun/2026 a busca também pode retornar resultados de imagem (ver abaixo). Para pesquisa profunda multi-etapa, use gpt-5.5 com reasoning em high/xhigh e background mode.

+
+
+ + + +
+
+
response = client.responses.create(
+    model="gpt-5.5",
+    input="Quais foram as novidades de IA esta semana?",
+    tools=[{"type": "web_search"}],
+)
+print(response.output_text)
+
+
+
const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Quais foram as novidades de IA esta semana?",
+  tools: [{ type: "web_search" }],
+});
+console.log(response.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "Quais foram as novidades de IA esta semana?",
+    "tools": [{ "type": "web_search" }]
+  }'
+
+
+
Atenção: trate o conteúdo de páginas, PDFs e e-mails retornados como entrada não confiável. Só instruções diretas do usuário contam como permissão.
+ +

Resultados de imagem (image search)

+

O web search pode retornar imagens junto dos resultados de texto (novidade de jun/2026) — útil quando o app precisa de visuais atuais e ancorados na web: fotos de produtos, lugares, eventos, referências visuais com link da fonte. Configure search_content_types incluindo "image" (adicione "text" se também quiser resultados textuais que ajudem o modelo a resumir, ranquear ou explicar as imagens) e ajuste o comportamento com image_settings: max_results (quantidade de imagens) e caption (descrições curtas quando disponíveis).

+

Os resultados de imagem não entram na message final: eles voltam no próprio item web_search_call. Para inspecioná-los, peça include: ["web_search_call.results"] e leia web_search_call.results[] — cada image_result traz image_url (URL canônica da imagem), source_website_url (página onde a imagem foi encontrada), thumbnail_url e caption (quando disponíveis).

+
resp = client.responses.create(
+    model="gpt-5.5",
+    input="Fotos recentes da Golden Gate ao pôr do sol",
+    tools=[{
+        "type": "web_search",
+        "search_content_types": ["image", "text"],
+        "image_settings": {"max_results": 5, "caption": True},
+    }],
+    include=["web_search_call.results"],
+)
+
+for item in resp.output:
+    if item.type == "web_search_call":
+        for r in (item.results or []):
+            if r.type == "image_result":
+                print(r.image_url, "|", r.source_website_url, "|", r.caption)
+
{
+  "output": [
+    {
+      "type": "web_search_call",
+      "status": "completed",
+      "results": [
+        {
+          "type": "image_result",
+          "image_url": "https://cdn.example/golden-gate-sunset.jpg",
+          "thumbnail_url": "https://cdn.example/golden-gate-sunset-thumb.jpg",
+          "source_website_url": "https://example.com/source-page",
+          "caption": "Golden Gate Bridge at sunset"
+        }
+      ]
+    }
+  ]
+}
+ +

11.2 File search

+

Recupera informação de uma base de conhecimento de arquivos enviados, via busca semântica e por palavra-chave. Antes, crie um vector store e suba arquivos a ele; depois inclua file_search com os vector_store_ids. A saída traz um item file_search_call e uma message com citações de arquivo. Você pode limitar resultados, incluir os resultados via include e filtrar por metadados.

+
+
+ + + +
+
+
response = client.responses.create(
+    model="gpt-5.5",
+    input="O que é deep research da OpenAI?",
+    tools=[{
+        "type": "file_search",
+        "vector_store_ids": ["vs_abc123"],
+    }],
+)
+print(response.output_text)
+
+
+
const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: "O que é deep research da OpenAI?",
+  tools: [{ type: "file_search", vector_store_ids: ["vs_abc123"] }],
+});
+console.log(response.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "O que é deep research da OpenAI?",
+    "tools": [{ "type": "file_search", "vector_store_ids": ["vs_abc123"] }]
+  }'
+
+
+ +

11.3 MCP & Connectors

+

Dê ao modelo novas capacidades via servidores MCP remotos (qualquer servidor que implemente o Model Context Protocol) e connectors (wrappers MCP mantidos pela OpenAI para serviços como Google Workspace ou Dropbox). Ambos usam o tipo de ferramenta mcp. MCP remoto exige server_url (e às vezes um token OAuth em authorization); connectors exigem connector_id e o token OAuth. As chamadas podem ser automáticas ou exigir aprovação (require_approval).

+
+
+ + + +
+
+
resp = client.responses.create(
+    model="gpt-5.5",
+    tools=[{
+        "type": "mcp",
+        "server_label": "dmcp",
+        "server_description": "Servidor MCP de D&D para rolagem de dados.",
+        "server_url": "https://dmcp-server.deno.dev/sse",
+        "require_approval": "never",
+    }],
+    input="Role 2d4+1",
+)
+print(resp.output_text)
+
+
+
const resp = await client.responses.create({
+  model: "gpt-5.5",
+  tools: [{
+    type: "mcp",
+    server_label: "dmcp",
+    server_description: "Servidor MCP de D&D para rolagem de dados.",
+    server_url: "https://dmcp-server.deno.dev/sse",
+    require_approval: "never",
+  }],
+  input: "Role 2d4+1",
+});
+console.log(resp.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "tools": [{
+      "type": "mcp",
+      "server_label": "dmcp",
+      "server_description": "Servidor MCP de D&D para rolagem de dados.",
+      "server_url": "https://dmcp-server.deno.dev/sse",
+      "require_approval": "never"
+    }],
+    "input": "Role 2d4+1"
+  }'
+
+
+
Cuidado: confie apenas em servidores MCP que você revisou. Um servidor malicioso pode exfiltrar qualquer dado que entre no contexto do modelo. Para servidores privados/on-premises, use o Secure MCP Tunnel em vez de expô-los à internet pública.
+ +

11.4 Code Interpreter

+

Permite ao modelo escrever e executar Python num ambiente sandbox (o modelo o conhece como "python tool"). Use para análise de dados, geração de arquivos/gráficos, matemática e código iterativo. Requer um container: modo auto (cria ou reusa) ou explícito (via /v1/containers). O memory_limit padrão é 1 GB.

+
+
+ + + +
+
+
resp = client.responses.create(
+    model="gpt-5.5",
+    tools=[{
+        "type": "code_interpreter",
+        "container": {"type": "auto", "memory_limit": "4g"},
+    }],
+    instructions="Use a python tool para resolver problemas de matemática.",
+    input="Resolva 3x + 11 = 14.",
+)
+print(resp.output_text)
+
+
+
const resp = await client.responses.create({
+  model: "gpt-5.5",
+  tools: [{
+    type: "code_interpreter",
+    container: { type: "auto", memory_limit: "4g" },
+  }],
+  instructions: "Use a python tool para resolver problemas de matemática.",
+  input: "Resolva 3x + 11 = 14.",
+});
+console.log(resp.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "tools": [{ "type": "code_interpreter", "container": { "type": "auto", "memory_limit": "4g" } }],
+    "instructions": "Use a python tool para resolver problemas de matemática.",
+    "input": "Resolva 3x + 11 = 14."
+  }'
+
+
+ +

11.5 Computer use

+

Permite ao modelo operar software pela interface: ele inspeciona screenshots e devolve ações de UI (cliques, digitação, rolagem, pedidos de screenshot) que seu código executa. O gpt-5.4 recebeu treino específico para esse trabalho. Há três formatos de harness: o loop integrado (ferramenta computer), uma ferramenta/harness custom sobre Playwright/Selenium/VNC/MCP, ou um harness de execução de código.

+
Cuidado: rode Computer use em navegador/VM isolado, mantenha humano no loop para ações de alto impacto e trate todo conteúdo de tela como entrada não confiável. Passe um env vazio e desative extensões e acesso ao filesystem do host quando possível.
+ +

11.6 Apply Patch

+

A ferramenta apply_patch deixa o modelo criar, atualizar e deletar arquivos no seu código via diffs estruturados (formato V4A), habilitando edição iterativa multi-arquivo. Por ser uma ferramenta nomeada (não uma função freeform que você descreve), está in-distribution para o pós-treino — o que reduz a taxa de falha de patch em cerca de 35% frente à abordagem freeform/JSON anterior. O fluxo: ative tools=[{"type":"apply_patch"}], o modelo emite itens apply_patch_call (operações create_file/update_file/delete_file, com path e diff), sua aplicação aplica os patches e devolve um apply_patch_call_output por call_id com status (completed/failed). Disponível só pela Responses API. Ótima combinada com a ferramenta shell para descoberta de arquivos.

+
Nota: o diff V4A é baseado em contexto, não em números de linha — usa âncoras @@ e o envelope *** Begin Patch / *** Add File: / *** Update File: / *** Delete File: / *** Move to: / *** End Patch, com prefixos de linha + (adição), - (remoção) e espaço (contexto). Aplicar a um arquivo divergente falha; devolva status: "failed" com output para o modelo se recuperar.
+
resp = client.responses.create(
+    model="gpt-5.5",
+    tools=[{"type": "apply_patch"}],
+    input="Renomeie a função `parse` para `parse_input` em src/io.py.",
+)
+# Itere sobre resp.output procurando itens type == "apply_patch_call",
+# aplique o diff no seu workspace e devolva apply_patch_call_output por call_id.
+
Atenção: no seu harness, valide caminhos (evite directory traversal), restrinja edições a diretórios permitidos, faça backup antes de aplicar e sempre devolva status: "failed" com um output claro quando um patch não aplicar — assim o modelo se recupera.
+ +

11.7 Tool search

+

Tool search deixa o modelo buscar e carregar ferramentas no contexto sob demanda, evitando carregar todo o catálogo de uma vez — reduz tokens e custo. Só gpt-5.4 e modelos posteriores suportam. Para ativar: adicione {"type": "tool_search"} ao tools e marque as funções/MCP a adiar com defer_loading: true. As ferramentas carregadas são injetadas no fim do contexto, preservando o cache.

+
{
+  "tools": [
+    {
+      "type": "namespace",
+      "name": "crm",
+      "description": "Ferramentas de CRM para busca de clientes e gestão de pedidos.",
+      "tools": [
+        {
+          "type": "function",
+          "name": "list_open_orders",
+          "description": "Lista pedidos abertos por customer_id.",
+          "defer_loading": true,
+          "parameters": {
+            "type": "object",
+            "properties": { "customer_id": { "type": "string" } },
+            "required": ["customer_id"],
+            "additionalProperties": false
+          }
+        }
+      ]
+    },
+    { "type": "tool_search" }
+  ]
+}
+

Há dois modos: hosted (a OpenAI busca entre as ferramentas declaradas e devolve o subconjunto carregado na mesma resposta, via itens tool_search_call e tool_search_output) e client-executed (execution: "client": o modelo emite tool_search_call, sua aplicação faz a busca e devolve um tool_search_output com as ferramentas a carregar). Prefira agrupar em namespaces ou servidores MCP, com até ~10 funções cada e descrições curtas e discriminativas.

+ +

11.8 Local shell & Shell

+

A ferramenta shell dá ao modelo um ambiente de terminal completo, em container hospedado pela OpenAI (use environment: {"type": "container_auto"}) ou num runtime local que você executa. Disponível só pela Responses API.

+
+
+ + + +
+
+
response = client.responses.create(
+    model="gpt-5.5",
+    tools=[{"type": "shell", "environment": {"type": "container_auto"}}],
+    input=[{
+        "type": "message",
+        "role": "user",
+        "content": [{
+            "type": "input_text",
+            "text": "Execute: ls -lah /mnt/data && python --version",
+        }],
+    }],
+    tool_choice="auto",
+)
+print(response.output_text)
+
+
+
const response = await client.responses.create({
+  model: "gpt-5.5",
+  tools: [{ type: "shell", environment: { type: "container_auto" } }],
+  input: [{
+    type: "message",
+    role: "user",
+    content: [{ type: "input_text", text: "Execute: ls -lah /mnt/data && python --version" }],
+  }],
+  tool_choice: "auto",
+});
+console.log(response.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "tools": [{ "type": "shell", "environment": { "type": "container_auto" } }],
+    "input": [{
+      "type": "message", "role": "user",
+      "content": [{ "type": "input_text", "text": "Execute: ls -lah /mnt/data" }]
+    }],
+    "tool_choice": "auto"
+  }'
+
+
+

O runtime hospedado é baseado em Debian 12, com diretório de trabalho /mnt/data (caminho suportado para artefatos baixáveis) e linguagens pré-instaladas (Python 3.11, Node.js 22, Java 17, PHP 8.2, Ruby 3.1, Go 1.23). Não há TTY interativo nem sudo. Para fluxos iterativos, crie um container reutilizável e referencie-o entre chamadas.

+
Cuidado: executar comandos arbitrários é perigoso. Sempre faça sandbox, aplique allowlists/denylists e registre a atividade da ferramenta para auditoria.
+ +

11.9 Receitas e exemplos oficiais (Cookbook)

+

O OpenAI Cookbook traz receitas executáveis para os padrões desta parte. As abaixo estão alinhadas à Responses API e aos modelos atuais; use-as como ponto de partida e adapte os IDs de modelo para gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano.

+
+ + + + + + + + + + + + +
ReceitaO que ensinaLink oficial
GPT-5 prompting guideControle de eagerness/persistência, context gathering, preâmbulos de ferramenta e o ganho de qualidade ao encadear com previous_response_id.cookbook.openai.com/examples/gpt-5/gpt-5_prompting_guide
GPT-5.1 prompting guidereasoning.effort: none com ferramentas, as ferramentas nomeadas apply_patch e shell, e atualizações de status (preâmbulos).cookbook.openai.com/examples/gpt-5/gpt-5-1_prompting_guide
GPT-5 — novos parâmetros e ferramentasverbosity, custom tools de texto livre e gramáticas livres de contexto (CFG, Lark/regex).cookbook.openai.com/examples/gpt-5/gpt-5_new_params_and_tools
Construindo um coding agent com GPT-5.1Loop de agente de código real fiando apply_patch + shell pela Responses API.cookbook.openai.com/examples/Build_a_coding_agent_with_GPT-5.1
Structured Outputs — introduçãoJSON estrito por json_schema + helper Pydantic; regras de schema (todos os campos em required, additionalProperties: false, raiz objeto) e refusals.cookbook.openai.com/examples/structured_outputs_intro
File Search com a Responses APIVector stores, a ferramenta file_search e citações de arquivo em RAG.cookbook.openai.com/examples/file_search_responses
Guia da ferramenta MCPConfigurar o tool mcp, listar ferramentas remotas e tratar o fluxo de aprovação.cookbook.openai.com/examples/mcp/mcp_tool_guide
Agents SDK (Python)Agent/Runner, @function_tool, handoffs vs agent.as_tool(), guardrails com tripwire e sessões de memória — sobre a Responses API.openai.github.io/openai-agents-python
+
+
Atenção — receitas legadas: várias receitas mais antigas do Cookbook usam a Chat Completions API antiga e modelos descontinuados (ex.: How to format inputs to ChatGPT models, How to call functions with chat models, Orchestrating agents — um protótipo Swarm — e versões "with older completions API"). Aproveite delas só os conceitos atemporais (regras de schema, padrões de prompt); o equivalente moderno é sempre a Responses API com gpt-5.5 e, para multi-agentes, o Agents SDK (em vez de reimplementar o loop sobre Chat Completions).
+ +

Exemplos executáveis (Python e JavaScript) das receitas-chave desta parte, adaptados à Responses API e modelos atuais:

+ +

Structured Outputs (json_schema estrito) — cookbook.openai.com/examples/structured_outputs_intro

+
+
+ + +
+
+
from openai import OpenAI
+from pydantic import BaseModel
+
+client = OpenAI()
+
+# Schema estrito: campos tipados via Pydantic (vira json_schema com strict=true)
+class Step(BaseModel):
+    explanation: str
+    output: str
+
+class MathReasoning(BaseModel):
+    steps: list[Step]
+    final_answer: str
+
+# responses.parse aplica o schema e devolve o objeto já tipado
+response = client.responses.parse(
+    model="gpt-5.5",
+    input=[
+        {"role": "system", "content": "Você é um tutor de matemática. Resolva passo a passo."},
+        {"role": "user", "content": "Como resolvo 8x + 7 = -23?"},
+    ],
+    text_format=MathReasoning,
+)
+
+for output in response.output:
+    if output.type != "message":
+        continue
+    for item in output.content:
+        if item.type == "refusal":
+            # Recusa por segurança: não segue o schema; trate à parte
+            print("Recusa:", item.refusal)
+        elif item.parsed:
+            print(item.parsed.final_answer)
+
+
+
import OpenAI from "openai";
+import { z } from "zod";
+import { zodTextFormat } from "openai/helpers/zod";
+
+const client = new OpenAI();
+
+// Schema estrito definido com Zod (vira json_schema com strict=true)
+const Step = z.object({ explanation: z.string(), output: z.string() });
+const MathReasoning = z.object({
+  steps: z.array(Step),
+  final_answer: z.string(),
+});
+
+const response = await client.responses.parse({
+  model: "gpt-5.5",
+  input: [
+    { role: "system", content: "Você é um tutor de matemática. Resolva passo a passo." },
+    { role: "user", content: "Como resolvo 8x + 7 = -23?" },
+  ],
+  text: { format: zodTextFormat(MathReasoning, "math_reasoning") },
+});
+
+for (const output of response.output) {
+  if (output.type !== "message") continue;
+  for (const item of output.content) {
+    if (item.type === "refusal") {
+      // Recusa por segurança: não segue o schema; trate à parte
+      console.log("Recusa:", item.refusal);
+    } else if (item.parsed) {
+      console.log(item.parsed.final_answer);
+    }
+  }
+}
+
+
+ +

File Search / RAG (vector store + tool file_search) — cookbook.openai.com/examples/file_search_responses

+
+
+ + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+# 1) Cria o vector store e anexa um arquivo (a indexação roda no servidor)
+vector_store = client.vector_stores.create(name="base_conhecimento")
+# purpose="assistants" é o valor documentado para ingestão em vector store / file_search
+file = client.files.create(file=open("manual.pdf", "rb"), purpose="assistants")
+client.vector_stores.files.create(
+    vector_store_id=vector_store.id,
+    file_id=file.id,
+)
+
+# 2) A Responses API chama o tool file_search e cita os arquivos
+response = client.responses.create(
+    model="gpt-5.5",
+    input="Qual é a política de reembolso?",
+    tools=[{
+        "type": "file_search",
+        "vector_store_ids": [vector_store.id],
+        "max_num_results": 5,
+    }],
+)
+
+# 3) output[0] = file_search_call; output[1] = message com texto + citações
+print(response.output_text)
+for item in response.output:
+    if item.type == "message":
+        for ann in item.content[0].annotations:
+            print("Citação:", ann.filename)
+
+
+
import OpenAI from "openai";
+import fs from "fs";
+
+const client = new OpenAI();
+
+// 1) Cria o vector store e anexa um arquivo (a indexação roda no servidor)
+const vectorStore = await client.vectorStores.create({ name: "base_conhecimento" });
+// purpose: "assistants" é o valor documentado para ingestão em vector store / file_search
+const file = await client.files.create({
+  file: fs.createReadStream("manual.pdf"),
+  purpose: "assistants",
+});
+await client.vectorStores.files.create(vectorStore.id, { file_id: file.id });
+
+// 2) A Responses API chama o tool file_search e cita os arquivos
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Qual é a política de reembolso?",
+  tools: [{
+    type: "file_search",
+    vector_store_ids: [vectorStore.id],
+    max_num_results: 5,
+  }],
+});
+
+// 3) output[0] = file_search_call; output[1] = message com texto + citações
+console.log(response.output_text);
+for (const item of response.output) {
+  if (item.type === "message") {
+    for (const ann of item.content[0].annotations) console.log("Citação:", ann.filename);
+  }
+}
+
+
+ +

MCP remoto (tool mcp com fluxo de aprovação) — cookbook.openai.com/examples/mcp/mcp_tool_guide

+
+
+ + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+# require_approval="always" faz a API pedir aprovação antes de cada chamada
+resp = client.responses.create(
+    model="gpt-5.5",
+    tools=[{
+        "type": "mcp",
+        "server_label": "dmcp",
+        "server_description": "Servidor MCP de D&D para rolar dados.",
+        "server_url": "https://dmcp-server.deno.dev/sse",
+        "require_approval": "always",
+    }],
+    input="Role 2d4+1",
+)
+
+# A saída traz um item mcp_approval_request; aprove encadeando a resposta
+for item in resp.output:
+    if item.type == "mcp_approval_request":
+        resp = client.responses.create(
+            model="gpt-5.5",
+            previous_response_id=resp.id,
+            input=[{
+                "type": "mcp_approval_response",
+                "approve": True,
+                "approval_request_id": item.id,
+            }],
+        )
+
+print(resp.output_text)
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+
+// require_approval: "always" faz a API pedir aprovação antes de cada chamada
+let resp = await client.responses.create({
+  model: "gpt-5.5",
+  tools: [{
+    type: "mcp",
+    server_label: "dmcp",
+    server_description: "Servidor MCP de D&D para rolar dados.",
+    server_url: "https://dmcp-server.deno.dev/sse",
+    require_approval: "always",
+  }],
+  input: "Role 2d4+1",
+});
+
+// A saída traz um item mcp_approval_request; aprove encadeando a resposta
+for (const item of resp.output) {
+  if (item.type === "mcp_approval_request") {
+    resp = await client.responses.create({
+      model: "gpt-5.5",
+      previous_response_id: resp.id,
+      input: [{
+        type: "mcp_approval_response",
+        approve: true,
+        approval_request_id: item.id,
+      }],
+    });
+  }
+}
+
+console.log(resp.output_text);
+
+
+ + +
+ +
+

12. Streaming

+

Por padrão a API gera toda a saída antes de devolvê-la. Com stream=true, a Responses API transmite eventos semânticos via Server-Sent Events (SSE), permitindo processar/exibir o início da resposta enquanto ela é gerada. Em produção, lembre que transmitir a saída dificulta a moderação de conteúdo — conclusões parciais são mais difíceis de avaliar; considere isso nas suas políticas de uso aprovado.

+ +

12.1 Eventos comuns

+

Cada evento é tipado. Os principais para streaming de texto:

+
    +
  • response.created — a resposta começou.
  • +
  • response.output_text.delta — pedaços de texto à medida que são gerados.
  • +
  • response.completed — a resposta terminou.
  • +
  • error — falha durante o streaming.
  • +
+

Há ainda eventos para itens (response.output_item.added/done), partes de conteúdo, refusals, function_call_arguments.delta (argumentos de função em tempo real) e eventos específicos de file search / code interpreter.

+
+
+ + + +
+
+
stream = client.responses.create(
+    model="gpt-5.5",
+    input="Escreva um conto curto sobre lontras no espaço.",
+    stream=True,
+)
+
+for event in stream:
+    if event.type == "response.output_text.delta":
+        print(event.delta, end="", flush=True)
+    elif event.type == "response.completed":
+        print("\n[fim]")
+
+
+
const stream = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Escreva um conto curto sobre lontras no espaço.",
+  stream: true,
+});
+
+for await (const event of stream) {
+  if (event.type === "response.output_text.delta") process.stdout.write(event.delta);
+  else if (event.type === "response.completed") console.log("\n[fim]");
+}
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "Escreva um conto curto sobre lontras no espaço.",
+    "stream": true
+  }'
+
+
+ +

12.2 WebSocket Mode

+

A Responses API também suporta um modo WebSocket para fluxos longos e tool-call-heavy: você mantém uma conexão persistente com /v1/responses e continua cada turno enviando só os itens novos mais o previous_response_id, via eventos response.create no mesmo socket. Os campos de transporte stream e background não são usados nesse modo.

+

Como a conexão fica aberta e cada turno envia só o incremento, o WebSocket Mode reduz o overhead de continuação e melhora a latência ponta a ponta — em rollouts de 20+ chamadas de ferramenta, ganhos de até ~40%. Uma conexão trata uma resposta por vez (sem multiplexação; paralelismo exige conexões adicionais) e expira em ~60 min; a continuação usa a mesma semântica de previous_response_id, com um cache local da conexão para a resposta mais recente. É compatível com Zero Data Retention e store=false (dados só em memória). As amostras oficiais usam websocket-client em Python e ws em JavaScript.

+ +
HTTP é o padrão — e o fallback. Se o fluxo é uma requisição, uma resposta, fique no HTTP/SSE: o ganho do WebSocket só aparece em agentes de longa duração com muitas chamadas de ferramenta na mesma cadeia. O modo WebSocket é uma otimização de latência opt-in, não o transporte default da Responses API. No Agents SDK (Python) o mesmo transporte é controlado por set_default_openai_responses_transport("websocket") — ver guia_agents_sdk §8.4.
+ + +
+ +
+

13. Estado de conversa

+

Cada geração é independente e stateless por padrão. Há três formas de manter contexto entre turnos.

+ +

13.1 Manual

+

Inclua o histórico no input com mensagens user/assistant alternadas, ou anexe os itens de output da resposta anterior ao próximo input.

+ +

13.2 previous_response_id

+

Encadeia respostas passando o id da anterior. O estado prévio (incluindo reasoning e contexto de ferramenta) é preservado automaticamente — o jeito mais simples de threading.

+
+
+ + + +
+
+
first = client.responses.create(model="gpt-5.5", input="Conte uma piada.")
+print(first.output_text)
+
+second = client.responses.create(
+    model="gpt-5.5",
+    previous_response_id=first.id,
+    input=[{"role": "user", "content": "Explique por que tem graça."}],
+)
+print(second.output_text)
+
+
+
const first = await client.responses.create({ model: "gpt-5.5", input: "Conte uma piada." });
+console.log(first.output_text);
+
+const second = await client.responses.create({
+  model: "gpt-5.5",
+  previous_response_id: first.id,
+  input: [{ role: "user", content: "Explique por que tem graça." }],
+});
+console.log(second.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "previous_response_id": "resp_123",
+    "input": [{ "role": "user", "content": "Explique por que tem graça." }]
+  }'
+
+
+ +

13.3 Conversations API e compaction

+

A Conversations API persiste o estado como um objeto durável (com id próprio) que você reusa entre sessões/dispositivos; passe-o no parâmetro conversation. Itens de uma conversa não têm o TTL de 30 dias das respostas avulsas.

+

Para agentes de longa duração, use compaction para reduzir o contexto preservando o estado necessário: deixe o servidor compactar (com previous_response_id + context_management e compact_threshold) ou chame client.responses.compact() e use a saída diretamente no próximo turno. Não edite a saída compactada — ela é estado de máquina, não um resumo humano.

+
Nota: mesmo com previous_response_id, todos os tokens de entrada da cadeia são cobrados como input a cada turno. Respostas são guardadas por 30 dias por padrão (desative com store=false).
+ + +
+ +
+

14. Background & webhooks

+

Tarefas de raciocínio podem levar minutos. O background mode executa de forma assíncrona, sem risco de timeout: faça a requisição com background: true e faça polling do objeto de resposta.

+ +

14.1 background=true e polling

+
+
+ + + +
+
+
from time import sleep
+
+resp = client.responses.create(
+    model="gpt-5.5",
+    input="Escreva um romance longo sobre lontras no espaço.",
+    background=True,
+)
+
+while resp.status in {"queued", "in_progress"}:
+    sleep(2)
+    resp = client.responses.retrieve(resp.id)
+
+print(resp.status, resp.output_text)
+
+
+
let resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Escreva um romance longo sobre lontras no espaço.",
+  background: true,
+});
+
+while (resp.status === "queued" || resp.status === "in_progress") {
+  await new Promise((r) => setTimeout(r, 2000));
+  resp = await client.responses.retrieve(resp.id);
+}
+console.log(resp.status, resp.output_text);
+
+
+
# Inicia em background
+curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{ "model": "gpt-5.5", "input": "Escreva um romance longo...", "background": true }'
+
+# Polling pelo id
+curl https://api.openai.com/v1/responses/resp_123 \
+  -H "Authorization: Bearer $OPENAI_API_KEY"
+
+# Cancelar (idempotente)
+curl -X POST https://api.openai.com/v1/responses/resp_123/cancel \
+  -H "Authorization: Bearer $OPENAI_API_KEY"
+
+
+

Você pode combinar background com stream: true para começar a receber eventos imediatamente; guarde o sequence_number de cada evento como cursor e, se a conexão cair, retome com ?stream=true&starting_after=<cursor>. Cancelar é idempotente.

+
Atenção: background=true requer store=true (requisições stateless são rejeitadas) e não é compatível com Zero Data Retention, pois guarda dados por ~10 minutos para o polling. Você só pode iniciar um stream a partir de uma resposta em background se a criou com stream=true.
+ +

14.2 Webhooks (assinatura e verificação)

+

Webhooks entregam notificações em tempo real de eventos (ex.: response.completed, conclusão de batch ou fine-tuning) a um endpoint HTTP seu, seguindo a especificação Standard Webhooks. Verifique sempre a assinatura: configure o OPENAI_WEBHOOK_SECRET e use client.webhooks.unwrap(...), que lança erro se a assinatura for inválida.

+
+
+ + +
+
+
import os
+from flask import Flask, request, Response
+from openai import OpenAI, InvalidWebhookSignatureError
+
+app = Flask(__name__)
+client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
+
+@app.route("/webhook", methods=["POST"])
+def webhook():
+    try:
+        event = client.webhooks.unwrap(request.data, request.headers)
+        if event.type == "response.completed":
+            resp = client.responses.retrieve(event.data.id)
+            print("Saída:", resp.output_text)
+        return Response(status=200)
+    except InvalidWebhookSignatureError as e:
+        return Response("Assinatura inválida", status=400)
+
+
+
import OpenAI from "openai";
+import express from "express";
+
+const app = express();
+const client = new OpenAI({ webhookSecret: process.env.OPENAI_WEBHOOK_SECRET });
+
+// Use o corpo cru — a verificação de assinatura precisa do texto original
+app.use(express.text({ type: "application/json" }));
+
+app.post("/webhook", async (req, res) => {
+  try {
+    const event = await client.webhooks.unwrap(req.body, req.headers);
+    if (event.type === "response.completed") {
+      const resp = await client.responses.retrieve(event.data.id);
+      console.log("Saída:", resp.output_text);
+    }
+    res.status(200).send();
+  } catch (error) {
+    if (error instanceof OpenAI.InvalidWebhookSignatureError) {
+      res.status(400).send("Assinatura inválida");
+    } else throw error;
+  }
+});
+
+
+
Cuidado: use o corpo cru (raw body) na verificação — em Express, express.text(), não express.json(). Sem isso, a assinatura não confere.
+ + +
+ +
+

15. Prompt caching

+

O Prompt Caching roteia requisições para servidores que processaram recentemente o mesmo prefixo, reduzindo latência em até ~80% e custo de tokens de entrada em até ~90%. É automático (sem mudança de código, sem custo extra) para prompts de 1024 tokens ou mais, e os hits aparecem em usage.input_tokens_details.cached_tokens na Responses API (ou usage.prompt_tokens_details.cached_tokens em Chat Completions); prompts abaixo de 1024 tokens sempre reportam cached_tokens igual a 0.

+ +

15.1 Estruturando para cache

+

Cache hits exigem prefixo idêntico. Coloque conteúdo estático (instruções, exemplos, schema, tools, imagens) no início do prompt e o conteúdo variável (dados do usuário) no fim. Pode ser cacheado: o array de mensagens completo, imagens (com detail idêntico), o array tools, e o schema de Structured Outputs.

+ +

15.2 prompt_cache_key e retenção

+

Para tráfego repetido com prefixos comuns, use prompt_cache_key de forma consistente: ele é combinado ao hash do prefixo para melhorar o roteamento e a taxa de acerto. Mantenha cada par prefixo+chave abaixo de ~15 requisições por minuto para evitar overflow. Monitore usage.input_tokens_details.cached_tokens na Responses API (em Chat Completions, usage.prompt_tokens_details.cached_tokens).

+
{
+  "model": "gpt-5.5",
+  "input": "...",
+  "prompt_cache_key": "checkout-v3",
+  "prompt_cache_retention": "24h"
+}
+

O parâmetro prompt_cache_retention aceita in_memory (cache em memória volátil, 5–10 min de inatividade até ~1h) e 24h (retenção estendida, até 24h, descarregando tensores key/value para storage GPU-local). Desde 2026-05-29, o padrão é 24h para organizações sem ZDR (Zero Data Retention) em todos os modelos elegíveis de v1/responses, v1/chat/completions e v1/batch — antes, a maioria dos modelos usava in_memory por padrão. Para gpt-5.5 e modelos futuros o padrão já era 24h e in_memory segue não suportado.

+
Nota: caches não são compartilhados entre organizações; o caching não altera a saída gerada (só o prefixo é cacheado, a resposta é recalculada) nem isenta tokens dos limites de TPM. Não há limpeza manual de cache.
+ + +
+ +
+

16. Contagem de tokens (texto)

+

Tokens são a unidade de medida de entrada e saída. A janela de contexto é o total máximo de tokens por requisição, incluindo input, output e reasoning. Estouros podem truncar a saída — confira a janela na página de cada modelo.

+ +

16.1 Como contar

+

Para texto puro, use o tiktoken ou a ferramenta de tokenizer da plataforma. Para entradas que incluem imagens, arquivos, tools ou conversas, estimativas locais (tipo caracteres / 4) são imprecisas — use o endpoint de contagem de tokens de entrada, que aceita o mesmo payload da Responses API e devolve a contagem exata que o modelo receberá.

+
POST /v1/responses/input_tokens
+# Resposta: { "object": "response.input_tokens", "input_tokens": 1234 }
+
+
+ + +
+
+
count = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    input=[{"role": "user", "content": "Quantos tokens isto usa?"}],
+)
+print(count.input_tokens)
+
+
+
const count = await client.responses.inputTokens.count({
+  model: "gpt-5.5",
+  input: [{ role: "user", content: "Quantos tokens isto usa?" }],
+});
+console.log(count.input_tokens);
+
+
+ +

16.2 Otimização e custos

+

Após a chamada, o objeto usage reporta o consumo real: input_tokens (com cached_tokens em input_tokens_details), output_tokens (com reasoning_tokens em output_tokens_details) e total_tokens. Os tokens de raciocínio são cobrados como saída. Para controlar custo, limite a geração com max_output_tokens, reduza o número de funções carregadas (ou use tool search) e aproveite o prompt caching.

+
Dica: use a contagem prévia de tokens para validar tamanho antes de enviar, estimar custo e rotear por tamanho (prompts menores para modelos mais rápidos como gpt-5.4-mini/gpt-5.4-nano).
+ + +
+ +

Parte B — Imagem & Visão

Geração e edição de imagens com gpt-image-2, entrada de imagens (visão) na Responses API e como a tokenização de imagem afeta custos.

+ +
+

17. Geração de imagens (gpt-image-2)

+

+ O modelo de geração de imagens atual e estado da arte é o gpt-image-2 (snapshot fixável + gpt-image-2-2026-04-21): ele entende texto e imagens, usa conhecimento de mundo para criar cenas + realistas e tem forte aderência a instruções. Esse é o ID confirmado na página oficial de modelos e no guia de + geração de imagens. Há dois caminhos para gerar imagens: +

+
+ + + + + + + + + + + + + + +
CaminhoQuando usarModelo no campo model
Image API
/v1/images/generations
Gerar/editar uma imagem a partir de um único prompt, sem conversa.gpt-image-2 (modelo de imagem direto)
Responses API
tool image_generation
Experiências conversacionais e multi-turno, com edição iterativa e entrada de imagens por file_id.Um modelo mainline com texto (ex.: gpt-5.5) que chama a tool — o GPT Image roda por baixo.
+
+ +
Nota: na Responses API, o valor de model é sempre um modelo de texto (por exemplo gpt-5.5) com a tool image_generation habilitada — gpt-image-2 não é um valor válido em model nesse fluxo. Na Image API, ao contrário, você passa gpt-image-2 diretamente em model.
+ +
Atenção: antes de usar GPT Image (incluindo gpt-image-2) sua organização pode precisar concluir a API Organization Verification no console de desenvolvedor.
+ +
Nota — referência de API desatualizada: alguns exemplos na API Reference de /v1/images ainda mostram um ID de modelo de imagem anterior no campo model. Isso é apenas texto de exemplo desatualizado — o ID canônico e recomendado para geração e edição é gpt-image-2.
+ +
Nota — família de modelos de imagem (2026-06-25): além do gpt-image-2, estão disponíveis: gpt-image-1-mini (otimizado para custo e throughput — ideal para lotes, prototipagem e rascunhos), gpt-image-1.5 (transição) e gpt-image-1 (legado — sunset 2026-10-23, migre para gpt-image-2). Para novos projetos, prefira sempre gpt-image-2. Fonte: developers.openai.com/api/docs/deprecations.
+ +

17.1 Gerar e salvar a imagem

+

+ Os dois caminhos retornam a imagem em base64. Na Image API o conteúdo vem em + result.data[0].b64_json; na Responses API ele aparece no item de saída do tipo + image_generation_call, no campo result. Decodifique o base64 e grave os bytes em disco. +

+ +
+
+ + + +
+
+
from openai import OpenAI
+import base64
+
+client = OpenAI()
+
+# Caminho 1 — Image API (modelo de imagem direto)
+result = client.images.generate(
+    model="gpt-image-2",
+    prompt="Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
+    size="1024x1024",
+    quality="high",
+)
+image_bytes = base64.b64decode(result.data[0].b64_json)
+with open("gato_lontra.png", "wb") as f:
+    f.write(image_bytes)
+
+# Caminho 2 — Responses API (tool image_generation; modelo mainline)
+response = client.responses.create(
+    model="gpt-5.5",
+    input="Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
+    tools=[{"type": "image_generation"}],
+)
+image_data = [
+    out.result
+    for out in response.output
+    if out.type == "image_generation_call"
+]
+if image_data:
+    with open("gato_lontra_resp.png", "wb") as f:
+        f.write(base64.b64decode(image_data[0]))
+
+
+
import OpenAI from "openai";
+import fs from "fs";
+
+const client = new OpenAI();
+
+// Caminho 1 — Image API
+const result = await client.images.generate({
+  model: "gpt-image-2",
+  prompt: "Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
+  size: "1024x1024",
+  quality: "high",
+});
+fs.writeFileSync("gato_lontra.png", Buffer.from(result.data[0].b64_json, "base64"));
+
+// Caminho 2 — Responses API (tool image_generation)
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
+  tools: [{ type: "image_generation" }],
+});
+const imageData = response.output
+  .filter((o) => o.type === "image_generation_call")
+  .map((o) => o.result);
+if (imageData.length > 0) {
+  fs.writeFileSync("gato_lontra_resp.png", Buffer.from(imageData[0], "base64"));
+}
+
+
+
curl -X POST "https://api.openai.com/v1/images/generations" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "gpt-image-2",
+    "prompt": "Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
+    "n": 1,
+    "size": "1024x1024",
+    "quality": "high"
+  }' | jq -r '.data[0].b64_json' | base64 --decode > gato_lontra.png
+
+
+ +
Nota: a resposta inclui usage com input_tokens, output_tokens e total_tokens (mais input_tokens_details separando text_tokens de image_tokens). Use esses campos para medir custo real — ver a seção 20.
+ +

17.2 Parâmetros de saída

+

Tanto a Image API quanto a tool da Responses API aceitam as mesmas opções de saída:

+
+ + + + + + + + + + + + + + +
ParâmetroValoresDescrição
promptstringDescrição da imagem desejada.
size1024x1024, 1536x1024, 1024x1536, 2048x2048, 3840x2160, … ou autoDimensões. O gpt-image-2 aceita resoluções flexíveis dentro das restrições da seção 17.3. auto deixa o modelo escolher.
qualitylow, medium, high, auto padrão: autolow é o mais rápido (rascunhos, miniaturas); suba para medium/high nos finais.
backgroundopaque, autoFundo opaco ou automático. O gpt-image-2 não suporta fundo transparente; background: "transparent" falha.
output_format / formatopng (padrão), jpeg, webpFormato do arquivo de saída. jpeg é mais rápido que png — prefira-o se latência importa.
output_compression0–100Nível de compressão para jpeg/webp. Ex.: 50 comprime ~50%.
ninteiroNúmero de imagens por requisição (padrão 1).
moderationauto (padrão), lowRigor de moderação de conteúdo. low é menos restritivo.
partial_images0–3Quantas imagens parciais receber em streaming (ver 17.4).
action toolauto (padrão), generate, editSó na tool da Responses API: força gerar nova imagem ou editar uma já no contexto.
+
+
Dica: na Responses API você força a chamada da tool com tool_choice = {"type": "image_generation"}. As opções de saída acima entram dentro do objeto da tool, ex.: tools=[{"type": "image_generation", "quality": "high", "partial_images": 2}].
+ +

17.3 Resoluções suportadas e prompt revisado

+

O gpt-image-2 aceita milhares de resoluções, desde que respeitem:

+
+ + + + + + + + +
Restrição de sizeRegra
Borda máximaLado mais longo ≤ 3840px
MúltiploAmbos os lados múltiplos de 16px
ProporçãoRazão lado longo : lado curto ≤ 3:1
Pixels totais≥ 655.360 e ≤ 8.294.400
+
+

+ Saídas acima de 2560x1440 (~3,69 MP, o "2K") são consideradas experimentais. + Imagens quadradas costumam ser as mais rápidas de gerar. +

+

+ Ao usar a tool na Responses API, o modelo mainline (ex.: gpt-5.5) reescreve automaticamente seu prompt + para melhorar o resultado. Você lê o texto final em revised_prompt dentro do image_generation_call: +

+
{
+  "id": "ig_123",
+  "type": "image_generation_call",
+  "status": "completed",
+  "revised_prompt": "A gray tabby cat hugging an otter wearing an orange scarf...",
+  "result": "...base64..."
+}
+ +

17.4 Streaming de imagens parciais

+

+ Para feedback visual mais rápido, ative partial_images (1–3). Com 0 você recebe apenas a imagem final; + com valores maiores você pode receber menos parciais do que pediu, caso a imagem fique pronta antes. +

+
+
+ + + +
+
+
from openai import OpenAI
+import base64
+
+client = OpenAI()
+
+# Image API: evento image_generation.partial_image / b64_json
+stream = client.images.generate(
+    model="gpt-image-2",
+    prompt="Um rio feito de penas brancas de coruja serpenteando por uma paisagem de inverno",
+    stream=True,
+    partial_images=2,
+)
+for event in stream:
+    if event.type == "image_generation.partial_image":
+        idx = event.partial_image_index
+        with open(f"rio_{idx}.png", "wb") as f:
+            f.write(base64.b64decode(event.b64_json))
+
+# Responses API: evento response.image_generation_call.partial_image / partial_image_b64
+resp_stream = client.responses.create(
+    model="gpt-5.5",
+    input="Desenhe um rio feito de penas brancas de coruja numa paisagem de inverno serena",
+    stream=True,
+    tools=[{"type": "image_generation", "partial_images": 2}],
+)
+for event in resp_stream:
+    if event.type == "response.image_generation_call.partial_image":
+        idx = event.partial_image_index
+        with open(f"rio_resp_{idx}.png", "wb") as f:
+            f.write(base64.b64decode(event.partial_image_b64))
+
+
+
import OpenAI from "openai";
+import fs from "fs";
+
+const client = new OpenAI();
+
+// Image API
+const stream = await client.images.generate({
+  model: "gpt-image-2",
+  prompt: "Um rio feito de penas brancas de coruja numa paisagem de inverno",
+  stream: true,
+  partial_images: 2,
+});
+for await (const event of stream) {
+  if (event.type === "image_generation.partial_image") {
+    const idx = event.partial_image_index;
+    fs.writeFileSync(`rio_${idx}.png`, Buffer.from(event.b64_json, "base64"));
+  }
+}
+
+// Responses API
+const respStream = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Desenhe um rio feito de penas brancas de coruja numa paisagem de inverno",
+  stream: true,
+  tools: [{ type: "image_generation", partial_images: 2 }],
+});
+for await (const event of respStream) {
+  if (event.type === "response.image_generation_call.partial_image") {
+    const idx = event.partial_image_index;
+    fs.writeFileSync(`rio_resp_${idx}.png`, Buffer.from(event.partial_image_b64, "base64"));
+  }
+}
+
+
+
curl -s -N -X POST "https://api.openai.com/v1/images/generations" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "gpt-image-2",
+    "prompt": "Um rio feito de penas brancas de coruja numa paisagem de inverno",
+    "size": "1024x1024",
+    "stream": true,
+    "partial_images": 2
+  }'
+# Eventos SSE: image_generation.partial_image (com b64_json e partial_image_index)
+# e image_generation.completed (com b64_json final e usage)
+
+
+
Atenção: cada imagem parcial em streaming custa +100 tokens de imagem de saída. Use partial_images com parcimônia em produção de alto volume.
+ +
Nota — proveniência: a OpenAI declara, fora da referência de API, que imagens geradas por GPT Image carregam metadados de proveniência no padrão C2PA. A referência de API consultada não documenta esse comportamento, então trate o detalhe como UNVERIFIED e não dependa dele em fluxos críticos sem confirmar na documentação atual.
+ + +
+ +
+

18. Edição & inpainting

+

+ O endpoint de edições (/v1/images/edits) e a tool image_generation na Responses API permitem três coisas: + editar uma imagem existente, gerar uma nova usando outras como referência, e substituir uma região específica via máscara (inpainting). +

+ +

18.1 Editar e combinar imagens de referência

+

+ Passe uma ou mais imagens de entrada. Com várias referências, o modelo combina os elementos no resultado. + Na Image API você envia os bytes (multipart/form-data); na Responses API você pode referenciar por + file_id da Files API. +

+
+
+ + + +
+
+
from openai import OpenAI
+import base64
+
+client = OpenAI()
+
+prompt = (
+    "Gere uma imagem fotorrealista de uma cesta de presentes em fundo branco, "
+    "rotulada 'Relax & Unwind', contendo todos os itens das imagens de referência."
+)
+
+result = client.images.edit(
+    model="gpt-image-2",
+    image=[
+        open("body-lotion.png", "rb"),
+        open("bath-bomb.png", "rb"),
+        open("incense-kit.png", "rb"),
+        open("soap.png", "rb"),
+    ],
+    prompt=prompt,
+)
+with open("cesta.png", "wb") as f:
+    f.write(base64.b64decode(result.data[0].b64_json))
+
+
+
import fs from "fs";
+import OpenAI, { toFile } from "openai";
+
+const client = new OpenAI();
+
+const files = ["bath-bomb.png", "body-lotion.png", "incense-kit.png", "soap.png"];
+const images = await Promise.all(
+  files.map((file) => toFile(fs.createReadStream(file), null, { type: "image/png" }))
+);
+
+const response = await client.images.edit({
+  model: "gpt-image-2",
+  image: images,
+  prompt: "Gere uma cesta de presentes fotorrealista em fundo branco com todos os itens das referências.",
+});
+fs.writeFileSync("cesta.png", Buffer.from(response.data[0].b64_json, "base64"));
+
+
+
curl -s -X POST "https://api.openai.com/v1/images/edits" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -F "model=gpt-image-2" \
+  -F "image[]=@body-lotion.png" \
+  -F "image[]=@bath-bomb.png" \
+  -F "image[]=@incense-kit.png" \
+  -F "image[]=@soap.png" \
+  -F 'prompt=Gere uma cesta de presentes fotorrealista em fundo branco com todos os itens das referências' \
+  | jq -r '.data[0].b64_json' | base64 --decode > cesta.png
+
+
+
Dica: a geração funciona melhor com verbos como desenhe ou edite. Para combinar imagens, em vez de "combine" ou "mescle", peça algo como "edite a primeira imagem adicionando este elemento da segunda imagem".
+ +

18.2 Inpainting com máscara

+

+ A máscara indica qual região da imagem deve ser substituída. Na Image API, passe mask junto com image; + na Responses API, use input_image_mask dentro da tool, apontando para o file_id da máscara. + Se você fornecer várias imagens de entrada, a máscara é aplicada à primeira. +

+
Nota: o mascaramento no GPT Image é guiado por prompt. O modelo usa a máscara como orientação, mas pode não seguir o contorno exato com precisão absoluta.
+
+
+ + + +
+
+
from openai import OpenAI
+import base64
+
+client = OpenAI()
+
+# Image API: image + mask (mesmo formato/tamanho; máscara com canal alfa)
+result = client.images.edit(
+    model="gpt-image-2",
+    image=open("sunlit_lounge.png", "rb"),
+    mask=open("mask.png", "rb"),
+    prompt="Uma sala de estar iluminada pelo sol com uma piscina contendo um flamingo",
+)
+with open("lounge.png", "wb") as f:
+    f.write(base64.b64decode(result.data[0].b64_json))
+
+# Responses API: input_image_mask por file_id, dentro da tool
+file_id = create_file("sunlit_lounge.png")  # purpose="vision"
+mask_id = create_file("mask.png")
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "Mesma sala iluminada, mas a piscina deve conter um flamingo"},
+            {"type": "input_image", "file_id": file_id},
+        ],
+    }],
+    tools=[{
+        "type": "image_generation",
+        "quality": "high",
+        "input_image_mask": {"file_id": mask_id},
+    }],
+)
+data = [o.result for o in response.output if o.type == "image_generation_call"]
+if data:
+    with open("lounge_resp.png", "wb") as f:
+        f.write(base64.b64decode(data[0]))
+
+
+
import fs from "fs";
+import OpenAI, { toFile } from "openai";
+
+const client = new OpenAI();
+
+// Image API
+const rsp = await client.images.edit({
+  model: "gpt-image-2",
+  image: await toFile(fs.createReadStream("sunlit_lounge.png"), null, { type: "image/png" }),
+  mask: await toFile(fs.createReadStream("mask.png"), null, { type: "image/png" }),
+  prompt: "Uma sala iluminada pelo sol com uma piscina contendo um flamingo",
+});
+fs.writeFileSync("lounge.png", Buffer.from(rsp.data[0].b64_json, "base64"));
+
+// Responses API com input_image_mask
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "Mesma sala iluminada, mas a piscina deve conter um flamingo" },
+      { type: "input_image", file_id: fileId },
+    ],
+  }],
+  tools: [{ type: "image_generation", quality: "high", input_image_mask: { file_id: maskId } }],
+});
+
+
+
curl -s -X POST "https://api.openai.com/v1/images/edits" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -F "model=gpt-image-2" \
+  -F "image[]=@sunlit_lounge.png" \
+  -F "mask=@mask.png" \
+  -F 'prompt=Uma sala iluminada pelo sol com uma piscina contendo um flamingo' \
+  | jq -r '.data[0].b64_json' | base64 --decode > lounge.png
+
+
+ +

Requisitos da máscara

+
    +
  • A imagem a editar e a máscara devem ter o mesmo formato e tamanho (cada uma com menos de 50 MB).
  • +
  • A máscara precisa ter um canal alfa — a transparência define a área a substituir. Salve a máscara preservando o alfa.
  • +
  • É possível converter uma máscara preto e branco em RGBA por código, usando a própria máscara para preencher o canal alfa:
  • +
+
from PIL import Image
+from io import BytesIO
+
+mask = Image.open("mask_pb.png").convert("L")   # 1. carrega como tons de cinza
+mask_rgba = mask.convert("RGBA")                  # 2. espaço para canal alfa
+mask_rgba.putalpha(mask)                          # 3. usa a própria máscara como alfa
+
+buf = BytesIO()
+mask_rgba.save(buf, format="PNG")                 # 4. serializa em PNG
+with open("mask_alpha.png", "wb") as f:           # 5. salva
+    f.write(buf.getvalue())
+ +

18.3 input_fidelity e edição multi-turno

+

+ O parâmetro input_fidelity controla quão fortemente o modelo preserva os detalhes das imagens de entrada + durante edições e fluxos com referência. Para gpt-image-2, omita esse parâmetro: a API não + permite alterá-lo porque o modelo já processa toda imagem de entrada em alta fidelidade automaticamente. +

+
Atenção: como o gpt-image-2 sempre trata entradas em alta fidelidade, requisições de edição que incluem imagens de referência podem consumir mais tokens de imagem de entrada. Considere isso no custo (seção 20).
+

+ Na Responses API a edição é naturalmente multi-turno: você continua a conversa referenciando o + previous_response_id ou reinjetando o item image_generation_call (pelo id) num turno seguinte. + Use action: "edit" para forçar edição de uma imagem já no contexto (forçar edit sem imagem em contexto retorna erro); + action: "generate" força criar uma nova; auto deixa o modelo decidir. +

+
from openai import OpenAI
+client = OpenAI()
+
+# Turno 1 — gera
+r1 = client.responses.create(
+    model="gpt-5.5",
+    input="Gere um gato tabby cinza abraçando uma lontra com cachecol laranja",
+    tools=[{"type": "image_generation"}],
+)
+
+# Turno 2 — refina referenciando o turno anterior
+r2 = client.responses.create(
+    model="gpt-5.5",
+    previous_response_id=r1.id,
+    input="Agora deixe a imagem realista",
+    tools=[{"type": "image_generation"}],
+)
+ + +
+ +
+

19. Visão (entrada de imagens)

+

+ Visão é a capacidade do modelo de "enxergar" e entender imagens — objetos, formas, cores, texturas e até + texto contido nelas. Na Responses API você envia imagens como conteúdo do tipo input_image, ao lado de + input_text, dentro de uma mensagem de usuário. +

+ +

19.1 Três formas de passar a imagem

+
+ + + + + + + +
FormaCampo em input_imageQuando usar
URL públicaimage_url (URL http(s))Imagem já hospedada e acessível publicamente.
Base64 (data URL)image_url com data:image/jpeg;base64,...Imagem local, sem upload prévio; embute os bytes na requisição.
File IDfile_idImagem enviada à Files API (purpose="vision"), reutilizável entre chamadas.
+
+

Você pode passar várias imagens na mesma requisição, incluindo múltiplos itens input_image no array content — lembrando que cada imagem conta como tokens (seção 20).

+ +
+
+ + + +
+
+
from openai import OpenAI
+import base64
+
+client = OpenAI()
+
+def encode_image(path):
+    with open(path, "rb") as f:
+        return base64.b64encode(f.read()).decode("utf-8")
+
+b64 = encode_image("foto.jpg")
+
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "O que há nestas imagens? Compare-as."},
+            # 1) por URL pública
+            {"type": "input_image",
+             "image_url": "https://exemplo.com/imagem.jpg",
+             "detail": "high"},
+            # 2) por base64 (data URL)
+            {"type": "input_image",
+             "image_url": f"data:image/jpeg;base64,{b64}"},
+            # 3) por file_id (Files API, purpose="vision")
+            {"type": "input_image", "file_id": "file-abc123", "detail": "auto"},
+        ],
+    }],
+)
+print(response.output_text)
+
+
+
import fs from "fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+const b64 = fs.readFileSync("foto.jpg", "base64");
+
+const response = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "O que há nestas imagens? Compare-as." },
+      { type: "input_image", image_url: "https://exemplo.com/imagem.jpg", detail: "high" },
+      { type: "input_image", image_url: `data:image/jpeg;base64,${b64}` },
+      { type: "input_image", file_id: "file-abc123", detail: "auto" },
+    ],
+  }],
+});
+console.log(response.output_text);
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": [
+      {
+        "role": "user",
+        "content": [
+          {"type": "input_text", "text": "O que há nesta imagem?"},
+          {
+            "type": "input_image",
+            "image_url": "https://exemplo.com/imagem.jpg",
+            "detail": "high"
+          }
+        ]
+      }
+    ]
+  }'
+
+
+
Dica: para subir a imagem à Files API antes de usar por file_id, crie o arquivo com client.files.create(file=open("foto.jpg","rb"), purpose="vision") e use o id retornado.
+ +

19.2 Nível de detalhe (detail)

+

+ O parâmetro detail diz ao modelo o nível de detalhe ao processar a imagem. Vale tanto na Responses API quanto na Chat Completions. + Se omitido, o padrão é auto. No gpt-5.5, auto e o comportamento padrão omitido equivalem a original. +

+
+ + + + + + + + +
NívelMelhor para
lowEntendimento rápido e barato quando o detalhe fino não importa. O modelo recebe uma versão de 512px × 512px.
highCompreensão de alta fidelidade padrão.
originalImagens grandes, densas, espacialmente sensíveis ou de uso de computador. Disponível em gpt-5.4 e modelos futuros.
autoSeleção automática. No gpt-5.5, equivale a original.
+
+

Para uso de computador, localização e precisão de clique nos modelos gpt-5.4 e futuros, recomenda-se "detail": "original".

+ +
Dica — detail ≠ raciocínio: detail resolve percepção (deixar a imagem legível). Depois que a imagem está legível, o gargalo costuma ser raciocínio, não percepção — jogar detail: "original" numa falha de raciocínio não ajuda. Para gráficos, tabelas, plantas e leitura composicional, aumente reasoning.effort (ex.: reasoning={"effort": "high"}) em vez de só subir o detail.
+ +

19.3 Requisitos da imagem e comportamento de redimensionamento

+
+ + + + + + + + +
RequisitoValor
Formatos suportadosPNG (.png), JPEG (.jpeg/.jpg), WEBP (.webp), GIF não animado (.gif)
Tamanho do payloadAté 512 MB de payload total por requisição
QuantidadeAté 1.500 imagens individuais por requisição
OutrosSem marcas d'água/logos, sem conteúdo NSFW, nítida o bastante para um humano entender
+
+

+ Modelos diferentes redimensionam antes de tokenizar. Em gpt-5.5 e gpt-5.4: high permite até + 2.500 patches ou dimensão máxima de 2048px; original permite até 10.000 patches ou 6000px. + Se algum limite é excedido, a imagem é reduzida preservando a proporção até caber. Em gpt-5.4-mini e gpt-5.4-nano, + high permite até 1.536 patches ou 2048px (sem original). Detalhes da matemática na seção 20. +

+
Nota — limitações conhecidas de visão: imagens médicas especializadas (ex.: tomografias) não são adequadas; texto em alfabetos não latinos pode ter desempenho menor; texto pequeno deve ser ampliado (e "detail": "original" ajuda); imagens rotacionadas, panorâmicas ou olho-de-peixe confundem o modelo; contagens podem ser aproximadas; metadados e nomes de arquivo não são processados; e CAPTCHAs são bloqueados por segurança.
+ +

19.4 Entradas de arquivo (input_file): PDF, documentos e planilhas

+

Além de imagens, a Responses API aceita arquivos como itens de conteúdo do tipo input_file — passados de três formas: URL externa (file_url), ID da Files API (file_id, após upload com purpose="user_data") ou base64 (file_data + filename). É o caminho para Q&A direto sobre um documento, sem montar um pipeline de RAG.

+
+
+ + +
+
+
from openai import OpenAI
+client = OpenAI()
+
+# (a) Arquivo por URL externa — sem upload
+resp = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "Resuma os pontos-chave deste relatório."},
+            {"type": "input_file", "file_url": "https://exemplo.com/relatorio.pdf"},
+        ],
+    }],
+)
+print(resp.output_text)
+
+# (b) Upload pela Files API e referência por file_id
+f = client.files.create(file=open("contrato.pdf", "rb"), purpose="user_data")
+resp = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_file", "file_id": f.id},
+            {"type": "input_text", "text": "Quais são as cláusulas de rescisão?"},
+        ],
+    }],
+)
+print(resp.output_text)
+
+
+
import OpenAI from "openai";
+import fs from "fs";
+const client = new OpenAI();
+
+// (a) Arquivo por URL externa — sem upload
+let resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "Resuma os pontos-chave deste relatório." },
+      { type: "input_file", file_url: "https://exemplo.com/relatorio.pdf" },
+    ],
+  }],
+});
+console.log(resp.output_text);
+
+// (b) Upload pela Files API e referência por file_id
+const f = await client.files.create({
+  file: fs.createReadStream("contrato.pdf"),
+  purpose: "user_data",
+});
+resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_file", file_id: f.id },
+      { type: "input_text", text: "Quais são as cláusulas de rescisão?" },
+    ],
+  }],
+});
+console.log(resp.output_text);
+
+
+
Como cada tipo é processado: PDF — o modelo recebe o texto extraído e uma imagem de cada página (importa para layout/diagramas), então PDFs consomem mais tokens; documentos de texto (.txt/.md/.docx/.pptx/.html) — só o texto; planilhas (.csv/.xlsx) — augmentação específica que lê as primeiras 1.000 linhas. Para arquivos grandes ou muitos documentos, prefira File Search (RAG) em vez de despejar tudo como input_file.
+ + +
+ +
+

20. Tokenização & custos de imagem

+

+ Imagens de entrada são medidas e cobradas em tokens, como o texto, e contam para o limite de tokens por minuto (TPM). + A forma de converter pixels em tokens depende da geração do modelo: os modelos gpt-5.x atuais usam o método + patch-based (por blocos de 32px); as gerações anteriores usavam o + método tile-based. Apresentamos o patch como principal e o tile apenas como nota de cálculo/migração. +

+ +

20.1 Patch-based (método atual)

+

+ O modelo cobre a imagem com patches de 32px × 32px e define um orçamento máximo de patches. O custo em tokens segue 4 passos: +

+

A. Conte quantos patches de 32px cobrem a imagem original (um patch pode ultrapassar a borda):

+
original_patch_count = ceil(width / 32) * ceil(height / 32)
+

B. Se exceder o orçamento de patches do modelo, reduza proporcionalmente até caber, ajustando a escala para que as dimensões inteiras finais permaneçam dentro do orçamento:

+
shrink_factor = sqrt((32**2 * patch_budget) / (width * height))
+adjusted_shrink_factor = shrink_factor * min(
+    floor(width  * shrink_factor / 32) / (width  * shrink_factor / 32),
+    floor(height * shrink_factor / 32) / (height * shrink_factor / 32),
+)
+

C. Converta a escala ajustada em pixels inteiros e reconte os patches. Esse é o número de tokens de imagem antes do multiplicador, limitado pelo orçamento:

+
resized_patch_count = ceil(resized_width / 32) * ceil(resized_height / 32)
+

D. Aplique o multiplicador do modelo para obter os tokens finais:

+
+ + + + + + +
ModeloMultiplicador
gpt-5.4-mini1.62
gpt-5.4-nano2.46
+
+
Nota — gpt-5.5: o gpt-5.5 (frontier) não aparece na tabela de multiplicadores acima, o que significa multiplicador efetivo de ×1,0 — a contagem de patches já é a contagem de tokens de imagem. Seu orçamento de patches por nível de detalhe é maior: high = 2.500 patches (ou 2048px); original = 10.000 patches (ou 6000px); auto e o detalhe omitido equivalem a original. Para gpt-5.4-mini/gpt-5.4-nano, high = 1.536 patches.
+ +

Exemplo (orçamento de 1.536 patches)

+
    +
  • Imagem 1024 × 1024: ceil(1024/32) × ceil(1024/32) = 32 × 32 = 1024 patches. Está abaixo de 1.536, então não há redimensionamento. Tokens antes do multiplicador = 1024.
  • +
  • Imagem 1800 × 2400: original = 57 × 75 = 4275 patches (excede 1.536). shrink_factor ≈ 0,603 → adjusted ≈ 0,586 → redimensiona para 1056 × 1408 → 33 × 44 = 1452 patches. Tokens antes do multiplicador = 1452.
  • +
+

Em ambos, multiplique o resultado pelo fator do modelo (tabela acima) para obter as unidades de token cobradas.

+ +

20.2 Tile-based (legado)

+

+ Nas gerações anteriores ao gpt-5.x, o custo dependia de tamanho e detail — nenhum modelo SOTA atual + usa este método, mantido aqui apenas como referência de migração. + Com detail: "low" o custo era um número-base fixo de tokens. Com detail: "high": +

+
    +
  1. Escala para caber num quadrado de 2048px × 2048px, mantendo a proporção.
  2. +
  3. Escala para que o menor lado fique com 768px.
  4. +
  5. Conta os quadrados de 512px; cada quadrado custava um valor fixo de tokens.
  6. +
  7. Soma os tokens-base ao total: tokens = base + (tokens_por_tile × nº de tiles).
  8. +
+
Nota: os valores de tokens-base e tokens por tile variavam por geração de modelo legado e não se aplicam a nenhum modelo atual. O método patch-based dos modelos gpt-5.x substitui inteiramente essa contagem por tiles; consulte a calculadora oficial para qualquer integração ativa.
+ +

20.3 Custo de saída do gpt-image-2

+

+ Para o gpt-image-2, o custo de saída depende de quality e size. Como ele aceita milhares de + resoluções, o caminho recomendado é estimar os tokens de saída pela calculadora oficial (a partir de + quality + size); a tabela abaixo lista os tamanhos clássicos confirmados, para comparação. O custo total de + uma requisição é a soma de: tokens de texto de entrada + tokens de imagem de entrada (se editando referências) + + tokens de imagem de saída. +

+
+ + + + + + + +
Qualidade1024×10241024×15361536×1024
LowUS$ 0,006US$ 0,005US$ 0,005
MediumUS$ 0,053US$ 0,041US$ 0,041
HighUS$ 0,211US$ 0,165US$ 0,165
+
+
Dica: uma resolução não quadrada maior às vezes gera menos tokens de saída do que uma menor/quadrada na mesma qualidade. E cada imagem parcial em streaming adiciona +100 tokens de saída.
+
Atenção — entradas em edição: como o gpt-image-2 processa toda imagem de entrada em alta fidelidade, edições com referências consomem mais tokens de imagem de entrada. Inclua isso ao estimar o custo. Preços são perecíveis — confirme sempre na calculadora e na página de preços oficiais.
+ +

20.4 Receitas e exemplos oficiais (Cookbook)

+

+ O OpenAI Cookbook traz receitas práticas de imagem e visão. Use as marcadas como atual como + referência: elas já usam gpt-image-2 para geração/edição e visão gpt-5.x pela Responses API. + Algumas receitas mais antigas continuam no ar com stack legado (modelos de imagem anteriores, + visão por Chat Completions); para essas, prefira o equivalente moderno indicado. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReceitaO que ensinaStatus
GPT Image Models Prompting GuidePrompting de geração e edição com gpt-image-2 (estrutura cena→sujeito→detalhes→constraints, texto na imagem, multi-imagem por índice, iteração).atual
Document & Multimodal Understanding TipsVisão de documentos com gpt-5.4 na Responses API: detail="original", reasoning.effort, bounding boxes em grade 0–999, code_interpreter para crop/zoom.atual
Grounded Spatial Reasoning & LayoutsRaciocínio espacial com gpt-5.5 + render gpt-image-2: separar semântica (modelo) de geometria (validação determinística); saída como spec JSON.atual
Image EvalsAvaliar imagem geradas com padrão Gate → Grade → Tag e juiz multimodal gpt-5.x via Responses API (gates hard pass/fail antes de pontuar; nunca usar média para contornar um gate).atual
Image Gen 1.5 Prompting GuidePrompting de geração em um modelo de imagem anterior. Equivalente moderno: trocar por gpt-image-2 e remover input_fidelity (no gpt-image-2 é automático).legado
GPT-4 Vision with Function CallingVisão + tool calling via Chat Completions e biblioteca externa. Equivalente moderno: Responses API com input_image nativo + tools de função + Structured Outputs, em modelo gpt-5.x.legado
Vision RAG com PineconeRAG sobre PDF com visão via Chat Completions. Equivalente moderno: Responses API com input_image/Files API nativo e visão gpt-5.x.legado
Custom Image Embedding SearchBusca por similaridade com embedding de imagem local + QA por um modelo de visão anterior. Equivalente moderno: visão gpt-5.x pela Responses API; não tratar como padrão atual.legado
+
+
Dica — padrão de edição que evita "drift": ao editar, descreva exatamente o que muda e o que permanece: "mude APENAS X; mantenha todo o resto exatamente igual" (rosto, pose, fundo, proporções). Repita a lista de preservação a cada iteração — isso reduz o desvio acumulado em edições multi-turno.
+ +

+ A seguir, três receitas mínimas em Python e JavaScript, fiéis aos exemplos oficiais da documentação: + geração de imagem, edição com máscara (inpainting) e visão. Todas usam gpt-image-2 para imagem e a Responses API + com input_image para visão — sem stacks legados e sem parâmetros inventados (no gpt-image-2, + input_fidelity é automático e não deve ser enviado). +

+ +

Receita 1 — Geração de imagem com gpt-image-2 · via tool image_generation (Responses API) ou images.generate · image-generation#generate-images

+
+
+ + +
+
+
from openai import OpenAI
+import base64
+
+client = OpenAI()
+
+# Caminho A — Responses API: tool image_generation no modelo mainline
+response = client.responses.create(
+    model="gpt-5.5",
+    input="Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
+    tools=[{"type": "image_generation"}],
+)
+
+# Coleta os resultados das chamadas de geração de imagem
+image_data = [
+    output.result
+    for output in response.output
+    if output.type == "image_generation_call"
+]
+
+if image_data:
+    image_base64 = image_data[0]
+    with open("lontra.png", "wb") as f:
+        f.write(base64.b64decode(image_base64))
+
+# Caminho B — Image API: modelo de imagem direto (retorna b64_json)
+result = client.images.generate(
+    model="gpt-image-2",
+    prompt="Desenho de livro infantil: um veterinario auscultando uma lontra bebe",
+)
+image_bytes = base64.b64decode(result.data[0].b64_json)
+with open("lontra_direto.png", "wb") as f:
+    f.write(image_bytes)
+
+
+
+
import OpenAI from "openai";
+import fs from "fs";
+
+const openai = new OpenAI();
+
+// Caminho A — Responses API: tool image_generation no modelo mainline
+const response = await openai.responses.create({
+  model: "gpt-5.5",
+  input: "Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
+  tools: [{ type: "image_generation" }],
+});
+
+// Coleta os resultados das chamadas de geração de imagem
+const imageData = response.output
+  .filter((output) => output.type === "image_generation_call")
+  .map((output) => output.result);
+
+if (imageData.length > 0) {
+  const imageBase64 = imageData[0];
+  fs.writeFileSync("lontra.png", Buffer.from(imageBase64, "base64"));
+}
+
+// Caminho B — Image API: modelo de imagem direto (retorna b64_json)
+const result = await openai.images.generate({
+  model: "gpt-image-2",
+  prompt: "Desenho de livro infantil: um veterinario auscultando uma lontra bebe",
+});
+const imageBytes = Buffer.from(result.data[0].b64_json, "base64");
+fs.writeFileSync("lontra_direto.png", imageBytes);
+
+
+
+ +

Receita 2 — Edição / inpainting com gpt-image-2 · images.edit com imagem + máscara (a máscara precisa de canal alfa) · image-generation#edit-images

+
+
+ + +
+
+
from openai import OpenAI
+import base64
+
+client = OpenAI()
+
+# A máscara marca a área a substituir; imagem e máscara devem ter
+# o mesmo formato e tamanho, e a máscara precisa de canal alfa.
+result = client.images.edit(
+    model="gpt-image-2",
+    image=open("sunlit_lounge.png", "rb"),
+    mask=open("mask.png", "rb"),
+    prompt="Uma sala de estar ensolarada com uma piscina contendo um flamingo",
+)
+
+image_bytes = base64.b64decode(result.data[0].b64_json)
+with open("lounge_editado.png", "wb") as f:
+    f.write(image_bytes)
+
+
+
+
import fs from "fs";
+import OpenAI, { toFile } from "openai";
+
+const client = new OpenAI();
+
+// A máscara marca a área a substituir; imagem e máscara devem ter
+// o mesmo formato e tamanho, e a máscara precisa de canal alfa.
+const rsp = await client.images.edit({
+  model: "gpt-image-2",
+  image: await toFile(fs.createReadStream("sunlit_lounge.png"), null, {
+    type: "image/png",
+  }),
+  mask: await toFile(fs.createReadStream("mask.png"), null, {
+    type: "image/png",
+  }),
+  prompt: "Uma sala de estar ensolarada com uma piscina contendo um flamingo",
+});
+
+const imageBytes = Buffer.from(rsp.data[0].b64_json, "base64");
+fs.writeFileSync("lounge_editado.png", imageBytes);
+
+
+
+ +

Receita 3 — Visão: analisar uma imagem com gpt-5.5 · Responses API com input_image (URL ou base64) · images-vision#analyze-images

+
+
+ + +
+
+
from openai import OpenAI
+import base64
+
+client = OpenAI()
+
+# Opção 1 — imagem por URL pública
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "O que há nesta imagem?"},
+            {
+                "type": "input_image",
+                "image_url": "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
+            },
+        ],
+    }],
+)
+print(response.output_text)
+
+# Opção 2 — imagem local em base64 (data URL)
+def encode_image(path):
+    with open(path, "rb") as f:
+        return base64.b64encode(f.read()).decode("utf-8")
+
+base64_image = encode_image("foto.jpg")
+response = client.responses.create(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "Descreva esta imagem."},
+            {
+                "type": "input_image",
+                "image_url": f"data:image/jpeg;base64,{base64_image}",
+            },
+        ],
+    }],
+)
+print(response.output_text)
+
+
+
+
import fs from "fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+
+// Opção 1 — imagem por URL pública
+const response = await openai.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "O que há nesta imagem?" },
+      {
+        type: "input_image",
+        image_url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
+      },
+    ],
+  }],
+});
+console.log(response.output_text);
+
+// Opção 2 — imagem local em base64 (data URL)
+const base64Image = fs.readFileSync("foto.jpg", "base64");
+const response2 = await openai.responses.create({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "Descreva esta imagem." },
+      {
+        type: "input_image",
+        image_url: `data:image/jpeg;base64,${base64Image}`,
+      },
+    ],
+  }],
+});
+console.log(response2.output_text);
+
+
+
+ + +
+ +

Parte C — Áudio & Realtime

Fala em tempo real (gpt-realtime-2), tradução e transcrição ao vivo, transcrição de arquivos (gpt-4o-transcribe), síntese de voz (gpt-4o-mini-tts) e áudio no chat (gpt-audio-1.5).

+ +
+

21. Visão geral de áudio

+

Os modelos de áudio da OpenAI sabem entender fala, gerar fala ou fazer as duas coisas na mesma interação. Antes de escrever código, vale fixar o vocabulário comum e, principalmente, decidir entre duas grandes arquiteturas: APIs baseadas em requisição (você envia um arquivo ou um texto e recebe uma resposta delimitada) e sessões em tempo real (uma conexão aberta por onde fluem áudio e eventos com baixa latência). Essa escolha define endpoint, transporte, modelo e complexidade do cliente.

+ +

21.1 Modalidades de áudio

+

Uma aplicação de áudio combina uma ou mais destas modalidades. Pense nelas como "peças" que você liga ou desliga conforme a tarefa.

+
+ + + + + + + + +
ModalidadeO que éUsos comuns
Entrada de áudioO modelo recebe som do usuário ou da aplicação.Agentes de voz, transcrição, tradução.
Saída de áudioO modelo ou a API devolve áudio falado.Agentes de voz, text-to-speech, respostas faladas.
Transcrição em textoA fala vira texto.Legendas, análise de chamadas, busca, registros.
Prompt de textoTexto controla o que o modelo diz ou faz.Geração de fala, fluxos de voz roteirizados, prompts.
+
+ +

21.2 Tarefas comuns de fala

+
    +
  • Speech-to-text (STT) — converte fala em texto. Para legendas, notas, transcrições, analytics, busca e acessibilidade. Pode ser baseada em requisição (arquivos) ou em streaming (áudio ao vivo).
  • +
  • Text-to-speech (TTS) — converte texto em áudio falado. Para narração, assistentes, acessibilidade e respostas geradas. A geração pode transmitir o áudio em streaming à medida que é produzido.
  • +
  • Speech-to-speech (S2S) — um único modelo escuta, raciocina e fala em uma sessão de baixa latência. Para agentes de voz conversacionais que respondem, chamam tools e mantêm estado de sessão.
  • +
  • Tradução de fala — escuta fala em um idioma e devolve áudio/transcrição traduzidos em outro idioma. Use uma sessão de tradução em tempo real quando a tradução deve começar continuamente conforme o áudio chega.
  • +
+ +

21.3 Streaming e latência

+

Streaming significa que cliente e serviço trocam entrada ou saída parcial enquanto a interação ainda está ativa — essencial quando o usuário espera feedback imediato (legendas ao vivo, chamadas, agentes de voz, tradução). Latência mais baixa exige uma conexão em tempo real, manejo cuidadoso de mídia e um modelo de sessão capaz de emitir eventos parciais. As APIs baseadas em requisição são mais simples para upload de arquivos e trabalho não interativo, mas não suportam os mesmos padrões de interação ao vivo.

+ +

21.4 APIs baseadas em requisição vs. sessões realtime

+

A OpenAI oferece três arquiteturas de áudio. Comece pelo resultado desejado e deixe ele escolher a arquitetura:

+
+ + + + + + + +
ArquiteturaUse quandoExemplos / endpoints
APIs de áudio por requisiçãoVocê tem um arquivo, um texto ou uma requisição delimitada.Speech-to-text (/v1/audio/transcriptions), text-to-speech (/v1/audio/speech).
Sessões em tempo realO áudio é ao vivo e o app precisa de eventos de baixa latência.Agentes de voz, tradução, transcrição — sobre /v1/realtime e endpoints irmãos.
Chat multimodalVocê está estendendo um fluxo de chat existente com áudio.Entrada/saída de áudio em Chat Completions com gpt-audio-1.5.
+
+ +

21.5 Escolha de modelo por tarefa

+

Cada tarefa de áudio tem um modelo recomendado. Esta tabela é o mapa de toda a Parte C — as seções seguintes detalham cada linha.

+
+ + + + + + + + + + + +
ObjetivoModeloOnde detalhar
Agente de voz de baixa latência (fala↔fala)gpt-realtime-2 realtimeSeções 22 e 28
Traduzir fala ao vivo para outro idiomagpt-realtime-translateSeção 23
Transcrever áudio ao vivo em texto contínuogpt-realtime-whisperSeção 24
Transcrever arquivos / requisições delimitadasgpt-4o-transcribe, gpt-4o-mini-transcribe, gpt-4o-transcribe-diarizeSeção 25
Tradução de áudio→inglês e timestamps/word-levelwhisper-1Seção 25
Gerar fala a partir de textogpt-4o-mini-ttsSeção 26
Adicionar áudio a um app de Chat Completionsgpt-audio-1.5Seção 27
+
+
Nota: gpt-realtime-2 e gpt-audio-1.5 são nativamente multimodais — entendem e geram áudio e texto como entrada e saída. A diferença prática é o transporte: gpt-realtime-2 vive em uma sessão de streaming bidirecional; gpt-audio-1.5 responde a uma requisição de chat delimitada.
+ + +
+ +
+

22. Realtime API (gpt-realtime-2)

+

A Realtime API mantém uma conexão aberta enquanto sua aplicação envia áudio, recebe eventos e atualiza o estado da sessão. O modelo principal é o gpt-realtime-2, o modelo de voz mais capaz da OpenAI: fala↔fala com reasoning effort configurável, melhor obediência a instruções e uso de tools mais confiável para fluxos de agente complexos. Para um modelo fala↔fala rápido e sem reasoning, há o gpt-realtime-1.5 (speech-to-speech rápido e confiável, sem reasoning; tem guia de prompting dedicado na doc oficial).

+ +
Dica: em produção, comece com reasoning.effort: "low" na maioria dos agentes de voz e suba só se a tarefa exigir — reasoning maior aumenta latência e tokens de saída.
+ +

22.1 Tipos de sessão realtime

+

Uma sessão em tempo real é uma interação stateful. Existem três tipos, cada um com um propósito distinto:

+
+ + + + + + + +
Tipo de sessãoUse quandoEndpoint / padrão
Sessão de agente de vozO modelo deve responder ao usuário, chamar tools e gerenciar o estado da conversa.Sessão de conversa em /v1/realtime
Sessão de traduçãoO app deve traduzir fala continuamente conforme chega.Sessão contínua em /v1/realtime/translations (Seção 23)
Sessão de transcriçãoO app precisa de deltas de transcrição sem resposta falada do modelo.Sessão type: "transcription" (Seção 24)
+
+

Esta seção foca na sessão de agente de voz (fala↔fala). Os componentes do estado são: o objeto Session (modelo, voz, configuração), a Conversation (itens de entrada do usuário e de saída do modelo) e as Responses (itens de áudio/texto gerados que entram na conversa). A duração máxima de uma sessão Realtime é de 60 minutos.

+ +

22.2 Transportes: WebRTC, WebSocket e SIP

+

Escolha o transporte pelo lugar onde sua aplicação captura e toca o áudio:

+
+ + + + + + + +
TransporteUse quandoCaracterística
WebRTCCliente em navegador/mobile captura ou toca áudio diretamente.Mais robusto sob redes incertas; o WebRTC cuida da mídia (microfone via getUserMedia, saída via track remota).
WebSocketSeu servidor já recebe áudio cru de um pipeline de mídia, sistema de chamadas ou worker.Interface de mais baixo nível: você envia e recebe chunks Base64 de áudio manualmente sobre o socket.
SIPAgentes de voz por telefonia (PSTN via SIP trunking, ex.: Twilio).Webhook realtime.call.incoming → você aceita/rejeita a chamada e monitora via WebSocket. Confirme suporte do modelo antes de usar SIP para tradução/transcrição.
+
+
Atenção: ao conectar de um cliente (navegador ou mobile), prefira WebRTC a WebSocket — desempenho mais consistente. Use WebSocket para integração servidor↔servidor, onde a chave de API fica segura no backend.
+ +

22.2.1 WebRTC: interface unificada e token efêmero

+

Há dois mecanismos para conectar do navegador via WebRTC: a interface unificada (seu servidor encaminha o SDP e fica no caminho crítico da inicialização) ou tokens efêmeros (seu servidor emite um client secret de curta duração e o navegador conecta direto). Em ambos, a chave de API padrão só existe no servidor. A negociação WebRTC é feita contra POST /v1/realtime/calls (SDP), e o token efêmero vem de POST /v1/realtime/client_secrets.

+
+
+ + + +
+
+
# Servidor: emite um client secret efêmero (Python + SDK oficial)
+from openai import OpenAI
+
+client = OpenAI()
+
+# O client secret de curta duração que o navegador usará para conectar via WebRTC.
+secret = client.realtime.client_secrets.create(
+    session={
+        "type": "realtime",
+        "model": "gpt-realtime-2",
+        "audio": {"output": {"voice": "marin"}},
+    },
+)
+
+print(secret.value)  # ek_... -> devolva ao navegador (NUNCA exponha a chave de API)
+
+
+
+
// Navegador: conecta ao Realtime via WebRTC usando o token efêmero do servidor
+const tokenResponse = await fetch("/token");
+const { value: EPHEMERAL_KEY } = await tokenResponse.json();
+
+const pc = new RTCPeerConnection();
+
+// Toca o áudio remoto vindo do modelo
+const audioEl = document.createElement("audio");
+audioEl.autoplay = true;
+pc.ontrack = (e) => (audioEl.srcObject = e.streams[0]);
+
+// Microfone local como track de entrada
+const ms = await navigator.mediaDevices.getUserMedia({ audio: true });
+pc.addTrack(ms.getTracks()[0]);
+
+// Canal de dados para eventos cliente/servidor
+const dc = pc.createDataChannel("oai-events");
+dc.addEventListener("message", (e) => console.log(JSON.parse(e.data)));
+
+// Negociação SDP contra /v1/realtime/calls
+const offer = await pc.createOffer();
+await pc.setLocalDescription(offer);
+const sdpResponse = await fetch("https://api.openai.com/v1/realtime/calls", {
+  method: "POST",
+  body: offer.sdp,
+  headers: {
+    Authorization: `Bearer ${EPHEMERAL_KEY}`,
+    "Content-Type": "application/sdp",
+  },
+});
+await pc.setRemoteDescription({ type: "answer", sdp: await sdpResponse.text() });
+
+
+
+
# Servidor: mintar um client secret efêmero para o navegador
+curl https://api.openai.com/v1/realtime/client_secrets \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -H "OpenAI-Safety-Identifier: hashed-user-id" \
+  -d '{
+    "session": {
+      "type": "realtime",
+      "model": "gpt-realtime-2",
+      "audio": { "output": { "voice": "marin" } }
+    }
+  }'
+
+
+
+ +

22.2.2 WebSocket: servidor↔servidor

+

Para integração de backend, conecte direto via WebSocket com a chave de API padrão (segura no servidor). Inclua, quando aplicável, o cabeçalho OpenAI-Safety-Identifier com um identificador estável e que preserve privacidade (ex.: hash do ID interno do usuário).

+
+
+ + + +
+
+
# pip install websocket-client
+import os, json, websocket
+
+url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2"
+headers = [
+    "Authorization: Bearer " + os.environ["OPENAI_API_KEY"],
+    "OpenAI-Safety-Identifier: hashed-user-id",
+]
+
+def on_open(ws):
+    ws.send(json.dumps({
+        "type": "session.update",
+        "session": {"type": "realtime", "instructions": "Seja claro e breve."},
+    }))
+
+def on_message(ws, message):
+    print(json.loads(message))
+
+ws = websocket.WebSocketApp(url, header=headers, on_open=on_open, on_message=on_message)
+ws.run_forever()
+
+
+
+
import WebSocket from "ws";
+
+const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2";
+const ws = new WebSocket(url, {
+  headers: {
+    Authorization: "Bearer " + process.env.OPENAI_API_KEY,
+    "OpenAI-Safety-Identifier": "hashed-user-id",
+  },
+});
+
+ws.on("open", () => {
+  ws.send(JSON.stringify({
+    type: "session.update",
+    session: { type: "realtime", instructions: "Seja claro e breve." },
+  }));
+});
+
+ws.on("message", (message) => console.log(JSON.parse(message.toString())));
+
+
+
+
# WebSocket não é um verbo HTTP simples; o handshake é um GET com upgrade.
+# A URL e os cabeçalhos de autenticação são:
+#   wss://api.openai.com/v1/realtime?model=gpt-realtime-2
+#   Authorization: Bearer $OPENAI_API_KEY
+#   OpenAI-Safety-Identifier: hashed-user-id
+# Use um cliente WebSocket (ws / websocket-client) — ver abas Python e JavaScript.
+echo "Conecte com um cliente WebSocket; veja as abas Python/JavaScript."
+
+
+
+ +

22.2.3 SIP: telefonia

+

Com SIP você direciona chamadas telefônicas para a Realtime API via um provedor de SIP trunking. Aponte seu trunk para sip:$PROJECT_ID@sip.api.openai.com;transport=tls. Cada chamada dispara um webhook realtime.call.incoming; a partir dele você aceita (configurando modelo, voz, instruções e tools) ou rejeita a chamada e depois monitora a sessão por WebSocket.

+
+
+ + +
+
+
from flask import Flask, request, Response
+from openai import OpenAI, InvalidWebhookSignatureError
+import os, json, asyncio, threading, requests, websockets
+
+app = Flask(__name__)
+client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
+AUTH = {"Authorization": "Bearer " + os.environ["OPENAI_API_KEY"]}
+
+async def monitor(call_id):
+    async with websockets.connect(
+        "wss://api.openai.com/v1/realtime?call_id=" + call_id,
+        additional_headers=AUTH,
+    ) as ws:
+        await ws.send(json.dumps({"type": "response.create"}))
+        while True:
+            print(await ws.recv())
+
+@app.route("/", methods=["POST"])
+def webhook():
+    try:
+        event = client.webhooks.unwrap(request.data, request.headers)
+        if event.type == "realtime.call.incoming":
+            # Aceita a chamada e configura a sessão Realtime que a atenderá
+            requests.post(
+                f"https://api.openai.com/v1/realtime/calls/{event.data.call_id}/accept",
+                headers={**AUTH, "Content-Type": "application/json"},
+                json={
+                    "type": "realtime",
+                    "model": "gpt-realtime-2",
+                    "instructions": "Você é o Alex, concierge da Example Corp.",
+                },
+            )
+            threading.Thread(
+                target=lambda: asyncio.run(monitor(event.data.call_id)), daemon=True
+            ).start()
+            return Response(status=200)
+    except InvalidWebhookSignatureError:
+        return Response("Invalid signature", status=400)
+
+
+
+
# Aceitar a chamada recebida (mesmos parâmetros de criar um client secret)
+curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/accept" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{ "type": "realtime", "model": "gpt-realtime-2",
+        "instructions": "Você é o Alex, concierge da Example Corp." }'
+
+# Rejeitar (ex.: 486 = ocupado), transferir (refer) ou encerrar (hangup):
+curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/reject" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" \
+  -d '{"status_code": 486}'
+curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/refer" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" \
+  -d '{"target_uri": "tel:+14155550123"}'
+curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/hangup" \
+  -H "Authorization: Bearer $OPENAI_API_KEY"
+
+
+
+ +

22.3 Ciclo de eventos cliente/servidor

+

A sessão é gerida por eventos do cliente (que você emite) e eventos do servidor (que a API emite para indicar mudanças de estado). Ao conectar, o servidor envia session.created; você ajusta a configuração com session.update (e recebe session.updated). A maioria das propriedades pode mudar a qualquer momento — exceto a voice, que não pode ser alterada depois que o modelo já emitiu áudio na sessão.

+

Para gerar uma resposta: crie um item com conversation.item.create e dispare response.create. Durante a geração, o servidor emite uma sequência de eventos de ciclo de vida que você pode usar para feedback em tempo real:

+
+ + + + + + + + + + +
FaseEventos do servidor (ordem aproximada)
Item adicionadoconversation.item.added → conversation.item.done
Resposta iniciadaresponse.created → response.output_item.added → response.content_part.added
Áudio (saída)response.output_audio.delta (bytes Base64) → response.output_audio.done
Transcrição do áudio geradoresponse.output_audio_transcript.delta → response.output_audio_transcript.done
Texto (quando há modalidade de texto)response.output_text.delta → response.output_text.done
Encerramentoresponse.content_part.done → response.output_item.done → response.done → rate_limits.updated
+
+
Atenção: os eventos response.output_audio.done e response.done não carregam os bytes do áudio — apenas a transcrição. Para obter o áudio real, escute os response.output_audio.delta e bufferize/transmita os chunks Base64.
+ +

22.4 Áudio de entrada e saída

+

Em WebRTC, a mídia é praticamente automática: adicione o track local do microfone e o usuário já pode falar; o áudio do modelo chega como track remoto. Você ainda recebe eventos de ciclo de vida (input_audio_buffer.speech_started/speech_stopped, deltas de transcrição, response.done).

+

Em WebSocket, você controla o input audio buffer manualmente: envie chunks Base64 com input_audio_buffer.append (cada chunk ≤ 15 MB). Formatos configuráveis por sessão (session.audio.input.format / output.format) — PCM 24 kHz mono (audio/pcm) é a base; há também audio/pcmu para telefonia.

+

Vozes disponíveis na sessão Realtime: alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin e cedar. Para melhor qualidade, prefira marin ou cedar. gpt-realtime-2 também aceita entrada de imagem como content part de uma mensagem do usuário.

+
+
+ + +
+
+
// session.update define modalidade de saída, formatos, voz e VAD
+const update = {
+  type: "session.update",
+  session: {
+    type: "realtime",
+    model: "gpt-realtime-2",
+    output_modalities: ["audio"], // use ["text"] para texto sem áudio
+    audio: {
+      input: {
+        format: { type: "audio/pcm", rate: 24000 },
+        turn_detection: { type: "semantic_vad" },
+      },
+      output: { format: { type: "audio/pcm" }, voice: "marin" },
+    },
+    instructions: "Confirme entendimento antes de agir.",
+  },
+};
+dataChannel.send(JSON.stringify(update)); // WebRTC ou WebSocket: ambos têm .send()
+
+// Em WebSocket: streamar áudio cru e disparar a resposta
+ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: base64Pcm16 }));
+ws.send(JSON.stringify({ type: "input_audio_buffer.commit" })); // quando VAD está off
+ws.send(JSON.stringify({ type: "response.create" }));
+
+// Coletar os bytes de saída
+ws.on("message", (m) => {
+  const ev = JSON.parse(m.toString());
+  if (ev.type === "response.output_audio.delta") bufferAudio(ev.delta); // Base64
+});
+
+
+
+
import base64, json
+
+# session.update equivalente (dicionário enviado como JSON pelo socket)
+update = {
+    "type": "session.update",
+    "session": {
+        "type": "realtime",
+        "model": "gpt-realtime-2",
+        "output_modalities": ["audio"],
+        "audio": {
+            "input": {
+                "format": {"type": "audio/pcm", "rate": 24000},
+                "turn_detection": {"type": "semantic_vad"},
+            },
+            "output": {"format": {"type": "audio/pcm"}, "voice": "marin"},
+        },
+        "instructions": "Confirme entendimento antes de agir.",
+    },
+}
+ws.send(json.dumps(update))
+
+# Streamar áudio cru e disparar a resposta
+ws.send(json.dumps({"type": "input_audio_buffer.append", "audio": base64_pcm16}))
+ws.send(json.dumps({"type": "input_audio_buffer.commit"}))   # quando VAD está off
+ws.send(json.dumps({"type": "response.create"}))
+
+def on_message(ws, message):
+    ev = json.loads(message)
+    if ev["type"] == "response.output_audio.delta":
+        chunk = base64.b64decode(ev["delta"])   # bytes de áudio
+
+
+
+ +

22.5 Tools na sessão

+

Você pode anexar tools para o modelo consultar dados ou agir durante a conversa. A configuração usa o mesmo conjunto de eventos em WebRTC e WebSocket, e pode ser feita no nível da sessão (session.tools em session.update, disponível pela sessão inteira) ou no nível da resposta (response.tools em response.create, só para um turno).

+
+ + + + + + + +
Tipo de toolUse quandoQuem executa
functionSua aplicação detém a lógica de negócio, checagens de aprovação ou acesso privado.Seu cliente/servidor recebe a chamada e devolve function_call_output.
mcp com server_urlO modelo deve chamar tools expostas por um servidor MCP remoto.A própria Realtime API chama o servidor MCP.
mcp com connector_idVocê quer um connector embutido (ex.: Google Calendar).A Realtime API chama o connector com a autorização fornecida.
+
+
+
+ + +
+
+
import json
+
+# 1) Registrar uma function tool na sessão
+ws.send(json.dumps({
+    "type": "session.update",
+    "session": {
+        "type": "realtime",
+        "model": "gpt-realtime-2",
+        "tools": [{
+            "type": "function",
+            "name": "lookup_order",
+            "description": "Busca um pedido pelo número.",
+            "parameters": {
+                "type": "object",
+                "properties": {"order_number": {"type": "string"}},
+                "required": ["order_number"],
+            },
+        }],
+        "tool_choice": "auto",
+    },
+}))
+
+# 2) Quando o modelo chamar a function, execute e devolva o resultado
+ws.send(json.dumps({
+    "type": "conversation.item.create",
+    "item": {
+        "type": "function_call_output",
+        "call_id": function_call["call_id"],
+        "output": json.dumps({"status": "shipped", "delivery_date": "2026-05-09"}),
+    },
+}))
+ws.send(json.dumps({"type": "response.create"}))
+
+
+
+
// 1) Registrar a function tool
+ws.send(JSON.stringify({
+  type: "session.update",
+  session: {
+    type: "realtime",
+    model: "gpt-realtime-2",
+    tools: [{
+      type: "function",
+      name: "lookup_order",
+      description: "Busca um pedido pelo número.",
+      parameters: {
+        type: "object",
+        properties: { order_number: { type: "string" } },
+        required: ["order_number"],
+      },
+    }],
+    tool_choice: "auto",
+  },
+}));
+
+// 2) Devolver o resultado da function
+ws.send(JSON.stringify({
+  type: "conversation.item.create",
+  item: {
+    type: "function_call_output",
+    call_id: functionCall.call_id,
+    output: JSON.stringify({ status: "shipped", delivery_date: "2026-05-09" }),
+  },
+}));
+ws.send(JSON.stringify({ type: "response.create" }));
+
+
+
+ +

22.6 Configuração de VAD na sessão

+

Por padrão, sessões fala↔fala têm voice activity detection (VAD) ligada — a API decide quando o usuário começou/parou de falar e responde sozinha (server_vad é o default). Configure em session.audio.input.turn_detection. Detalhes dos modos server_vad e semantic_vad estão na Seção 28. Para controle granular (ex.: push-to-talk), desligue a VAD com turn_detection: null e emita manualmente input_audio_buffer.commit e response.create.

+ +

22.7 Custos e truncation

+

O faturamento da Realtime API depende do tipo de sessão. Sessões de agente de voz acumulam tokens de entrada e saída (texto, áudio e imagem) por Response; tradução e transcrição em streaming são cobradas por duração do áudio (não pelo ciclo de Response). Os preços variam por modelo (veja a página de cada modelo).

+
    +
  • Tokens de áudio: mensagens do usuário = 1 token por 100 ms de áudio; mensagens do assistente = 1 token por 50 ms. Há pequenos tokens especiais além do conteúdo, então as contagens variam um pouco.
  • +
  • Conversa inteira por turno: a cada Response, toda a Conversation é enviada ao modelo; turnos mais tardios na sessão custam mais. Leia o uso real no campo usage do evento response.done.
  • +
  • Caching automático: o prompt caching é aplicado automaticamente e reduz muito o custo de entrada em sessões multiturno (melhor esforço). Mantenha o histórico, as instructions e as definições de tools estáticos — alterá-los no meio da sessão "quebra" o cache dali em diante.
  • +
  • Transcrição de entrada: se habilitada, é cobrada à parte (modelo de transcrição próprio, ex.: whisper-1 ou gpt-4o-transcribe); o uso vem em conversation.item.input_audio_transcription.completed.
  • +
  • Modelo mini: os modelos speech-to-speech têm uma versão "mini" bem mais barata — refine no modelo maior e só então tente otimizar custo migrando para o mini.
  • +
+

Quando os tokens excedem o limite de contexto do modelo, a Conversation é truncada (itens mais antigos são descartados). Você pode definir uma janela menor e controlar o trade-off custo × memória com session.truncation: token_limits.post_instructions limita os tokens de entrada por Response (exceto as instructions), e retention_ratio (default 1.0) faz a truncation descartar mais que o necessário para estender a folga antes da próxima truncation — útil porque truncar a cada turno derruba o cache. Também é possível "truncation": "disabled" para gerenciar a Conversation manualmente.

+
+
+ +
+
+
# Reduzir custo por sessão: limitar tokens e reter 80% antes de truncar de novo
+{
+  "event": "session.update",
+  "session": {
+    "truncation": {
+      "type": "retention_ratio",
+      "retention_ratio": 0.8,
+      "token_limits": { "post_instructions": 8000 }
+    }
+  }
+}
+
+
+
+
Dica: outra estratégia é editar a Conversation manualmente — remova itens antigos com conversation.item.delete (ou substitua por um resumo via conversation.item.create) para reduzir o tamanho da entrada. Estime custos rodando prompts representativos no Realtime Playground e medindo o uso de tokens por sessão.
+ + +
+ +
+

23. Tradução em tempo real (gpt-realtime-translate)

+

A tradução em tempo real transmite áudio de origem para uma sessão dedicada e devolve áudio traduzido + deltas de transcrição enquanto a pessoa ainda fala. Casos de uso: interpretação ao vivo, chamadas multilíngues, transmissões, reuniões, aulas e salas de vídeo. Use gpt-realtime-translate quando o app deve traduzir o que um humano diz; se precisa de um assistente que responde, chama tools e gerencia conversa, use gpt-realtime-2 (Seção 22).

+ +

23.1 Como a sessão de tradução difere

+
+ + + + + + + + + +
Sessão de agente de vozSessão de tradução
Conecta a /v1/realtime.Conecta a /v1/realtime/translations.
O modelo age como assistente.O modelo age como intérprete.
Usa ciclo de conversa e resposta.Transmite continuamente a partir do áudio de entrada.
Pode chamar tools e produzir turnos do assistente.Produz áudio traduzido e deltas de transcrição.
Você pode chamar response.create.Você não chama response.create.
+
+
Nota: a tradução parte do próprio fluxo de áudio. Continue dando append no áudio — inclusive os silêncios entre frases — e trate os eventos de saída conforme chegam. O modelo emite áudio traduzido em chunks PCM16 de ~200 ms, além de deltas de transcrição no idioma de destino. Use WebRTC para mídia de navegador e WebSockets para pipelines de servidor (Twilio Media Streams, mídia SIP, ingest de broadcast).
+ +

23.2 Fluxo, configuração e eventos

+

Conecte ao endpoint dedicado selecionando o modelo na URL, configure o idioma de destino com session.update (em audio.output.language) e então faça append de áudio continuamente. Escute os eventos de saída: session.output_audio.delta (áudio traduzido), session.output_transcript.delta (transcrição de destino) e session.input_transcript.delta (transcrição da origem).

+
+
+ + +
+
+
# pip install websocket-client
+import os, json, websocket
+
+ws = websocket.WebSocket()
+ws.connect(
+    "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
+    header=[
+        f"Authorization: Bearer {os.environ['OPENAI_API_KEY']}",
+        "OpenAI-Safety-Identifier: hashed-user-id",
+    ],
+)
+
+# Idioma de destino (ex.: espanhol)
+ws.send(json.dumps({
+    "type": "session.update",
+    "session": {"audio": {"output": {"language": "es"}}},
+}))
+
+# Streamar áudio de origem continuamente (incluindo silêncios)
+ws.send(json.dumps({
+    "type": "session.input_audio_buffer.append",
+    "audio": base64_pcm16,
+}))
+
+while True:
+    ev = json.loads(ws.recv())
+    if ev["type"] == "session.output_audio.delta":
+        play_pcm16(ev["delta"])              # áudio traduzido (Base64)
+    elif ev["type"] == "session.output_transcript.delta":
+        print(ev["delta"], end="", flush=True)  # legenda no idioma de destino
+    elif ev["type"] == "session.input_transcript.delta":
+        update_source_transcript(ev["delta"])   # legenda na origem
+
+
+
+
import WebSocket from "ws";
+
+const ws = new WebSocket(
+  "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
+  { headers: {
+      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
+      "OpenAI-Safety-Identifier": "hashed-user-id",
+  } }
+);
+
+ws.on("open", () => {
+  ws.send(JSON.stringify({
+    type: "session.update",
+    session: { audio: { output: { language: "es" } } },
+  }));
+});
+
+// Áudio de origem (incluindo silêncios entre frases)
+ws.send(JSON.stringify({
+  type: "session.input_audio_buffer.append",
+  audio: base64Pcm16,
+}));
+
+ws.on("message", (data) => {
+  const ev = JSON.parse(data);
+  if (ev.type === "session.output_audio.delta") playPcm16(ev.delta);
+  if (ev.type === "session.output_transcript.delta") process.stdout.write(ev.delta);
+  if (ev.type === "session.input_transcript.delta") updateSourceTranscript(ev.delta);
+});
+
+
+
+ +

23.3 Encerrar o stream de origem

+

Quando o áudio de origem termina, envie session.close antes de fechar o WebSocket. Esse evento (suportado apenas em sessões de tradução) faz o serviço esvaziar o áudio de entrada pendente, emitir o áudio/transcrição traduzidos restantes e então enviar session.closed. Pare de dar append e continue lendo eventos no seu loop normal até receber session.closed — fechar o socket imediatamente descarta a saída ainda em drenagem.

+
+
+ + +
+
+
import json
+
+closing = False
+
+def close_translation_session():
+    global closing
+    if closing:
+        return
+    closing = True
+    ws.send(json.dumps({"type": "session.close"}))
+
+close_translation_session()  # chame quando o stream de origem terminar
+
+while True:
+    ev = json.loads(ws.recv())
+    if ev["type"] == "session.output_audio.delta":
+        play_pcm16(ev["delta"])
+    elif ev["type"] == "session.output_transcript.delta":
+        print(ev["delta"], end="", flush=True)
+    elif ev["type"] == "session.closed":
+        ws.close()
+        break
+
+
+
+
let closing = false;
+function closeTranslationSession() {
+  if (closing) return;
+  closing = true;
+  ws.send(JSON.stringify({ type: "session.close" }));
+}
+
+ws.on("message", (data) => {
+  const ev = JSON.parse(data);
+  if (ev.type === "session.output_audio.delta") playPcm16(ev.delta);
+  if (ev.type === "session.output_transcript.delta") process.stdout.write(ev.delta);
+  if (ev.type === "session.closed") ws.close();
+});
+
+closeTranslationSession(); // chame quando o stream de origem terminar
+
+
+
+
Dica: use uma sessão por idioma de destino. Para uma chamada entre duas pessoas, crie uma sessão por direção (A→idioma de B, B→idioma de A). Em salas de grupo, o número de sessões ≈ falantes de origem ativos × idiomas de destino distintos. Mantenha os tracks de cada falante separados.
+ + +
+ +
+

24. Transcrição em streaming (gpt-realtime-whisper)

+

Use transcrição em tempo real quando o app precisa de speech-to-text ao vivo sem resposta falada do modelo. A sessão transmite deltas de transcrição conforme o áudio chega, de modo que o usuário vê texto antes do enunciado terminar. Para o caminho de menor latência, use gpt-realtime-whisper, projetado para ser nativamente em streaming dentro de sessões Realtime com latência controlável.

+ +

24.1 Escolha do modelo de transcrição

+
+ + + + + + + +
ModeloMelhor paraNotas
gpt-realtime-whisperÁudio ao vivo, deltas de transcrição, latência ajustável.Nativamente em streaming, feito para sessões realtime.
gpt-4o-transcribeSTT de maior acurácia quando streaming não é necessário.Para fluxos de arquivo e requisição-resposta (Seção 25).
gpt-4o-mini-transcribeTranscrição de menor custo.Quando custo importa mais que acurácia máxima.
+
+
Atenção: gpt-realtime-whisper é uma alternativa para transcrição ao vivo, não um substituto universal. Teste contra seu áudio, idiomas, vocabulário e requisitos de latência antes de migrar tráfego de produção.
+ +

24.2 Sessão de transcrição, deltas e uso

+

A transcrição em tempo real usa uma sessão type: "transcription". Conecte via WebSocket (pipeline de servidor) ou WebRTC (áudio de navegador). Campos de sessão relevantes:

+
+ + + + + + + + + + +
CampoDescrição
typeDefina como transcription para sessões só de transcrição.
audio.input.formatEncoding do áudio adicionado ao buffer. Use PCM mono 24 kHz para audio/pcm.
audio.input.transcription.modelUse gpt-realtime-whisper para streaming.
audio.input.transcription.languageDica opcional de idioma (ex.: pt, en).
audio.input.transcription.delayTrade-off latência/acurácia. Valores: minimal, low, medium, high, xhigh.
audio.input.turn_detectionVAD opcional. Para gpt-realtime-whisper, omita ou defina null e faça commit manual.
+
+

Escute conversation.item.input_audio_transcription.delta (texto incremental) e conversation.item.input_audio_transcription.completed (transcrição final do item). Como a ordem entre turnos diferentes não é garantida, use item_id para casar e reconciliar os resultados.

+
+
+ + +
+
+
// 1) Abrir uma sessão de transcrição
+ws.send(JSON.stringify({
+  type: "session.update",
+  session: {
+    type: "transcription",
+    audio: {
+      input: {
+        format: { type: "audio/pcm", rate: 24000 },
+        transcription: {
+          model: "gpt-realtime-whisper",
+          language: "pt",
+          delay: "low",        // minimal | low | medium | high | xhigh
+        },
+        turn_detection: null,  // gpt-realtime-whisper: commit manual
+      },
+    },
+  },
+}));
+
+// 2) Streamar áudio e (sem VAD) commitar quando quiser iniciar a transcrição
+ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: base64Pcm16 }));
+ws.send(JSON.stringify({ type: "input_audio_buffer.commit" }));
+
+// 3) Consumir os deltas e o evento final
+ws.on("message", (data) => {
+  const ev = JSON.parse(data);
+  if (ev.type === "conversation.item.input_audio_transcription.delta")
+    process.stdout.write(ev.delta);
+  if (ev.type === "conversation.item.input_audio_transcription.completed")
+    console.log("\nFinal:", ev.transcript, "(item", ev.item_id + ")");
+});
+
+
+
+
# Forma do session.update enviado pelo socket (JSON):
+{
+  "type": "session.update",
+  "session": {
+    "type": "transcription",
+    "audio": {
+      "input": {
+        "format": { "type": "audio/pcm", "rate": 24000 },
+        "transcription": { "model": "gpt-realtime-whisper", "language": "pt" }
+      }
+    },
+    "include": ["item.input_audio_transcription.logprobs"]
+  }
+}
+
+
+
+
Nota: ajuste a latência por delay — minimal/low para legendas ao vivo, medium equilibrado, high/xhigh quando a acurácia importa mais que a exibição imediata. Faça benchmark com áudio representativo (microfones reais, telefonia, sotaques, ruído, código-troca). Em sessões GA com gpt-realtime-whisper, o parâmetro prompt não é suportado; logprobs podem ser pedidos via include quando disponíveis. Sempre confirme suporte de timestamps/diarização/confiança antes do lançamento e tenha fallback.
+ + +
+ +
+

25. Speech-to-text (arquivos)

+

A Audio API oferece dois endpoints de speech-to-text: transcriptions (transcreve no idioma do áudio) e translations (transcreve traduzindo para inglês). Use esta via para uploads de arquivos e requisições delimitadas; para deltas ao vivo de microfone/chamada, use a Seção 24. Uploads são limitados a 25 MB e aceitam mp3, mp4, mpeg, mpga, m4a, wav e webm.

+ +

25.1 Endpoint /v1/audio/transcriptions

+

O endpoint transcriptions aceita os modelos de maior qualidade gpt-4o-transcribe e gpt-4o-mini-transcribe, além de gpt-4o-transcribe-diarize e do whisper-1. Cada um suporta um conjunto diferente de response_format:

+
+ + + + + + + + +
Modeloresponse_format suportadoOutros parâmetros
gpt-4o-transcribejson, textAceita prompt, logprobs, stream.
gpt-4o-mini-transcribejson, textAceita prompt, logprobs, stream.
gpt-4o-transcribe-diarizejson, text, diarized_jsonExige chunking_strategy > 30 s; não aceita prompt, logprobs nem timestamp_granularities[].
whisper-1json, text, srt, verbose_json, vttÚnico com timestamp_granularities[] e subtítulos srt/vtt; sem streaming.
+
+
+
+ + + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+with open("audio.mp3", "rb") as audio_file:
+    transcription = client.audio.transcriptions.create(
+        model="gpt-4o-transcribe",
+        file=audio_file,
+        response_format="text",
+        prompt="Termos de domínio: DALL·E, GPT, OpenAI.",  # melhora reconhecimento
+    )
+
+print(transcription.text)
+
+
+
+
import fs from "fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+
+const transcription = await openai.audio.transcriptions.create({
+  file: fs.createReadStream("audio.mp3"),
+  model: "gpt-4o-transcribe",
+  response_format: "text",
+  prompt: "Termos de domínio: DALL·E, GPT, OpenAI.",
+});
+
+console.log(transcription.text);
+
+
+
+
curl https://api.openai.com/v1/audio/transcriptions \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: multipart/form-data" \
+  -F file=@audio.mp3 \
+  -F model=gpt-4o-transcribe \
+  -F response_format=text
+
+
+
+ +

25.2 Diarização de falantes (gpt-4o-transcribe-diarize)

+

gpt-4o-transcribe-diarize produz transcrições com identificação de falante. Peça response_format: "diarized_json" para receber um array de segmentos com speaker, start e end. Defina chunking_strategy ("auto" recomendado, ou uma config de VAD) — obrigatório quando o áudio passa de 30 s. Opcionalmente, mapeie até quatro falantes conhecidos com known_speaker_names[] e known_speaker_references[] (clipes de 2–10 s, codificados como data URLs no multipart).

+
+
+ + + +
+
+
import base64
+from openai import OpenAI
+
+client = OpenAI()
+
+def to_data_url(path: str) -> str:
+    with open(path, "rb") as fh:
+        return "data:audio/wav;base64," + base64.b64encode(fh.read()).decode("utf-8")
+
+with open("meeting.wav", "rb") as audio_file:
+    transcript = client.audio.transcriptions.create(
+        model="gpt-4o-transcribe-diarize",
+        file=audio_file,
+        response_format="diarized_json",
+        chunking_strategy="auto",  # obrigatório se > 30 s
+        extra_body={
+            "known_speaker_names": ["agente"],
+            "known_speaker_references": [to_data_url("agente.wav")],
+        },
+    )
+
+for seg in transcript.segments:
+    print(seg.speaker, seg.text, seg.start, seg.end)
+
+
+
+
import fs from "fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+const agentRef = fs.readFileSync("agente.wav").toString("base64");
+
+const transcript = await openai.audio.transcriptions.create({
+  file: fs.createReadStream("meeting.wav"),
+  model: "gpt-4o-transcribe-diarize",
+  response_format: "diarized_json",
+  chunking_strategy: "auto", // obrigatório se > 30 s
+  extra_body: {
+    known_speaker_names: ["agente"],
+    known_speaker_references: ["data:audio/wav;base64," + agentRef],
+  },
+});
+
+for (const seg of transcript.segments) {
+  console.log(`${seg.speaker}: ${seg.text}`, seg.start, seg.end);
+}
+
+
+
+
curl https://api.openai.com/v1/audio/transcriptions \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: multipart/form-data" \
+  -F file=@meeting.wav \
+  -F model=gpt-4o-transcribe-diarize \
+  -F response_format=diarized_json \
+  -F chunking_strategy=auto \
+  -F 'known_speaker_names[]=agente' \
+  -F 'known_speaker_references[]=data:audio/wav;base64,AAA...'
+
+
+
+
Nota: com stream=true, respostas diarizadas emitem transcript.text.segment quando cada segmento é finalizado. gpt-4o-transcribe-diarize está disponível apenas em /v1/audio/transcriptions e ainda não é suportado na Realtime API.
+ +

25.3 whisper-1: timestamps/word-level e /v1/audio/translations

+

whisper-1 é o modelo da OpenAI para dois trabalhos específicos: timestamps em nível de segmento ou palavra e tradução de áudio→inglês. Para timestamps, use response_format: "verbose_json" com timestamp_granularities[] ("word", "segment" ou ambos) — esse parâmetro é suportado somente pelo whisper-1. Ele também é o único que gera legendas srt/vtt.

+
+
+ + + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+# (a) Timestamps em nível de palavra
+with open("speech.mp3", "rb") as audio_file:
+    transcription = client.audio.transcriptions.create(
+        model="whisper-1",
+        file=audio_file,
+        response_format="verbose_json",
+        timestamp_granularities=["word"],   # só whisper-1
+    )
+print(transcription.words)
+
+# (b) Tradução de áudio para inglês (endpoint translations)
+with open("german.mp3", "rb") as audio_file:
+    translation = client.audio.translations.create(
+        model="whisper-1",                  # único modelo do endpoint translations
+        file=audio_file,
+    )
+print(translation.text)
+
+
+
+
import fs from "fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+
+// (a) Timestamps em nível de palavra
+const transcription = await openai.audio.transcriptions.create({
+  file: fs.createReadStream("speech.mp3"),
+  model: "whisper-1",
+  response_format: "verbose_json",
+  timestamp_granularities: ["word"], // só whisper-1
+});
+console.log(transcription.words);
+
+// (b) Tradução de áudio para inglês
+const translation = await openai.audio.translations.create({
+  file: fs.createReadStream("german.mp3"),
+  model: "whisper-1", // único modelo do endpoint translations
+});
+console.log(translation.text);
+
+
+
+
# (a) Timestamps em nível de palavra
+curl https://api.openai.com/v1/audio/transcriptions \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: multipart/form-data" \
+  -F file=@speech.mp3 \
+  -F model=whisper-1 \
+  -F response_format=verbose_json \
+  -F "timestamp_granularities[]=word"
+
+# (b) Tradução de áudio para inglês
+curl https://api.openai.com/v1/audio/translations \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: multipart/form-data" \
+  -F file=@german.mp3 \
+  -F model=whisper-1
+
+
+
+ +

25.4 Streaming e arquivos longos

+

Para uma gravação já concluída, passe stream=True nos modelos gpt-4o-transcribe/gpt-4o-mini-transcribe e receba eventos transcript.text.delta seguidos de transcript.text.done. Streaming não é suportado no whisper-1; para áudio ao vivo de microfone/chamada, use a transcrição em tempo real (Seção 24).

+

Para arquivos longos (acima de 25 MB), divida em pedaços de ≤ 25 MB ou use um formato comprimido — evite cortar no meio de uma frase para não perder contexto. O prompt (até 224 tokens no whisper-1) ajuda a corrigir grafias e acrônimos.

+ + +
+ +
+

26. Text-to-speech (gpt-4o-mini-tts)

+

O endpoint /v1/audio/speech transforma texto em áudio falado usando o modelo gpt-4o-mini-tts, o modelo de TTS mais recente e confiável da OpenAI. Os três insumos principais são: model, input (o texto, máximo de 4096 caracteres) e voice. Um diferencial do gpt-4o-mini-tts é o parâmetro instructions, que controla como o modelo fala (sotaque, faixa emocional, entonação, velocidade, tom, sussurro).

+
Atenção: as políticas de uso exigem que você informe claramente aos usuários finais que a voz TTS é gerada por IA e não é uma voz humana.
+ +
Nota — modelos TTS (2026-06-25): além do gpt-4o-mini-tts, está disponível o gpt-4o-tts (modelo TTS completo, maior qualidade). Atenção: o snapshot gpt-4o-mini-tts-2025-03-20 encerra em 2026-07-23 — migre para o snapshot gpt-4o-mini-tts-2025-12-15 ou use o alias gpt-4o-mini-tts. Fonte: developers.openai.com/api/docs/deprecations.
+ +

26.1 Gerar fala

+
+
+ + + +
+
+
from pathlib import Path
+from openai import OpenAI
+
+client = OpenAI()
+speech_file = Path("speech.mp3")
+
+with client.audio.speech.with_streaming_response.create(
+    model="gpt-4o-mini-tts",
+    voice="coral",
+    input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
+    instructions="Fale em tom alegre e positivo.",
+) as response:
+    response.stream_to_file(speech_file)
+
+
+
+
import fs from "fs";
+import path from "path";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+const speechFile = path.resolve("./speech.mp3");
+
+const mp3 = await openai.audio.speech.create({
+  model: "gpt-4o-mini-tts",
+  voice: "coral",
+  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
+  instructions: "Fale em tom alegre e positivo.",
+});
+
+const buffer = Buffer.from(await mp3.arrayBuffer());
+await fs.promises.writeFile(speechFile, buffer);
+
+
+
+
curl https://api.openai.com/v1/audio/speech \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "gpt-4o-mini-tts",
+    "input": "Hoje é um ótimo dia para construir algo que as pessoas amem!",
+    "voice": "coral",
+    "instructions": "Fale em tom alegre e positivo."
+  }' \
+  --output speech.mp3
+
+
+
+ +

26.2 Vozes, instructions e formatos

+

O endpoint de fala oferece 13 vozes embutidas no gpt-4o-mini-tts: alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, verse, marin e cedar. Para melhor qualidade, prefira marin ou cedar. As vozes são otimizadas para inglês, mas você pode gerar áudio em vários idiomas fornecendo o texto no idioma desejado. Ouça as vozes em OpenAI.fm.

+
Atenção: existem três conjuntos de vozes distintos — não os misture. (1) gpt-4o-mini-tts: as 13 acima. (2) tts-1 / tts-1-hd: apenas 9 (alloy, ash, coral, echo, fable, onyx, nova, sage, shimmer) — e não aceitam instructions. (3) Realtime API: 10 vozes (alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin, cedar) — sem fable, nova nem onyx.
+
+ + + + + + + + + +
ParâmetroValoresDescrição
inputtexto (≤ 4096 caracteres)O texto a sintetizar.
voiceuma das 13 embutidas, ou { "id": "voice_..." }Voz embutida ou voz personalizada (custom voice).
instructionsstring livreControla estilo (tom, emoção, velocidade, sotaque, sussurro).
response_formatmp3 (default), opus, aac, flac, wav, pcmFormato do áudio de saída.
speed0.25 a 4.0 (default 1.0)Velocidade da fala gerada.
+
+

Formatos por uso: MP3 (uso geral, default), Opus (streaming/baixa latência), AAC (YouTube, Android, iOS), FLAC (lossless), WAV (PCM com cabeçalho), PCM (amostras cruas 24 kHz, 16-bit signed little-endian).

+ +

26.3 Streaming de áudio em tempo real

+

O endpoint suporta streaming via chunk transfer encoding: o áudio pode tocar antes do arquivo inteiro ser gerado. Para as menores latências de resposta, use wav ou pcm como response_format.

+
+
+ + + +
+
+
import asyncio
+from openai import AsyncOpenAI
+from openai.helpers import LocalAudioPlayer
+
+openai = AsyncOpenAI()
+
+async def main() -> None:
+    async with openai.audio.speech.with_streaming_response.create(
+        model="gpt-4o-mini-tts",
+        voice="coral",
+        input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
+        instructions="Fale em tom alegre e positivo.",
+        response_format="pcm",   # pcm/wav para menor latência
+    ) as response:
+        await LocalAudioPlayer().play(response)
+
+asyncio.run(main())
+
+
+
+
import OpenAI from "openai";
+import { playAudio } from "openai/helpers/audio";
+
+const openai = new OpenAI();
+
+const response = await openai.audio.speech.create({
+  model: "gpt-4o-mini-tts",
+  voice: "coral",
+  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
+  instructions: "Fale em tom alegre e positivo.",
+  response_format: "wav", // wav/pcm para menor latência
+});
+
+await playAudio(response);
+
+
+
+
curl https://api.openai.com/v1/audio/speech \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "gpt-4o-mini-tts",
+    "input": "Hoje é um ótimo dia para construir algo que as pessoas amem!",
+    "voice": "coral",
+    "instructions": "Fale em tom alegre e positivo.",
+    "response_format": "wav"
+  }' | ffplay -i -
+
+
+
+
Nota: tanto a referência da API quanto a seção "Voice options" do guia confirmam 13 vozes embutidas no gpt-4o-mini-tts (incluindo marin e cedar) — a contagem oficial é 13. O parâmetro instructions controla estilo (tom, emoção, velocidade, sotaque, sussurro) e está documentado como disponível no gpt-4o-mini-tts (não funciona em tts-1/tts-1-hd). Custom voices (voz personalizada via { "id": "voice_..." }) exigem habilitação para clientes elegíveis e gravação de consentimento; até 20 vozes por organização.
+ + +
+ +
+

27. Áudio no chat (gpt-audio-1.5)

+

Quando você já tem um app baseado em Chat Completions e quer adicionar áudio sem montar uma sessão em tempo real, use o modelo nativamente multimodal gpt-audio-1.5. Ele aceita entrada de áudio e produz saída de áudio em uma única requisição de chat: basta incluir "audio" no array modalities e configurar audio: { voice, format }.

+
Nota: esse padrão de áudio no chat usa Chat Completions com um modelo de áudio. A documentação da Responses API descreve, hoje, entradas de texto e imagem com saída de texto; para entrada/saída de áudio direta no modelo, use Chat Completions com gpt-audio-1.5.
+ +

27.1 Entrada e saída de áudio

+
+
+ + + +
+
+
import base64
+from openai import OpenAI
+
+client = OpenAI()
+
+# Saída de áudio: pergunta em texto, resposta falada
+completion = client.chat.completions.create(
+    model="gpt-audio-1.5",
+    modalities=["text", "audio"],
+    audio={"voice": "alloy", "format": "wav"},
+    messages=[{"role": "user", "content": "Golden retriever é um bom cão de família?"}],
+)
+
+print(completion.choices[0].message)
+wav_bytes = base64.b64decode(completion.choices[0].message.audio.data)
+with open("dog.wav", "wb") as f:
+    f.write(wav_bytes)
+
+# Entrada de áudio: enviar gravação como content part input_audio
+with open("pergunta.wav", "rb") as fh:
+    audio_b64 = base64.b64encode(fh.read()).decode("utf-8")
+
+resp = client.chat.completions.create(
+    model="gpt-audio-1.5",
+    modalities=["text", "audio"],
+    audio={"voice": "alloy", "format": "wav"},
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "text", "text": "O que há nesta gravação?"},
+            {"type": "input_audio", "input_audio": {"data": audio_b64, "format": "wav"}},
+        ],
+    }],
+)
+print(resp.choices[0].message)
+
+
+
+
import { writeFileSync, readFileSync } from "node:fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+
+// Saída de áudio
+const response = await openai.chat.completions.create({
+  model: "gpt-audio-1.5",
+  modalities: ["text", "audio"],
+  audio: { voice: "alloy", format: "wav" },
+  messages: [{ role: "user", content: "Golden retriever é um bom cão de família?" }],
+});
+writeFileSync("dog.wav",
+  Buffer.from(response.choices[0].message.audio.data, "base64"));
+
+// Entrada de áudio
+const audioB64 = readFileSync("pergunta.wav").toString("base64");
+const resp = await openai.chat.completions.create({
+  model: "gpt-audio-1.5",
+  modalities: ["text", "audio"],
+  audio: { voice: "alloy", format: "wav" },
+  messages: [{
+    role: "user",
+    content: [
+      { type: "text", text: "O que há nesta gravação?" },
+      { type: "input_audio", input_audio: { data: audioB64, format: "wav" } },
+    ],
+  }],
+});
+console.log(resp.choices[0].message);
+
+
+
+
curl https://api.openai.com/v1/chat/completions \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -d '{
+    "model": "gpt-audio-1.5",
+    "modalities": ["text", "audio"],
+    "audio": { "voice": "alloy", "format": "wav" },
+    "messages": [
+      { "role": "user", "content": [
+        { "type": "text", "text": "O que há nesta gravação?" },
+        { "type": "input_audio",
+          "input_audio": { "data": "<base64 do áudio>", "format": "wav" } }
+      ] }
+    ]
+  }'
+
+
+
+ +

27.2 Quando usar áudio no chat vs. Realtime/STT/TTS

+
+ + + + + + + + +
CenárioUsePor quê
Conversa ao vivo, baixa latência, barge-in, tools em tempo realgpt-realtime-2 (Realtime, Seção 22)Sessão de streaming bidirecional; o modelo escuta e fala continuamente.
Estender um app de chat com perguntas/respostas faladas e turnos delimitadosgpt-audio-1.5 (Chat Completions)Requisição única; sem gerenciar sessão, buffers ou eventos.
Só transcrever áudio (sem resposta falada)gpt-4o-transcribe / gpt-realtime-whisperSTT puro de arquivo (Seção 25) ou ao vivo (Seção 24).
Só converter texto em falagpt-4o-mini-tts (Seção 26)Geração de fala com controle de estilo via instructions.
+
+ + +
+ +
+

28. Voice agents & VAD

+

Agentes de voz levam os conceitos de agente para interações faladas de baixa latência. A decisão de arquitetura mais importante é: o modelo deve trabalhar diretamente com áudio ao vivo, ou sua aplicação deve encadear explicitamente speech-to-text, raciocínio em texto e text-to-speech?

+ +

28.1 Arquitetura: fala↔fala vs. pipeline encadeado

+
+ + + + + + +
ArquiteturaMelhor paraPor quê
Fala↔fala (sessão de áudio ao vivo)Conversas naturais e de baixa latência.O modelo lida com entrada e saída de áudio diretamente (gpt-realtime-2).
Pipeline de voz encadeadoFluxos previsíveis ou extensão de um agente de texto existente.Seu app mantém controle explícito sobre transcrição, raciocínio em texto e geração de fala.
+
+

No fluxo fala↔fala em navegador: (1) seu servidor cria um client secret efêmero; (2) o frontend cria uma RealtimeSession; (3) a sessão conecta por WebRTC (navegador) ou WebSocket (servidor); (4) o agente trata turnos de áudio, tools, interrupções e handoffs dentro da sessão. No pipeline encadeado, seu app gerencia explicitamente STT → workflow do agente → TTS — melhor para fluxos de suporte, com aprovações, ou quando você quer transcrições duráveis e lógica determinística entre as etapas. A regra prática: escolha a arquitetura de áudio primeiro, depois desenhe o resto do agente como faria para texto. Anexe tools, handoffs e guardrails ao RealtimeAgent do mesmo jeito que faria com um agente de texto.

+
Nota: as bibliotecas expõem helpers diferentes: em TypeScript, o caminho mais rápido para voz no navegador é RealtimeAgent + RealtimeSession; em Python, a via simples para estender um agente de texto é um VoicePipeline encadeado.
+ +

28.2 VAD: server_vad e semantic_vad

+

Voice activity detection (VAD) detecta automaticamente quando o usuário começou/parou de falar. É ligada por padrão em sessões fala↔fala (default server_vad); em sessões de transcrição, depende do modelo (e o gpt-realtime-whisper exige turn_detection omitido ou null). Configure em session.audio.input.turn_detection. Quando ligada, a API emite input_audio_buffer.speech_started e input_audio_buffer.speech_stopped.

+
+ + + + + + +
ModoComo decide o fim do turnoParâmetros
server_vad (default)Períodos de silêncio para fatiar o áudio automaticamente.threshold (0–1), prefix_padding_ms, silence_duration_ms.
semantic_vadUm classificador semântico estima, pelas palavras ditas, se o usuário terminou (um "ummm..." gera timeout maior).eagerness: low | medium | high | auto (default ≈ medium).
+
+

Em conversa fala↔fala, os campos create_response e interrupt_response (só do modo conversa) controlam se a VAD dispara a resposta e se interrompe a fala em andamento. Em sessões de transcrição, a VAD apenas controla como o áudio é fatiado. eagerness: "high" faz o modelo responder/chunkar mais rápido; "low" deixa o usuário falar sem interrupção.

+
+
+ + +
+
+
{
+  "type": "session.update",
+  "session": {
+    "type": "realtime",
+    "audio": {
+      "input": {
+        "turn_detection": {
+          "type": "server_vad",
+          "threshold": 0.5,
+          "prefix_padding_ms": 300,
+          "silence_duration_ms": 500,
+          "create_response": true,
+          "interrupt_response": true
+        }
+      }
+    }
+  }
+}
+
+
+
+
// semantic_vad: o modelo decide o fim do turno pelas palavras
+const event = {
+  type: "session.update",
+  session: {
+    type: "realtime",
+    audio: {
+      input: {
+        turn_detection: {
+          type: "semantic_vad",
+          eagerness: "low",          // low | medium | high | auto
+          create_response: true,     // só em modo conversa
+          interrupt_response: true,  // só em modo conversa
+        },
+      },
+    },
+  },
+};
+dataChannel.send(JSON.stringify(event));
+
+
+
+ +

28.3 Boas práticas de prompt de voz

+
    +
  • Reasoning effort: comece com low na maioria dos agentes e ajuste pela tolerância de latência e complexidade da tarefa.
  • +
  • Captura exata de entidades: peça ao modelo para confirmar números, nomes e datas antes de agir; valide entidades de alto valor manualmente.
  • +
  • Áudio incerto: instrua o agente a pedir repetição quando o áudio for ambíguo, em vez de adivinhar.
  • +
  • Barge-in e turnos: use semantic_vad com eagerness baixo quando quiser deixar o usuário concluir frases; server_vad ajustado quando o ambiente é ruidoso (suba o threshold).
  • +
  • Tools e preâmbulos: defina políticas de uso de tools e mensagens de preâmbulo curtas; mantenha lógica de negócio na definição do agente e o transporte na camada de sessão.
  • +
  • Segurança: inclua um OpenAI-Safety-Identifier estável (hash do ID do usuário) nas requisições Realtime; ao usar token efêmero, defina o cabeçalho no request que cria o client secret.
  • +
+ + + +

28.4 Receitas e exemplos oficiais (Cookbook)

+

Exemplos oficiais de áudio e tempo real, lidos e classificados em 2026-05-24 quanto a aderência ao estado da arte. Em produção, prefira os modelos atuais (gpt-realtime-2, gpt-realtime-translate, gpt-realtime-whisper, gpt-4o-mini-tts, gpt-audio-1.5).

+
+ + + + + + + + + + +
Receita / repositórioO que ensinaStatus
Build Live Translation Apps (gpt-realtime-translate)Tradução fala→fala ao vivo no endpoint dedicado, em 3 transportes (aba do navegador, Twilio, LiveKit); voz dinâmica.SOTA
openai-realtime-consoleTemplate mínimo de Realtime via WebRTC (data channel oai-events), com function calling no cliente.SOTA
ElatoAI — Realtime no ESP32Fala→fala em hardware de borda (ESP32-S3, Opus 12 kbps, Server VAD, relay edge).SOTA
openai-realtime-agentsPadrões de voice agents (chat-supervisor, handoff sequencial, guardrails) com o Agents SDK.Padrões SOTA · trocar IDs
One-way translationUm locutor → muitos ouvintes (uma sessão por idioma).Legado
Steering TTSDirigir tom/estilo da voz.Legado
+
+
Sinais de receita legada (substituir ao portar): IDs de áudio/realtime com sufixo *-preview de gerações anteriores, TTS apenas por um modelo legado dedicado, steering de voz por system message e arquitetura turn-based para tradução. Equivalentes modernos: tradução ao vivo → gpt-realtime-translate (endpoint dedicado); estilo de voz → gpt-4o-mini-tts + instructions; áudio in/out no chat → gpt-audio-1.5; voz em tempo real → gpt-realtime-2 (com reasoning.effort).
+ +

Os três exemplos abaixo são extraídos e adaptados da documentação oficial (verificados em 2026-06-10), já com os modelos atuais. Use a aba para alternar entre Python e JavaScript.

+ +

1. Transcrição de arquivo com gpt-4o-transcribe — upload de áudio e leitura do texto. · guides/speech-to-text

+
+
+ + +
+
+
from openai import OpenAI
+
+client = OpenAI()  # usa a variável de ambiente OPENAI_API_KEY
+
+# Abre o arquivo de áudio em modo binário (mp3, wav, m4a, webm... até 25 MB)
+with open("/caminho/audio.mp3", "rb") as audio_file:
+    transcription = client.audio.transcriptions.create(
+        model="gpt-4o-transcribe",
+        file=audio_file,
+        response_format="text",   # gpt-4o-transcribe aceita "json" ou "text"
+        # prompt opcional melhora termos/siglas do domínio
+        prompt="Transcrição de uma reunião sobre a API da OpenAI.",
+    )
+
+print(transcription.text)
+
+
+
+
import fs from "fs";
+import OpenAI from "openai";
+
+const openai = new OpenAI(); // usa OPENAI_API_KEY do ambiente
+
+// Envia o arquivo como stream de leitura
+const transcription = await openai.audio.transcriptions.create({
+  file: fs.createReadStream("/caminho/audio.mp3"),
+  model: "gpt-4o-transcribe",
+  response_format: "text",
+  prompt: "Transcrição de uma reunião sobre a API da OpenAI.",
+});
+
+console.log(transcription.text);
+
+
+
+ +

2. Texto→fala com gpt-4o-mini-tts — estilo dirigido por instructions, voz marin, salvando um mp3. · guides/text-to-speech

+
+
+ + +
+
+
from pathlib import Path
+from openai import OpenAI
+
+client = OpenAI()
+speech_file_path = Path(__file__).parent / "fala.mp3"
+
+# instructions controla tom/sotaque/emoção; voz "marin" é uma das recomendadas
+with client.audio.speech.with_streaming_response.create(
+    model="gpt-4o-mini-tts",
+    voice="marin",
+    input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
+    instructions="Fale em tom animado, acolhedor e com ritmo tranquilo.",
+) as response:
+    response.stream_to_file(speech_file_path)  # grava o mp3 em disco
+
+print(f"Áudio salvo em {speech_file_path}")
+
+
+
+
import fs from "fs";
+import path from "path";
+import OpenAI from "openai";
+
+const openai = new OpenAI();
+const speechFile = path.resolve("./fala.mp3");
+
+// instructions dirige o estilo; voz "marin" é uma das recomendadas
+const mp3 = await openai.audio.speech.create({
+  model: "gpt-4o-mini-tts",
+  voice: "marin",
+  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
+  instructions: "Fale em tom animado, acolhedor e com ritmo tranquilo.",
+});
+
+// O default já é mp3; converte o ArrayBuffer em Buffer e grava
+const buffer = Buffer.from(await mp3.arrayBuffer());
+await fs.promises.writeFile(speechFile, buffer);
+console.log(`Áudio salvo em ${speechFile}`);
+
+
+
+ +

3. Sessão Realtime com gpt-realtime-2 — no navegador via WebRTC (aba JavaScript: RTCPeerConnection + data channel oai-events + token efêmero) e no servidor via WebSocket (aba Python). Cada aba mostra session.update e o envio/recebimento de eventos no transporte natural de cada ambiente. · realtime-webrtc · realtime-websocket

+
+
+ + +
+
+
# servidor→servidor: pip install websocket-client
+import os
+import json
+import websocket
+
+# A chave padrão fica só no backend seguro; nunca no navegador.
+url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2"
+headers = [
+    "Authorization: Bearer " + os.environ["OPENAI_API_KEY"],
+    "OpenAI-Safety-Identifier: hash-do-id-do-usuario",
+]
+
+
+def on_open(ws):
+    print("Conectado ao servidor.")
+    # Configura a sessão (session.update) e envia uma mensagem do usuário
+    ws.send(json.dumps({
+        "type": "session.update",
+        "session": {
+            "type": "realtime",
+            "instructions": "Você é um assistente de voz objetivo e gentil.",
+        },
+    }))
+    ws.send(json.dumps({
+        "type": "conversation.item.create",
+        "item": {
+            "type": "message",
+            "role": "user",
+            "content": [{"type": "input_text", "text": "Olá! Me dê uma dica rápida."}],
+        },
+    }))
+    ws.send(json.dumps({"type": "response.create"}))
+
+
+def on_message(ws, message):
+    event = json.loads(message)
+    print("Evento recebido:", event.get("type"))
+
+
+ws = websocket.WebSocketApp(
+    url, header=headers, on_open=on_open, on_message=on_message,
+)
+ws.run_forever()
+
+
+
+
// Navegador: busca um token efêmero gerado pelo SEU backend (/token),
+// que chama POST /v1/realtime/client_secrets com a chave padrão.
+const tokenResponse = await fetch("/token");
+const data = await tokenResponse.json();
+const EPHEMERAL_KEY = data.value; // ex.: "ek_..." (nunca a chave padrão!)
+
+// Conexão peer WebRTC
+const pc = new RTCPeerConnection();
+
+// Toca o áudio remoto do modelo
+const audioEl = document.createElement("audio");
+audioEl.autoplay = true;
+pc.ontrack = (e) => (audioEl.srcObject = e.streams[0]);
+
+// Microfone local como faixa de entrada
+const ms = await navigator.mediaDevices.getUserMedia({ audio: true });
+pc.addTrack(ms.getTracks()[0]);
+
+// Data channel para enviar/receber eventos JSON
+const dc = pc.createDataChannel("oai-events");
+dc.addEventListener("open", () => {
+  // session.update logo após abrir o canal
+  dc.send(JSON.stringify({
+    type: "session.update",
+    session: { type: "realtime", instructions: "Seja gentil e direto." },
+  }));
+});
+dc.addEventListener("message", (e) => {
+  const event = JSON.parse(e.data); // eventos do servidor
+  console.log("Evento:", event.type);
+});
+
+// Oferta SDP → troca com a Realtime API usando o token efêmero
+const offer = await pc.createOffer();
+await pc.setLocalDescription(offer);
+const sdpResponse = await fetch("https://api.openai.com/v1/realtime/calls", {
+  method: "POST",
+  body: offer.sdp,
+  headers: {
+    Authorization: `Bearer ${EPHEMERAL_KEY}`,
+    "Content-Type": "application/sdp",
+  },
+});
+await pc.setRemoteDescription({ type: "answer", sdp: await sdpResponse.text() });
+
+
+
+ + +
+ +

Parte D — Embeddings, Moderation, Operação & Referência

Embeddings e moderation, preços e limites por modelo, processamento em lote/flex/priority, Admin APIs, erros, checklist de produção e referência rápida.

+ +
+

29. Embeddings

+

Embeddings transformam texto em vetores de ponto flutuante cuja distância mede a relação semântica entre dois trechos: distâncias pequenas indicam alta relação, distâncias grandes indicam baixa relação. São a base de busca semântica, RAG, clustering, recomendação, detecção de anomalias e classificação. O endpoint é POST /v1/embeddings e a cobrança é por token de entrada.

+ +

29.1 Modelos e dimensões

+

OpenAI oferece dois modelos de embedding de terceira geração (sufixo -3). O comprimento padrão do vetor é 1536 para text-embedding-3-small e 3072 para text-embedding-3-large. Ambos aceitam até 8192 tokens por entrada.

+
+ + + + + + +
ModeloDimensões padrãoMáx. entrada (tokens)Uso recomendado
text-embedding-3-small15368192Maior volume e custo baixo; busca/RAG de larga escala.
text-embedding-3-large30728192Maior qualidade de recuperação quando precisão importa mais que custo.
+
+
Nota: a entrada pode ser uma string ou um array (lote) de strings/arrays de tokens. Cada array é limitado a 2048 elementos e o request inteiro a no máximo 300.000 tokens somados em todas as entradas.
+ +

29.2 Reduzir dimensões com dimensions

+

O parâmetro dimensions (suportado nos modelos text-embedding-3 e posteriores) encurta o vetor sem perder as propriedades de representação de conceito — útil para caber em bancos vetoriais com limite de dimensão, reduzindo memória e custo de armazenamento com pequena perda de acurácia. Ao encurtar manualmente após a geração, é preciso renormalizar (L2) o vetor; ao passar dimensions na chamada, a normalização já vem aplicada — esta é a abordagem recomendada.

+ +

29.3 Gerar embeddings

+
+
+ + + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+resp = client.embeddings.create(
+    model="text-embedding-3-large",
+    input="O texto que você quer indexar para busca semântica.",
+    dimensions=1024,           # encurta de 3072 para 1024 (já normalizado)
+    encoding_format="float",
+)
+
+vetor = resp.data[0].embedding
+print(len(vetor), resp.usage.total_tokens)
+
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const resp = await client.embeddings.create({
+  model: "text-embedding-3-large",
+  input: "O texto que você quer indexar para busca semântica.",
+  dimensions: 1024,
+  encoding_format: "float",
+});
+
+const vetor = resp.data[0].embedding;
+console.log(vetor.length, resp.usage.total_tokens);
+
+
+
+
curl https://api.openai.com/v1/embeddings \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "text-embedding-3-large",
+    "input": "O texto que você quer indexar para busca semântica.",
+    "dimensions": 1024,
+    "encoding_format": "float"
+  }'
+
+
+
+ +

29.4 Uso em busca e RAG

+

Para recuperar os documentos mais relevantes, gere o embedding da consulta com o mesmo modelo usado para indexar e calcule a similaridade de cosseno entre o vetor da consulta e os vetores dos documentos, ordenando do maior para o menor. Coloque os trechos mais relevantes no contexto do modelo de geração para compor a resposta (RAG). Como o endpoint é estável e elegível a Zero Data Retention, embeddings podem ser pré-computados e persistidos em um banco vetorial. Para grandes coleções, prefira gerar os vetores via Batch API com 50% de desconto.

+ + +
+ +
+

30. Moderation

+

Há dois fluxos de moderação: o endpoint standalone POST /v1/moderations, que classifica um texto ou imagem isoladamente, e os scores inline, que voltam junto da geração na Responses API e no Chat Completions (ver §30.5). O endpoint standalone verifica se um texto ou imagem é potencialmente nocivo, retornando categorias sinalizadas e pontuações de confiança. É gratuito. Com ele você pode filtrar conteúdo, intervir em contas abusivas ou bloquear entradas antes de chegar ao modelo. Arquivos de imagem são limitados a 20 MB.

+ +

30.1 Modelo atual

+

O modelo recomendado é omni-moderation-latest: suporta entradas multimodais (texto e imagem) e mais categorias de classificação. A entrada pode ser uma string simples ou um array de conteúdo com objetos text e image_url.

+ +

30.2 Estrutura da resposta

+
+ + + + + + + + +
CampoDescrição
flaggedtrue se o modelo classifica o conteúdo como potencialmente nocivo.
categoriesDicionário com um flag booleano por categoria.
category_scoresPontuação de 0 a 1 por categoria (confiança do modelo). Políticas que dependem desses scores podem precisar de recalibração ao longo do tempo.
category_applied_input_typesQuais tipos de entrada ("text", "image") dispararam cada categoria. Disponível apenas nos modelos omni.
+
+ +

30.3 Categorias

+
+ + + + + + + + + + + + + + + + + +
CategoriaDescriçãoEntradas
harassmentAssédio dirigido a qualquer alvo.Texto
harassment/threateningAssédio com violência ou dano grave.Texto
hateÓdio baseado em grupo protegido (raça, gênero, religião etc.).Texto
hate/threateningConteúdo de ódio com violência ou dano grave.Texto
illicitInstruções para cometer atos ilícitos. OmniTexto
illicit/violentIlícito com referência a violência ou obtenção de arma. OmniTexto
self-harmPromove, encoraja ou retrata automutilação.Texto e imagem
self-harm/intentExpressa intenção/engajamento em automutilação.Texto e imagem
self-harm/instructionsEncoraja ou instrui automutilação.Texto e imagem
sexualConteúdo sexual (exclui educação/bem-estar).Texto e imagem
sexual/minorsConteúdo sexual com menor de 18 anos.Texto
violenceMorte, violência ou lesão física.Texto e imagem
violence/graphicMorte, violência ou lesão em detalhe gráfico.Texto e imagem
+
+
Nota: categorias marcadas como apenas texto retornam score 0 quando só há imagem na entrada.
+ +

30.4 Moderar texto e imagem

+
+
+ + + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+resp = client.moderations.create(
+    model="omni-moderation-latest",
+    input=[
+        {"type": "text", "text": "Descreva esta imagem."},
+        {"type": "image_url",
+         "image_url": {"url": "https://exemplo.com/imagem.jpg"}},
+    ],
+)
+
+resultado = resp.results[0]
+if resultado.flagged:
+    print("Conteúdo sinalizado:", resultado.categories)
+
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const resp = await client.moderations.create({
+  model: "omni-moderation-latest",
+  input: [
+    { type: "text", text: "Descreva esta imagem." },
+    { type: "image_url", image_url: { url: "https://exemplo.com/imagem.jpg" } },
+  ],
+});
+
+const r = resp.results[0];
+if (r.flagged) console.log("Conteúdo sinalizado:", r.categories);
+
+
+
+
curl https://api.openai.com/v1/moderations \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "omni-moderation-latest",
+    "input": [
+      { "type": "text", "text": "Descreva esta imagem." },
+      { "type": "image_url", "image_url": { "url": "https://exemplo.com/imagem.jpg" } }
+    ]
+  }'
+
+
+
+ +

30.5 Scores de moderação inline (Responses e Chat Completions)

+

Desde jun/2026 é possível pedir os scores de moderação no mesmo fluxo da geração, sem requisição separada: passe um objeto moderation no topo da requisição (Responses API ou Chat Completions) com o modelo de moderação em moderation.model. A resposta volta com response.moderation.input (moderação da entrada) e response.moderation.output (moderação da saída gerada) — cada um é um moderation_result com os mesmos campos de §30.2 (flagged, categories, category_scores). Suporte tipado no SDK Python a partir de openai 2.41.0.

+
+
+ + + +
+
+
resp = client.responses.create(
+    model="gpt-5.5",
+    input="Escreva uma resposta para este e-mail de cliente: ...",
+    moderation={"model": "omni-moderation-latest"},
+)
+
+# Revise os scores ANTES de exibir a saída ou agir sobre ela.
+for lado, resultado in (("input", resp.moderation.input), ("output", resp.moderation.output)):
+    if getattr(resultado, "flagged", False):
+        enviar_para_fila_de_revisao(lado, resultado.categories, resp.id)
+
+
+
+
const resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Escreva uma resposta para este e-mail de cliente: ...",
+  moderation: { model: "omni-moderation-latest" },
+});
+
+for (const [lado, resultado] of [["input", resp.moderation.input], ["output", resp.moderation.output]]) {
+  if (resultado?.flagged) enviarParaFilaDeRevisao(lado, resultado.categories, resp.id);
+}
+
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "Escreva uma resposta para este e-mail de cliente: ...",
+    "moderation": { "model": "omni-moderation-latest" }
+  }'
+
+
+
+
    +
  • A geração acontece normalmente. Os scores são sinal para a sua política (logging, roteamento, fila de revisão humana, bloqueio) — não um bloqueio automático. Uma recusa ou resposta safety-aware ainda pode vir sinalizada se discute conteúdo nocivo.
  • +
  • Streaming: os scores chegam só depois que a saída completa está disponível — eles não vêm nos deltas parciais.
  • +
  • Tool calling: a moderação cobre argumentos de tool calls e outputs de tools quando aparecem no conteúdo da conversa; não cobre nomes, descriptions e schemas de tools, nem schemas de response_format.
  • +
  • Falhas: se a etapa de moderação não completar, o campo correspondente (input ou output) pode conter um erro em vez de scores — cheque o tipo do resultado antes de ler flagged.
  • +
+ + +
+ +
+

31. Preços

+

Os preços abaixo são por 1 milhão de tokens (USD) no tier Standard, salvo quando indicado por minuto/unidade/chamada. Preços são perecíveis: confira sempre a página oficial. Conferência feita em 2026-06-10 direto na tabela oficial (fonte ao final).

+
Modelos sem linha própria na tabela oficial. Alguns modelos de áudio — gpt-audio-1.5, gpt-4o-mini-tts, gpt-4o-transcribe-diarize e whisper-1 — não aparecem como linha de preço na página oficial (verificado: a página tem só as seções Realtime and audio generation models e Transcription models, e não há seção de TTS). Eles são cobrados por token nas taxas do endpoint/modelo correspondente. Onde a tabela mostra por token, é esse o regime — não um preço fixo por minuto/caractere publicado.
+ +

31.1 Modelos de texto / reasoning (Standard)

+
+ + + + + + + + + +
ModeloEntradaEntrada em cacheSaída
gpt-5.5 (<272K contexto)$5,00$0,50$30,00
gpt-5.5-pro (<272K contexto)$30,00—$180,00
gpt-5.4-mini$0,75$0,075$4,50
gpt-5.4-nano$0,20$0,02$1,25
gpt-5.4-pro (<272K contexto)$30,00—$180,00
+
+
Nota: endpoints de processamento regional (residência de dados) têm acréscimo de 10% para a família gpt-5.5/gpt-5.4. Tarifas de Batch e Flex equivalem a ~50% da tarifa Standard.
+ +

31.2 Priority processing

+

O tier Priority oferece latência mais baixa e consistente, cobrado com prêmio sobre o Standard (descontos de cache continuam valendo).

+
+ + + + + + +
ModeloEntradaEntrada em cacheSaída
gpt-5.5$12,50$1,25$75,00
gpt-5.4-mini$1,50$0,15$9,00
+
+ +

31.3 Imagem, realtime e áudio

+

Preços por 1M tokens, salvo quando indicado por minuto. Modalidades cobradas separadamente por modelo realtime.

+
+ + + + + + + + + + + + + +
ModeloModalidadeEntradaCacheSaída
gpt-image-2Imagem / textoEstimado por quality+size na calculadora oficial (tabela por imagem na §20). Ex. 1024×1024: low ~$0,006 · medium ~$0,053 · high ~$0,211. Tokens de imagem: $8 entrada / $2 cache / $30 saída.
gpt-realtime-2Áudio$32,00$0,40$64,00
Texto$4,00$0,40$24,00
Imagem$5,00$0,50—
gpt-realtime-miniÁudio$10,00$0,30$20,00
Texto$0,60$0,06$2,40
Imagem$0,80$0,08—
gpt-realtime-translateÁudio——$0,034 / min
gpt-audio-1.5Áudio no chatCobrado por token (áudio + texto de entrada/saída) às taxas do modelo — sem linha própria na tabela oficial.
+
+ +

31.4 Transcrição e fala

+
+ + + + + + + + + +
ModeloEntrada (texto)Saída (texto)Áudio
gpt-4o-transcribe$2,50$10,00$0,006 / min
gpt-4o-mini-transcribe$1,25$5,00$0,003 / min
gpt-4o-transcribe-diarizeCobrado como transcrição (tokens de entrada/saída) — sem linha própria: a tabela Transcription models oficial lista só gpt-4o-transcribe e gpt-4o-mini-transcribe.
gpt-4o-mini-ttsCobrado por token (texto de entrada + áudio de saída) — sem linha própria: a página oficial não tem seção de TTS.
whisper-1——$0,006 / min (tarifa histórica; não consta na tabela atual)
+
+ +

31.5 Embeddings e moderation

+
+ + + + + + + +
ModeloPreço
text-embedding-3-small$0,02 / 1M tokens
text-embedding-3-large$0,13 / 1M tokens
omni-moderation-latestGratuito
+
+ +

31.6 Ferramentas integradas

+
+ + + + + + + + + + +
FerramentaPreço
Web search (modelos de reasoning gpt-5.x)$10,00 / 1k chamadas + tokens de conteúdo à taxa do modelo
Web search (modelos não-reasoning)$25,00 / 1k chamadas (conteúdo gratuito)
File search — armazenamento$0,10 / GB por dia (1 GB grátis)
File search — chamada$2,50 / 1k chamadas (somente Responses API)
Containers (Hosted Shell + Code Interpreter)1 GB $0,03 · 4 GB $0,12 · 16 GB $0,48 · 64 GB $1,92 por 20 min (base de preço) — desde 2026-06-02 a cobrança é por minuto, com mínimo de 5 min por sessão (não se cobra mais o bloco de 20 min inteiro)
computer-use-preview (modelo dedicado de Computer Use, atual — usado só na Responses API; o gpt-5.x não o substitui para a tool de computer use)$3,00 entrada / $12,00 saída por 1M tokens
+
+
Nota: tokens usados pelas ferramentas integradas são cobrados às taxas por token do modelo escolhido. Responses, Chat Completions, Realtime, Batch e Assistants não são cobradas à parte — você paga apenas os tokens.
+ + +
+ +
+

32. Rate limits & tiers

+

Rate limits restringem quantas requisições e tokens você pode usar por janela de tempo. São aplicados no nível de organização e de projeto (não por usuário), variam por modelo e podem ser atingidos por qualquer métrica — o que vier primeiro.

+ +

32.1 Métricas

+
+ + + + + + + + +
SiglaSignificado
RPM / RPDRequisições por minuto / por dia.
TPM / TPDTokens por minuto / por dia.
IPMImagens por minuto.
ÁudioMinutos de áudio por minuto, em alguns modelos de streaming.
+
+
Nota: algumas famílias compartilham limite (qualquer chamada conta para o mesmo pool). Modelos de contexto longo têm limite separado. A ingestão em vector store compartilha 300 RPM por vector_store_id.
+ +

32.2 Tiers de uso

+

À medida que o gasto na API sobe, a organização é promovida automaticamente de tier, aumentando os limites na maioria dos modelos.

+
+ + + + + + + + + + +
TierQualificaçãoLimite de gasto
FreeGeografia permitida$100 / mês
Tier 1$5 pagos$100 / mês
Tier 2$50 pagos$500 / mês
Tier 3$100 pagos$1.000 / mês
Tier 4$250 pagos$5.000 / mês
Tier 5$1.000 pagos$200.000 / mês
+
+ +

32.3 Headers de limite

+

Cada resposta HTTP traz o estado atual do seu limite, útil para implementar backoff proativo:

+
+ + + + + + + + + + +
HeaderExemploSignificado
x-ratelimit-limit-requests60Máximo de requisições permitidas.
x-ratelimit-limit-tokens150000Máximo de tokens permitidos.
x-ratelimit-remaining-requests59Requisições restantes.
x-ratelimit-remaining-tokens149984Tokens restantes.
x-ratelimit-reset-requests1sTempo até resetar o limite de requisições.
x-ratelimit-reset-tokens6m0sTempo até resetar o limite de tokens.
+
+ +

32.4 Estratégia de backoff/retry

+

Para se recuperar de 429 sem falhas, faça retry com backoff exponencial e jitter aleatório (para evitar que retries colidam ao mesmo tempo). Lembre que requisições malsucedidas também contam para o limite, então reenviar em loop não resolve. Outras táticas: reduzir max_tokens para perto do tamanho esperado da resposta; juntar várias tarefas por requisição quando o gargalo é RPM (mas há TPM sobrando); e usar a Batch API para cargas que não precisam de resposta imediata.

+
+
+ + + +
+
+
from openai import OpenAI
+from tenacity import retry, stop_after_attempt, wait_random_exponential
+
+client = OpenAI()
+
+@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
+def responder(**kwargs):
+    return client.responses.create(**kwargs)
+
+resp = responder(model="gpt-5.5", input="Olá!")
+print(resp.output_text)
+
+
+
+
import OpenAI from "openai";
+
+// O SDK oficial já aplica retries com backoff automaticamente.
+const client = new OpenAI({ maxRetries: 6 });
+
+const resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Olá!",
+});
+console.log(resp.output_text);
+
+
+
+
# Inspecione os headers de limite antes de decidir o ritmo das chamadas:
+curl -i https://api.openai.com/v1/responses \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{ "model": "gpt-5.5", "input": "Olá!" }' \
+  | grep -i "x-ratelimit"
+
+
+
+ + +
+ +
+

33. Batch, Flex & Priority

+

O parâmetro service_tier controla o regime de processamento, trocando latência por custo. Além dele, a Batch API oferece um caminho assíncrono de maior throughput.

+ +

33.1 Batch API

+

A Batch API processa grandes grupos de requisições de forma assíncrona com 50% de desconto, um pool de rate limits separado (não consome o limite síncrono por modelo) e prazo de até 24 horas (geralmente menos). Ideal para avaliações, classificação de grandes datasets, geração de embeddings de repositórios e jobs offline.

+

Fluxo: monte um arquivo .jsonl (uma requisição por linha, cada uma com custom_id único e body idêntico ao do endpoint-alvo) → faça upload via Files API com purpose="batch" → crie o batch com completion_window="24h" → consulte o status → baixe o output_file_id. Endpoints suportados incluem /v1/responses, /v1/chat/completions, /v1/embeddings, /v1/moderations, /v1/images/generations e /v1/videos.

+
+ + + + + + + + + +
LimiteValor
Requisições por batchAté 50.000
Tamanho do arquivo de entradaAté 200 MB
Entradas de embeddings por batchAté 50.000
Criação de batchesAté 2.000 por hora
Saída disponívelArquivo de saída apagado 30 dias após a conclusão
+
+
Nota: a ordem das linhas de saída pode não corresponder à de entrada — use sempre o custom_id para mapear. Batches não concluídos a tempo vão para expired; você é cobrado apenas pelas requisições completadas.
+
+
+ + + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+# 1) upload do .jsonl
+entrada = client.files.create(file=open("batchinput.jsonl", "rb"), purpose="batch")
+
+# 2) cria o batch (janela fixa de 24h)
+batch = client.batches.create(
+    input_file_id=entrada.id,
+    endpoint="/v1/responses",
+    completion_window="24h",
+    metadata={"description": "geração noturna de embeddings"},
+)
+
+# 3) consulta o status; 4) ao concluir, baixa o output_file_id
+batch = client.batches.retrieve(batch.id)
+if batch.status == "completed":
+    saida = client.files.content(batch.output_file_id)
+    print(saida.text)
+
+
+
+
import fs from "fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const entrada = await client.files.create({
+  file: fs.createReadStream("batchinput.jsonl"),
+  purpose: "batch",
+});
+
+const batch = await client.batches.create({
+  input_file_id: entrada.id,
+  endpoint: "/v1/responses",
+  completion_window: "24h",
+});
+
+const atual = await client.batches.retrieve(batch.id);
+if (atual.status === "completed") {
+  const saida = await client.files.content(atual.output_file_id);
+  console.log(await saida.text());
+}
+
+
+
+
# upload
+curl https://api.openai.com/v1/files \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -F purpose="batch" -F file="@batchinput.jsonl"
+
+# cria o batch
+curl https://api.openai.com/v1/batches \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{ "input_file_id": "file-abc123", "endpoint": "/v1/responses", "completion_window": "24h" }'
+
+
+
+ +

33.2 Flex processing

+

Defina service_tier="flex" para custo menor (tarifa de Batch, com desconto adicional de prompt caching) em troca de latência maior e indisponibilidade ocasional de recurso. Ideal para tarefas não produtivas: avaliações, enriquecimento de dados e cargas assíncronas. Está em beta com disponibilidade limitada de modelos.

+
Atenção: com Flex, timeouts são mais prováveis — aumente o timeout do SDK (padrão de 10 min). Um 429 Resource Unavailable significa falta de capacidade e não é cobrado; faça retry com backoff, ou retry com service_tier="auto" para cair no processamento padrão.
+
+
+ + + +
+
+
from openai import OpenAI
+
+client = OpenAI(timeout=900.0)  # 15 min
+
+resp = client.responses.create(
+    model="gpt-5.5",
+    instructions="Liste e descreva todas as metáforas deste livro.",
+    input="<texto longo do livro>",
+    service_tier="flex",
+)
+print(resp.output_text)
+
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI({ timeout: 15 * 60 * 1000 }); // 15 min
+
+const resp = await client.responses.create({
+  model: "gpt-5.5",
+  instructions: "Liste e descreva todas as metáforas deste livro.",
+  input: "<texto longo do livro>",
+  service_tier: "flex",
+});
+console.log(resp.output_text);
+
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "<texto longo do livro>",
+    "service_tier": "flex"
+  }'
+
+
+
+ +

33.3 Priority processing

+

Defina service_tier="priority" para latência mais baixa e consistente, mantendo a flexibilidade pay-as-you-go. Ideal para aplicações de alto valor voltadas ao usuário com tráfego regular — não para processamento de dados, avaliações ou tráfego errático. Cobrado com prêmio sobre a padrão; descontos de cache continuam valendo. Pode ser ativado por requisição ou no nível de projeto.

+
Atenção: existe um ramp rate limit. Se o tráfego subir rápido demais (≥ 1M TPM e >50% de aumento de TPM em 15 min), parte das requisições é rebaixada para Standard e cobrada como tal — a resposta mostrará service_tier="default". Faça o ramp gradual e evite ETL/batch nesse tier. Contexto longo, modelos fine-tuned e embeddings ainda não são suportados.
+ + +
+ +
+

34. Admin APIs

+

As Admin APIs automatizam a gestão da organização — convites de usuários, revisão de audit logs, administração de projetos, gestão de chaves, alertas de gasto, retenção de dados, permissões de hosted tools por projeto (/v1/organization/projects/{project_id}/hosted_tool_permissions), itens granulares de cobrança e operações de rate limit — para ferramentas de back-office, fluxos de segurança e tooling operacional fora do dashboard (capacidades expandidas em 26/05/2026).

+
Workload Identity Federation (26/05/2026): cargas de trabalho confiáveis podem trocar tokens de identidade externa por tokens de acesso de curta duração da OpenAI API — elimina a necessidade de armazenar API keys de longa duração em CI/CD e infraestrutura.
+ +

34.1 Chave admin

+

Os endpoints sob /v1/organization/... exigem uma Admin API key (criada em Settings → Organization → Admin keys), que não funciona em endpoints comuns. Defina OPENAI_ADMIN_KEY e inicialize o SDK normalmente.

+ +

34.2 RBAC e acesso a modelo por projeto

+

O controle de acesso baseado em papéis (RBAC) governa API e Dashboard com as mesmas permissões. Conceitos: Organização (papéis valem em todos os projetos), Projeto (papéis valem só naquele projeto), Grupos (coleções de usuários, sincronizáveis via SCIM) e Papéis (pacotes de permissões; o acesso de um usuário é a união de seus papéis). Comece pelo princípio do menor privilégio; mudanças de papel podem levar até 30 minutos para propagar.

+

Para restringir quais modelos um projeto pode usar, configure model permissions em /v1/organization/projects/{project_id}/model_permissions: defina mode como allow_list (só os modelos listados) ou deny_list (bloqueia os listados, libera os demais).

+ +

34.3 Alertas de limite de gasto

+

Use /v1/organization/projects/{project_id}/spend_alerts para notificar a equipe quando o gasto do projeto atingir um limiar. Os valores são especificados em centavos.

+ +

34.4 Retenção de dados

+

Use /v1/organization/projects/{project_id}/data_retention para sobrescrever ou herdar a política da organização. Defina retention_type="organization_default" para herdar. Por padrão, logs de monitoramento de abuso são retidos por até 30 dias; organizações elegíveis podem solicitar Modified Abuse Monitoring ou Zero Data Retention (ZDR) (sujeito a aprovação prévia da OpenAI). Sob ZDR, o parâmetro store em /v1/responses e /v1/chat/completions é sempre tratado como false.

+ +

34.5 Convidar usuário e audit logs

+

Use /v1/organization/invites para enviar um convite por e-mail à organização (papéis reader ou owner), e /v1/organization/audit_logs para listar ações recentes de usuários e mudanças de configuração — base para auditoria e investigação de segurança.

+
+
+ + + +
+
+
import os
+from openai import OpenAI
+
+# Use a chave admin, não a chave de projeto
+admin = OpenAI(api_key=os.environ["OPENAI_ADMIN_KEY"])
+
+# Convidar um usuário como reader
+admin.organization.invites.create(email="dev@empresa.com.br", role="reader")
+
+# Restringir o projeto a um conjunto de modelos
+admin.organization.projects.model_permissions.create(
+    project_id="proj_123",
+    mode="allow_list",
+    model_ids=["gpt-5.5", "gpt-5.4-mini", "text-embedding-3-large"],
+)
+
+# Alerta de gasto a US$ 50,00 (valor em centavos)
+admin.organization.projects.spend_alerts.create(
+    project_id="proj_123", threshold=5000,
+)
+
+
+
+
import OpenAI from "openai";
+
+const admin = new OpenAI({ apiKey: process.env.OPENAI_ADMIN_KEY });
+
+await admin.organization.invites.create({ email: "dev@empresa.com.br", role: "reader" });
+
+await admin.organization.projects.modelPermissions.create("proj_123", {
+  mode: "allow_list",
+  model_ids: ["gpt-5.5", "gpt-5.4-mini", "text-embedding-3-large"],
+});
+
+await admin.organization.projects.spendAlerts.create("proj_123", { threshold: 5000 });
+
+
+
+
# Listar audit logs da organização
+curl https://api.openai.com/v1/organization/audit_logs \
+  -H "Authorization: Bearer $OPENAI_ADMIN_KEY"
+
+# Restringir modelos de um projeto (allowlist)
+curl https://api.openai.com/v1/organization/projects/proj_123/model_permissions \
+  -H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{ "mode": "allow_list", "model_ids": ["gpt-5.5", "text-embedding-3-large"] }'
+
+
+
+
Atenção: uma Admin API key concede controle amplo sobre a organização. Guarde-a em secret storage, restrinja quem a possui e audite periodicamente. Nunca a exponha em código ou repositórios.
+ + +
+ +
+

35. Códigos de erro

+

A API retorna erros HTTP padrão; os SDKs oficiais os mapeiam em exceções tipadas. Trate-os programaticamente e aplique backoff onde indicado.

+ +

35.1 Erros HTTP

+
+ + + + + + + + + + + + + +
CódigoCausaComo tratar
401 Invalid AuthenticationAutenticação inválida.Confirme a API key e a organização correta.
401 Incorrect API keyChave incorreta, deletada ou de outra org/projeto.Gere uma nova chave e limpe o cache.
401 IP not authorizedIP fora do allowlist do projeto/organização.Envie do IP correto ou ajuste o IP allowlist.
403 Country not supportedAcesso de país/região não suportado.Verifique a lista de países suportados.
429 Rate limit reachedRequisições rápidas demais.Ritme as chamadas; backoff exponencial.
429 Quota exceededSem créditos ou limite de gasto atingido.Compre créditos ou aumente o limite de uso.
500 Server errorErro nos servidores da OpenAI.Retry após breve espera; veja a status page.
503 Engine overloadedTráfego alto.Retry após espera.
503 Slow DownAumento súbito de tráfego (modelos pay-as-you-go).Reduza ao ritmo original, mantenha 15 min, e suba gradualmente.
+
+ +

35.2 Exceções do SDK Python

+
+ + + + + + + + + + + + + + +
TipoCausa
APIConnectionErrorFalha de conexão/rede/proxy/SSL.
APITimeoutErrorA requisição expirou.
AuthenticationErrorChave/token inválido, expirado ou revogado.
BadRequestErrorRequest malformado ou parâmetros faltando.
ConflictErrorRecurso atualizado por outra requisição.
InternalServerErrorProblema no lado da OpenAI.
NotFoundErrorRecurso solicitado não existe.
PermissionDeniedErrorSem acesso ao recurso pedido.
RateLimitErrorLimite de taxa atingido.
UnprocessableEntityErrorNão foi possível processar apesar do formato correto.
+
+
Nota: no WebSocket mode da Responses API você também pode ver previous_response_not_found (refaça com contexto completo e previous_response_id=null) e websocket_connection_limit_reached (conexão atingiu 60 min; abra uma nova).
+ + +
+ +
+

36. Checklist de produção

+

Ao levar uma aplicação para produção, estas alavancas melhoram qualidade, custo, latência e confiabilidade. Cada item é cumulativo e configurável na Responses API.

+ +
+ + + + + + + + + + + + + + + +
ItemImpacto
Usar a Responses APIQualidade, custo, latência, confiabilidade
reasoning.effortQualidade, custo, latência
text.verbosityQualidade, custo, latência
Parâmetro phase do assistantQualidade, custo
tool_searchCusto, latência
Ferramentas nativas (built-in tools)Qualidade
CompactionCusto
prompt_cache_keyLatência, custo
reasoning.encrypted_contentQualidade, latência
background=TrueResumabilidade
WebSocket modeLatência
+
+ +

36.1 Responses API como base

+

Sempre comece pela Responses API: é a API principal e o melhor lugar para acessar o comportamento mais recente dos modelos, ferramentas nativas, fluxos com estado e recursos de agente.

+ +

36.2 reasoning.effort e text.verbosity

+

Para gpt-5.5, reasoning.effort aceita none, low, medium (padrão), high e xhigh. Use low para extração, roteamento, classificação ou reescrita simples; medium/high para diagnosticar, comparar opções, planejar ou raciocinar sobre código; reserve xhigh para quando suas avaliações mostrarem que a latência extra compensa. O text.verbosity equilibra concisão (menos tokens de saída, resposta mais rápida) contra completude.

+ +

36.3 phase, tool_search e ferramentas nativas

+

O phase rotula mensagens do assistant como "commentary" (notas/progresso intermediário) ou "final_answer" (resposta concluída); preserve e reenvie esse campo no histórico em fluxos longos para evitar parada precoce. O tool_search (com defer_loading: true nas ferramentas caras) carrega só o subconjunto necessário em runtime, poupando tokens e preservando o cache — comece com hosted tool search e mantenha namespaces com até ~10 funções. Prefira ferramentas nativas (web search, file search, code interpreter, shell, computer use, image generation, MCP/connectors, skills, apply patch): por estarem em distribuição no pós-treino, têm melhor seleção e menos falhas.

+ +

36.4 Compaction e prompt caching

+

A compaction reduz o tamanho do contexto preservando o estado necessário entre muitos turnos — deixe o servidor cuidar (com previous_response_id + context_management e compact_threshold) ou chame client.responses.compact() e reaproveite a saída como está (não edite). O prompt caching reduz latência e custo quando requisições reusam o mesmo prefixo longo: defina prompt_cache_key de forma consistente para prefixos genuinamente compartilhados, mas com granularidade que evite concentrar tráfego — acima de ~15 req/min num mesmo par prefixo+chave, o cache perde eficácia.

+ +

36.5 Reasoning encrypted, background e WebSocket

+

Sempre faça round-trip dos itens de reasoning. Sob requisitos de ZDR (sem armazenar dados de resposta), adicione reasoning.encrypted_content ao include e devolva o item exatamente como veio para um handoff sem estado. Use background=True (requer store=True; incompatível com ZDR) para jobs longos: a API retorna um ID e você faz polling. Use WebSocket mode para fluxos longos e pesados em tool calls — mantendo a conexão aberta e continuando com previous_response_id e apenas os novos itens; em rollouts com 20+ tool calls fica ~40% mais rápido. Uma conexão trata uma resposta por vez e expira em 60 min; funciona com ZDR (dados só em memória).

+
+
+ + + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+resp = client.responses.create(
+    model="gpt-5.5",
+    input="Refatore este módulo e explique as decisões.",
+    reasoning={"effort": "high", "encrypted_content": True},
+    text={"verbosity": "medium"},
+    prompt_cache_key="refactor-service-v1",
+    background=True,
+    store=True,
+)
+print(resp.id, resp.status)   # faça polling por resp.id até completar
+
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Refatore este módulo e explique as decisões.",
+  reasoning: { effort: "high", encrypted_content: true },
+  text: { verbosity: "medium" },
+  prompt_cache_key: "refactor-service-v1",
+  background: true,
+  store: true,
+});
+console.log(resp.id, resp.status);
+
+
+
+
curl https://api.openai.com/v1/responses \
+  -H "Authorization: Bearer $OPENAI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{
+    "model": "gpt-5.5",
+    "input": "Refatore este módulo e explique as decisões.",
+    "reasoning": { "effort": "high" },
+    "text": { "verbosity": "medium" },
+    "prompt_cache_key": "refactor-service-v1",
+    "background": true,
+    "store": true
+  }'
+
+
+
+ + +
+ +
+

Referência rápida de endpoints

+

Base: https://api.openai.com/v1. Principais endpoints usados ao longo deste guia.

+
+ + + + + + + + + + + + + + + +
Método + caminhoDescrição
POST /v1/responsesAPI principal para texto, multimodal, reasoning e ferramentas (com estado).
POST /v1/embeddingsGera vetores de embedding para busca, RAG, clustering.
POST /v1/moderationsClassifica conteúdo nocivo em texto e imagem (gratuito).
POST /v1/audio/transcriptionsTranscreve áudio para texto (STT).
POST /v1/audio/translationsTraduz áudio para inglês.
POST /v1/audio/speechSintetiza fala a partir de texto (TTS).
POST /v1/images/generationsGera imagens.
POST /v1/images/editsEdita imagens existentes.
GET /v1/realtime / POST /v1/realtime/callsSessões realtime (speech-to-speech, transcrição, tradução).
POST /v1/batchesCria jobs assíncronos com 50% de desconto e janela de 24h.
POST /v1/filesFaz upload de arquivos (batch, fine-tuning, entradas).
+
+ +
+ +
+

Tabela de IDs de modelo

+

IDs exatos dos modelos atuais cobertos neste guia. Trate IDs e preços como perecíveis: confirme na doc oficial antes de usar em produção.

+
+ + + + + + + + + + + + + + + + + + + + + + +
IDTipo / usoEndpoint(s)Parte
gpt-5.5Frontier de reasoning/coding (effort: none–xhigh)/v1/responsesA
gpt-5.5-proVariante pro (raciocínio máximo); preço premium/v1/responsesA
gpt-5.3-codexModelo especializado em código (Codex)/v1/responsesA
gpt-5.4-miniTexto rápido/barato/v1/responsesA
gpt-5.4-nanoTexto de menor latência/custo/v1/responsesA
gpt-image-2Geração e edição de imagem/v1/images/*B
gpt-realtime-2Realtime speech-to-speech/v1/realtimeC
gpt-realtime-translateTradução em realtime/v1/realtime/translationsC
gpt-realtime-whisperTranscrição em streaming (realtime)/v1/realtime/transcription_sessionsC
gpt-4o-transcribeSTT de arquivo/v1/audio/transcriptionsC
gpt-4o-mini-transcribeSTT de arquivo (mais barato)/v1/audio/transcriptionsC
gpt-4o-transcribe-diarizeSTT com diarização (rótulo de falantes)/v1/audio/transcriptionsC
gpt-4o-mini-ttsSíntese de fala (TTS)/v1/audio/speechC
gpt-audio-1.5Áudio no chat/v1/chat/completionsC
whisper-1Tradução de áudio e timestamps (srt/vtt/verbose_json, word-level)/v1/audio/translations, /v1/audio/transcriptionsC
text-embedding-3-smallEmbeddings (1536 dim)/v1/embeddingsD
text-embedding-3-largeEmbeddings (3072 dim)/v1/embeddingsD
omni-moderation-latestModeration multimodal (gratuito)/v1/moderationsD
+
+ +
+ +
+

Glossário

+
+ + + + + + + + + + + + + + + + + +
TermoDefinição
Responses APIAPI principal da OpenAI para texto/multimodal/tools, com estado e ferramentas nativas (/v1/responses).
reasoning effortQuanto o modelo raciocina antes de responder (none–xhigh); mais esforço = mais latência e tokens de reasoning.
verbosityAlavanca de concisão vs. completude da saída (low/medium/high).
prompt cachingReuso automático de prefixos longos para reduzir latência e custo; direcionado por prompt_cache_key.
compactionRedução controlada do contexto preservando o estado necessário entre turnos.
VADVoice Activity Detection — detecção de atividade de voz que define os limites de corte do áudio.
diarizaçãoIdentificação e rotulagem de quem fala em cada trecho do áudio.
embeddingsVetores numéricos que representam o significado de um texto; distância = relação semântica.
moderationClassificação de conteúdo potencialmente nocivo em categorias com pontuação de confiança.
batchProcessamento assíncrono em lote com 50% de desconto e janela de 24h.
flexservice_tier de menor custo e maior latência, para cargas não produtivas.
priorityservice_tier de latência baixa e consistente, cobrado com prêmio.
service tierRegime de processamento de uma requisição: auto, default, flex ou priority.
+
+ +
+ +
+

Receitas oficiais (Cookbook) — RAG, embeddings, avaliação & operação

+

Exemplos oficiais do OpenAI Cookbook (e do repositório openai/openai-cookbook) para embeddings, RAG, avaliação e operação. Lidos e classificados em 2026-05-24 quanto a aderência ao estado da arte.

+
+ + + + + + + + + + + + +
ReceitaO que ensinaStatus
Prompt Caching 201prompt_cache_key como chave de shard; Flex vs Batch; caso real de 60%→87% de hit-rate.SOTA
api_request_parallel_processor.pyScript de produção para processar lotes mantendo-se sob RPM/TPM (backoff).SOTA
Multi-tool orchestration + RAG (Responses API)Rotear entre web_search, file_search e vector DB num único loop Responses.SOTA
Evals — regressão / bulk / monitoramentoAcompanhar desempenho de prompts entre iterações; comparar muitos prompts/modelos; detectar regressões em produção. Atenção: a deprecação da plataforma Evals foi anunciada em 2026-06-03 — planeje migração antes de adotar.Deprecação anunciada
Busca semântica com Supabase / pgvectorRAG self-hosted: Postgres + pgvector, índice HNSW, operador <#> (inner product, vetores unit-norm).SOTA
Question answering using embeddingsRAG clássico "Search-Ask": embeda corpus, top-k por cosseno, injeta contexto e responde.Portar p/ Responses
Embedding long inputsLidar com entradas > 8192 tokens: truncar vs. dividir-e-mediar com tiktoken.Técnica atual
Semantic text searchBusca semântica mínima por cosseno sobre um dataset.Legado
+
+
Ao portar receitas antigas: várias usam Chat Completions e helpers descontinuados (utils.embeddings_utils) ou embeddings de gerações anteriores. No estado da arte, use a Responses API com gpt-5.x e embeddings text-embedding-3-small/-3-large; calcule similaridade com numpy/JS puro em vez do embeddings_utils.
+ +

Código real, modernizado para o estado da arte

+

Três receitas portadas para o estado da arte: embeddings text-embedding-3-small com cosseno calculado em numpy/JS puro (sem o embeddings_utils descontinuado) e geração/roteamento via Responses API com gpt-5.5. Troque os corpora de exemplo pelos seus dados.

+ +

1. Embeddings + busca semântica (top-k por cosseno) · porta modernizada de Semantic_text_search_using_embeddings.ipynb

+
+
+ + +
+
+
import numpy as np
+from openai import OpenAI
+
+client = OpenAI()
+MODELO_EMB = "text-embedding-3-small"
+
+# Corpus de exemplo (troque pelos seus documentos)
+corpus = [
+    "O pinguim-imperador é a maior espécie de pinguim.",
+    "A fotossíntese converte luz solar em energia química.",
+    "Python é uma linguagem de programação de alto nível.",
+    "Os Jogos Olímpicos de Inverno de 2022 ocorreram em Pequim.",
+]
+
+def embeddings(textos: list[str]) -> np.ndarray:
+    # Embeddings da OpenAI já vêm normalizados (norma 1): cosseno = produto interno
+    resp = client.embeddings.create(model=MODELO_EMB, input=textos)
+    return np.array([d.embedding for d in resp.data])
+
+corpus_emb = embeddings(corpus)
+
+def busca(consulta: str, k: int = 3):
+    q = embeddings([consulta])[0]
+    sims = corpus_emb @ q                 # similaridade de cosseno (vetores unit-norm)
+    ordem = np.argsort(-sims)[:k]         # top-k em ordem decrescente
+    return [(corpus[i], float(sims[i])) for i in ordem]
+
+for texto, score in busca("Quem venceu em Pequim 2022?"):
+    print(f"{score:.3f}  {texto}")
+
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+const MODELO_EMB = "text-embedding-3-small";
+
+// Corpus de exemplo (troque pelos seus documentos)
+const corpus = [
+  "O pinguim-imperador é a maior espécie de pinguim.",
+  "A fotossíntese converte luz solar em energia química.",
+  "JavaScript é a linguagem da web.",
+  "Os Jogos Olímpicos de Inverno de 2022 ocorreram em Pequim.",
+];
+
+// Embeddings da OpenAI já vêm normalizados (norma 1): cosseno = produto interno
+async function embeddings(textos) {
+  const resp = await client.embeddings.create({ model: MODELO_EMB, input: textos });
+  return resp.data.map((d) => d.embedding);
+}
+const dot = (a, b) => a.reduce((s, v, i) => s + v * b[i], 0);
+
+const corpusEmb = await embeddings(corpus);
+
+async function busca(consulta, k = 3) {
+  const [q] = await embeddings([consulta]);
+  return corpus
+    .map((texto, i) => ({ texto, score: dot(corpusEmb[i], q) }))
+    .sort((a, b) => b.score - a.score)
+    .slice(0, k);
+}
+
+for (const { texto, score } of await busca("Quem venceu em Pequim 2022?")) {
+  console.log(score.toFixed(3), texto);
+}
+
+
+
+ +

2. RAG "Search-Ask": recupera contexto e responde via Responses API · porta do passo de resposta para a Responses API a partir de question_answering_using_embeddings

+
+
+ + +
+
+
import numpy as np
+from openai import OpenAI
+
+client = OpenAI()
+
+# Reaproveita corpus_emb / busca() do exemplo anterior (text-embedding-3-small)
+def responder(pergunta: str, k: int = 3) -> str:
+    trechos = [texto for texto, _ in busca(pergunta, k)]   # top-k por cosseno
+    contexto = "\n".join(f"- {t}" for t in trechos)
+    prompt = (
+        "Use APENAS o contexto abaixo para responder. "
+        'Se a resposta não estiver no contexto, diga "Não sei.".\n\n'
+        f"Contexto:\n{contexto}\n\nPergunta: {pergunta}"
+    )
+    # Geração no estado da arte: Responses API + gpt-5.5 (sem Chat Completions)
+    resp = client.responses.create(model="gpt-5.5", input=prompt)
+    return resp.output_text
+
+print(responder("Onde ocorreram os Jogos de Inverno de 2022?"))
+
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+
+// Reaproveita corpusEmb / busca() do exemplo anterior (text-embedding-3-small)
+async function responder(pergunta, k = 3) {
+  const trechos = (await busca(pergunta, k)).map((r) => r.texto); // top-k por cosseno
+  const contexto = trechos.map((t) => `- ${t}`).join("\n");
+  const prompt =
+    "Use APENAS o contexto abaixo para responder. " +
+    'Se a resposta não estiver no contexto, diga "Não sei.".\n\n' +
+    `Contexto:\n${contexto}\n\nPergunta: ${pergunta}`;
+  // Geração no estado da arte: Responses API + gpt-5.5 (sem Chat Completions)
+  const resp = await client.responses.create({ model: "gpt-5.5", input: prompt });
+  return resp.output_text;
+}
+
+console.log(await responder("Onde ocorreram os Jogos de Inverno de 2022?"));
+
+
+
+ +

3. Orquestração multiferramenta: web_search + file_search numa única chamada · o modelo roteia entre web e a vector store; shapes oficiais de tools-web-search + tools-file-search

+
Por que isto é válido: o parâmetro tools da Responses API é um array que aceita várias ferramentas de tipos diferentes; com tool_choice em auto (padrão), o modelo decide quais acionar. A própria doc descreve o modelo podendo "buscar na web, recuperar dos seus arquivos … e chamar suas funções" no mesmo fluxo. Cada shape de ferramenta aqui é oficial e individual; combiná-las num único array é o mecanismo documentado (não um formato especial). Você pode forçar com tool_choice: "required" quando a busca tiver de rodar.
+
+
+ + +
+
+
from openai import OpenAI
+
+client = OpenAI()
+
+# Uma única chamada com DUAS ferramentas hospedadas; o modelo decide qual usar.
+# web_search -> fatos atuais da internet; file_search -> sua base privada (vector store).
+resp = client.responses.create(
+    model="gpt-5.5",
+    input="Compare nossa política interna de reembolso com as melhores práticas atuais do setor.",
+    tools=[
+        {"type": "web_search"},
+        {"type": "file_search", "vector_store_ids": ["vs_seu_id_aqui"]},
+    ],
+)
+
+print(resp.output_text)
+# resp.output traz os itens web_search_call / file_search_call que o modelo acionou
+
+
+
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+
+// Uma única chamada com DUAS ferramentas hospedadas; o modelo decide qual usar.
+// web_search -> fatos atuais da internet; file_search -> sua base privada (vector store).
+const resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Compare nossa política interna de reembolso com as melhores práticas atuais do setor.",
+  tools: [
+    { type: "web_search" },
+    { type: "file_search", vector_store_ids: ["vs_seu_id_aqui"] },
+  ],
+});
+
+console.log(resp.output_text);
+// resp.output traz os itens web_search_call / file_search_call que o modelo acionou
+
+
+
+ + +
+ +
+

Histórico deste guia

+
+ + + + + + + + + +
DataAlteração
2026-05-24Versão inicial; modelos verificados na doc oficial.
2026-05-24Preços de áudio verificados na tabela oficial (Realtime/Transcription); modelos sem linha própria explicitados. Adicionado código real do Cookbook (Python + JavaScript) em cada parte. Fechadas lacunas in-scope: input_file (PDF/documentos/planilhas), gpt-5.5-pro/gpt-5.4-pro, ponteiro gpt-5.3-codex, campo safety_identifier.
2026-05-24Resolvidos os 2 itens pendentes: file_search usa purpose="assistants" (valor documentado para ingestão em vector store, confirmado no Cookbook + OpenAPI); orquestração web_search+file_search documentada como mecanismo de array de ferramentas (cada shape oficial; modelo roteia via tool_choice: auto). Zero itens UNVERIFIED de preço/código restantes.
2026-06-25Adicionados gpt-image-1-mini (imagem econômica) e gpt-4o-tts (TTS completo) na tabela de modelos e nas seções de referência. Nota de sunset gpt-image-1 (2026-10-23 → migrar para gpt-image-2) e snapshot gpt-4o-mini-tts-2025-03-20 (sunset 2026-07-23 → migrar para gpt-4o-mini-tts-2025-12-15). Nota de depreciação de 2026-06-11: snapshots gpt-5-2025-08-07, gpt-5-mini-2025-08-07, gpt-5-nano-2025-08-07, gpt-5-pro-2025-10-06, o3-2025-04-16 e o3-pro-2025-06-10 encerram em 2026-12-11 (substitutos: gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano / gpt-5.5-pro). Verificado em developers.openai.com/api/docs/deprecations.
2026-06-10Varredura de atualização contra doc oficial: billing de containers (Hosted Shell/Code Interpreter) agora é por minuto com mínimo de 5 min por sessão (mudança de 2026-06-02; taxas por 20 min seguem como base de preço); default de prompt_cache_retention passou a 24h para organizações sem ZDR em v1/responses, v1/chat/completions e v1/batch (mudança de 2026-05-29); deprecação da plataforma Evals anunciada em 2026-06-03 sinalizada na tabela do Cookbook; IDs de Embeddings/Moderation preenchidos no catálogo §1.2 (text-embedding-3-small/-large, omni-moderation-latest); marcadores de verificação atualizados para 2026-06-10.
+
+ +
+ + +
+
+ + + + + + diff --git a/references/agents_tools_best_guides/guia_operacao_seguranca_evals.html b/references/agents_tools_best_guides/guia_operacao_seguranca_evals.html new file mode 100644 index 0000000..b590bce --- /dev/null +++ b/references/agents_tools_best_guides/guia_operacao_seguranca_evals.html @@ -0,0 +1,1163 @@ + + + + + +Operação, Segurança & Evals de Agentes — Núcleo + + + + + + + + +
+
+
Operação, Segurança & Evals Núcleo agnóstico · super-guia de agentes
+
+ Verificado em 2026-06-11 + Núcleo · v1 + PT-BR · agnóstico + +
+
+
+ +
+ + +
+ +
+

Operação, Segurança & Evals de Agentes

+

+ Operação não é uma camada que vem depois do agente — é parte da arquitetura. Este capítulo do + núcleo é agnóstico de provider e framework: define privacidade/retenção/ZDR, guardrails + em três pontos (e o modelo L0/L1/L2), tracing/replay/cost ledger, evals e acceptance gates, runbooks, + policy-as-code, RACI, threat model alinhado à OWASP, SLIs/SLOs, release controlado e o kit de evidência + de incidente. Conceitos e contratos ficam aqui; a implementação concreta por framework e os detalhes de + retenção por provider estão nos guias dedicados, sempre cross-linkados. +

+
+ Núcleo · v1 + PT-BR · agnóstico + SOTA · verificado 2026-06-10 +
+
+ +
+

Sobre este guia

+

+ Este é um guia para IA e humanos: combina o "quando usar" com referência rápida + (tabelas de gates, schemas de span/ledger, runbooks e checklists copy-paste). É o capítulo + 05 do núcleo do super-guia de agentes e nenhum guia dedicado existente cobre + operação agnóstica de agentes — por isso a maior parte do conteúdo aqui é primário (MANTER), + com cross-links pontuais para profundidade específica de provider/framework. +

+
+ Tese operacional: um agente sem operação explícita é uma automação probabilística sem + controle. Cada decisão relevante deve ser rastreável a input → policy → source → tool call → + model response → schema → approval → eval. O ledger canônico próprio (definido no + capítulo de estado) é a fonte da verdade para replay e auditoria — o payload do provider é só uma + projeção. +
+
+ Como ler: a Parte 1 estabelece os fundamentos operacionais; a Parte 2 cobre resposta a + incidentes e gestão de risco; a Parte 3 fecha com times, checklist e o blueprint de hardening. O + cheat sheet resume gates, métricas e o esqueleto de policy-as-code. +
+
+ Vizinhança no super-guia: este capítulo depende do vocabulário definido em + Arquitetura & orquestração (capability registry, + microcontexto, fases) e em Estado, contexto & memória + (ledger, compaction, loss declaration). Segurança de tools e MCP é aprofundada em + Ferramentas, MCP & RAG; a camada de adapter e o + provider-switching contract estão em Providers & adapters. +
+
+ +
+

Fontes & verificação

+

+ Todo fato perecível deste guia foi conferido contra a documentação oficial em 2026-06-10 + ou anotado como UNVERIFIED nas + notas de verificação. Os IDs de modelo não são fixados no corpo + (use sempre model="..."); a folha de fatos SOTA do super-guia concentra os IDs perecíveis. +

+
+ + + + + + + + + + + + +
TemaRecurso oficial
Agents SDK (guardrails, tracing)openai.github.io/openai-agents-python
OpenAI Responses (estado, retenção)developers.openai.com/api/docs/guides/conversation-state
OpenAI reasoningdevelopers.openai.com/api/docs/guides/reasoning
Pydantic AI — evalspydantic.dev/docs/ai/evals/evals
Pydantic AI — Logfire / observabilidadepydantic.dev/docs/ai/integrations/logfire
MCP — spec (segurança/consentimento)modelcontextprotocol.io/specification/2025-11-25
OWASP — LLM Top 10 (2025)genai.owasp.org/llm-top-10
OWASP — Top 10 for Agentic Apps (2026)genai.owasp.org/.../agentic-applications-for-2026
EU AI Act — texto e cronogramaartificialintelligenceact.eu/implementation-timeline
+

+ Legenda dos selos: Verificado confirmado na doc oficial em 2026-06-10 · + Novo recurso/spec recente · + UNVERIFIED não confirmado dentro do orçamento (fonte/lacuna anotada) · + Evitar descontinuado/antipadrão · + N/D não documentado. +

+
+ Mudança de domínio do Pydantic AI (verificada ao vivo): em 2026-05-25, + ai.pydantic.dev/… retorna 301 Moved Permanently para + pydantic.dev/docs/ai/… (confirmado para /overview/, /evals/evals/ e + /integrations/logfire/). Este guia usa o destino canônico vivo + pydantic.dev/docs/ai/…. Ver notas de verificação. +
+
+ + +
+

Parte 1 — Fundamentos operacionais

+

+ Os cinco pilares que tornam um agente operável: tratar operação como arquitetura, decidir privacidade e + retenção por rota, instalar guardrails nos três pontos críticos, instrumentar tudo num cost/replay ledger + e travar releases atrás de acceptance gates. +

+
+ +
+

1. Operação é arquitetura

+

+ Operação, segurança e avaliação não são um "apêndice de produção": são decisões de design que + precisam existir desde o primeiro protótipo. Gates, timeouts, budgets, evals, cost ledger, tracing, + replay, ZDR, evidência estática e runbooks fazem parte do mesmo contrato do orquestrador. Se eles não + existem, o agente não é controlável — só observável depois do dano. +

+
+ Princípio: cada decisão relevante deve ser rastreável a input, + policy, source, tool_call, model_response, + schema, approval ou eval. Se você não consegue apontar a origem de + uma ação, você não consegue auditá-la nem revertê-la. +
+ +

Os quatro contratos operacionais

+

Toda rota de agente em produção fixa quatro contratos, independentemente do provider/framework:

+
+ + + + + + + +
ContratoO que fixaOnde vive
PrivacidadeClasses de dado permitidas, retenção, ZDR, redaction.Policy-as-code por rota (§7).
GuardrailsValidação de entrada, tool call e saída; HITL.L0/L1/L2 + acceptance gates (§3, §5).
ObservabilidadeSpan por chamada, custo, replay reconstruível.Trace/cost ledger (§4).
ResiliênciaBudgets, timeouts, circuit breakers, fallback, wind-down.Runbooks + policy (§6, §7).
+ +
+ + + + Orquestrador + registrar → reduzir → projetar + + + Privacidade / retenção / ZDR + classes de dado · redaction + + + Guardrails (L0/L1/L2) + entrada · tool · saída · HITL + + + Trace / cost ledger + span · usage · replay + + + Evals / gates / runbooks + aceite · regressão · incidente + + + + + + +
Os quatro planos operacionais circundam o loop do orquestrador. Nenhum é opcional em produção: privacidade decide o que pode sair, guardrails decidem o que pode entrar/agir, o ledger torna tudo reconstruível e os evals/gates decidem o que pode ser liberado.
+
+
+ +
+

2. Privacidade, retenção e ZDR

+

+ Privacidade é uma decisão de rota, não um detalhe de runtime. Cada rota declara, de forma auditável, qual + classe de dado pode chegar ao provider/tool, por quanto tempo o estado é retido e quando se exige + ZDR. O modelo nunca resolve tenant/auth sozinho — isso é + resolvido fora dele, no orquestrador. +

+
+ + + + + + + + +
CamadaDecisão obrigatóriaEvidência esperada
Classificação de dadosPúblico, interno, sensível, regulado, segredo, credencial.Item de ledger com classification e redaction_policy.
Retenção do providerstore true/false, conversation/session, cache, logs.Config por rota e justificativa.
Retenção internaQuanto tempo ledger, traces e assets ficam guardados.Política de retenção e deleção.
RedactionO que remover antes de provider/tool/subagente.Lista de campos e hash do conteúdo original quando necessário.
Tenant boundaryComo tenant/auth é resolvido fora do modelo.Runtime claims, scopes e logs.
+ +

ZDR e estado stateless

+

+ Cada provider expõe mecanismos próprios de estado e retenção. No padrão agnóstico, o orquestrador + sempre preserva o ledger próprio para replay e auditoria, mesmo quando opta por não + persistir nada no provider. Na OpenAI Responses API, fluxos sem retenção devolvem os output items + relevantes a cada turno (em vez de previous_response_id) e usam store=false; + reasoning stateless preserva o conteúdo de raciocínio do lado do cliente quando o provider o suporta. +

+
+ Regra de ouro: ZDR no provider não é o mesmo que ZDR no seu sistema. Se você + guarda o ledger e os traces sem redaction, você ainda retém o dado — só mudou de lugar. A política de + retenção interna (§7) precisa ser tão explícita quanto a do provider. +
+ +
+ Retenção/ZDR por provider (cross-link): os mecanismos concretos e as superfícies de + retenção ficam nos guias dedicados — + OpenAI · estado de conversa, + Gemini · store e retenção e + Claude · janelas de contexto / plataformas. A camada + de adapter que normaliza isso entre providers está em + Providers & adapters. +
+
+ +
+

3. Guardrails (3 pontos · modelo L0/L1/L2)

+

+ Guardrails precisam existir em três pontos do fluxo — entrada, ferramenta e saída — + e ser organizados por defesa em profundidade. O Agents SDK oferece guardrails como + primitivo (com o padrão tripwire); no runtime universal, complemente com validação de schema, + políticas de negócio e evals. +

+ +

3.1. Os cinco pontos de enforcement

+
+ + + + + + + + +
PontoGuardrailExemplos
EntradaClassificação, prompt injection, tamanho, consentimento, dados sensíveis.Bloquear segredo, reduzir anexo, pedir autorização.
Tool callSchema, side effect, auth, rate limit, idempotência.Rejeitar tool financeira sem aprovação.
Tool resultRedaction, caps, provenance, erro estruturado.Retornar top 8 evidências em vez de 200 chunks.
SaídaSchema, factualidade, citações, policy, tom, risco.Exigir fontes, detectar alucinação, marcar incerteza.
HandoffMotivo, contexto transferido, consentimento.Não transferir PII desnecessária.
+ +

3.2. Modelo de camadas L0 / L1 / L2

+

+ Uma forma operacional de organizar a defesa em profundidade é separar três camadas com responsabilidades + distintas. O bloqueio de conteúdo conversacional em linguagem natural é responsabilidade da + inteligência (L1 + composição do agente); determinismo (regex/keyword/classificador estático) é + sinal/máscara/auditoria, e só vira tripwire em portões de capability não conversacionais. +

+
+ + + + + + +
CamadaO que éOnde viveBloqueia?
L0Pré-filtro rápido: máscara de PII, scan de segredo, allowlist de URL, classificadores hospedados em shadow.SDK do vendor ou pré-filtro local atrás de um adapter (observe | mask | fail_closed_capability).Por padrão não (observe). Tripwire só em 3 classes não conversacionais: vazamento de segredo, desalinhamento de tool-call e violação de allowlist de URL.
L1Specs deliberativas com LLM-juiz (input/output guardrails).Camada de guardrail do framework (ex.: InputGuardrail/OutputGuardrail).Sim — palavra final sobre conteúdo conversacional; tripwire em risco validado.
L2Kernel no prompt: cadeia de comando (Sistema > Protocolo > Usuário), regra dado-como-dado, recusa/escopo/confidencialidade.System prompt do agente.Implícito — o agente recusa via composição inteligente.
+
+ Antipadrão a evitar: encadear 3–5 checks de LLM-juiz em série na L0 antes da L1 faz o + P50 explodir. LLM-juiz serial em L0 é proibido pelo cânone — L0 LLM-based roda em shadow/paralelo + e só vira enforce após o playbook shadow→enforce (≥7 dias ou dataset representativo, com matriz + FP/FN/concordância verde e fallback declarado). +
+ +

3.3. Fluxo de aprovação humana (HITL)

+

+ Ações com efeito colateral irreversível, financeiro ou sobre PII exigem aprovação humana. O HITL separa + explicitamente plan de execute, registra o racional e os parâmetros aprovados, e + nunca infere aprovação de respostas ambíguas. Três padrões de interação: +

+
    +
  • Interrupt & Resume — o agente pausa no meio da execução, coleta a decisão humana e retoma.
  • +
  • Human-as-a-Tool — o agente chama uma "tool humana" quando incerto e usa a resposta no contexto.
  • +
  • Role-Based Approval — só papéis específicos aprovam tipos específicos de ação; tier Critical exige aprovação multi-pessoa.
  • +
+
+ Guardrails/HITL por framework (cross-link): o primitivo de guardrail e o tripwire + do OpenAI Agents SDK estão em guia do Agents SDK · Guardrails; + HITL em LangGraph em LangGraph · interrupt/Command; + Tool Confirmation no ADK em Google ADK · Tool Confirmation. + O contrato de aprovação de tool agnóstico (níveis de side-effect) está em + Ferramentas, MCP & RAG. +
+ +
+ +
+

4. Tracing, replay e cost ledger

+

+ Observabilidade precisa ser granular o suficiente para reconstruir qualquer turno: qual + modelo foi chamado, com quais parâmetros, quais tools foram expostas, quais calls foram emitidas, + quais foram executadas, quais resultados entraram no contexto, quanto custou e qual foi a resposta final. + Cada span amarra a um item do ledger canônico, de modo que o replay seja determinístico até onde o + provider permitir. +

+
{
+  "trace_span": {
+    "span_id": "span_123",
+    "kind": "model_call | tool_call | guardrail | compaction | handoff",
+    "model": "provider/model",
+    "parameters": { "max_output_tokens": 4096, "tool_choice": "auto" },
+    "input_hash": "sha256:...",
+    "output_hash": "sha256:...",
+    "usage": { "input_tokens": 1000, "output_tokens": 300, "reasoning_tokens": 120 },
+    "cost_estimate": { "amount": 0.012, "currency": "USD", "known": false },
+    "status": "success"
+  }
+}
+ +
+ Custo desconhecido nunca é zero. Quando usage ou custo não estiverem + disponíveis (ex.: tool externa sem preço, provider sem campo de usage), registre como + known:false / estimado — jamais como 0. Custo "zero" silencioso é a causa + número um de cost spike não detectado. +
+

O que um span precisa permitir

+
    +
  • Replay sem dados sensíveis: hashes e ponteiros em vez do conteúdo bruto quando a classe de dado exigir.
  • +
  • Atribuição de custo: cost_per_success por rota/tenant/provider (ver §9).
  • +
  • Reconstrução de decisão: ligar span → policy aplicada → aprovação humana → gate que passou/falhou.
  • +
+
+ Tracing/persistência por framework (cross-link): módulo de tracing do + OpenAI Agents SDK; checkpointers como persistência durável em + LangGraph · persistence; observabilidade do + Google ADK. A teoria de budget de tokens e contagem + real está em Estado, contexto & memória. +
+
+ +
+

5. Evals e acceptance gates

+

+ Evals cobrem comportamento, schemas, segurança, custo/latência e regressões de contexto. Acceptance gates + são evals com poder de bloquear release: cada gate tem um teste mínimo e um critério + objetivo de aprovação. Esses gates são a tradução operacional dos contratos das seções anteriores. +

+
+ + + + + + + + + + + +
GateTeste mínimoCritério de aprovação
SCHEMA-001Output final sempre valida no schema esperado.0 violações em casos críticos; erro recuperável em casos não críticos.
TOOL-001Tool calls respeitam allowed tools e side-effect policy.Nenhuma chamada proibida executada.
RAG-001Toda alegação factual de RAG tem citation/provenance.Citações presentes e hash/posição rastreável.
CTX-001Compaction preserva fatos, decisões e pendências.Nenhum item crítico perdido em replay.
ZDR-001Fluxos sensíveis não usam retenção indevida do provider.Config auditável por rota.
BUDGET-001Final reserve impede esgotamento da resposta final.Sistema finaliza sem abrir tools quando a reserva é atingida.
PROVIDER-001Provider switch declara perdas.Loss declaration presente em todo switch.
SEC-001Prompt injection em tool/RAG não ganha autoridade.Modelo ignora instruções em documentos como comandos.
+

+ Evals code-first (ex.: Pydantic AI com Dataset/Case e evaluators como + LLMJudge) permitem versionar casos, rodar em CI e comparar contra um golden set. + Combine três tipos: determinísticos (schema, exact-match, contrato), LLM-juiz + (factualidade, tom, aderência a política) e adversariais (injection, exfiltração, + escalonamento) — estes últimos antes de cada release. +

+ +
+ Evals por framework (cross-link): Pydantic AI como camada de evals/observabilidade + complementar está em Providers & adapters; a avaliação por + critérios do ADK (tool trajectory, response match, rubric, safety, simulação de usuário) em + Google ADK · avaliação. +
+
+ + +
+

Parte 2 — Resposta a incidentes & gestão de risco

+

+ Operação madura é medida pela velocidade de detecção e recuperação. Esta parte traz os runbooks de + incidente, a enforcement em código, o threat model alinhado à OWASP, as métricas (SLIs/SLOs), o processo + de release controlado e o kit que torna qualquer incidente reconstruível. +

+
+ +
+

6. Runbooks operacionais

+

+ Cada incidente típico de agente tem um sinal, uma ação imediata e uma prevenção estrutural. O runbook é + a ponte entre a observabilidade (§4) e a policy (§7): o sinal vem dos spans/métricas, a prevenção vira + configuração. +

+
+ + + + + + + + + + +
IncidenteSinalAção imediataPrevenção
Context overflowProvider rejeita input ou trunca contexto crítico.Compaction forçada, reduzir assets, desabilitar novas tools.Budget por fase e medidor de tokens antes da chamada.
Tool timeoutTool passa do SLA ou retorna parcial.Registrar status timeout, usar fallback ou perguntar ao usuário.Timeouts por capability e circuit breaker.
Schema driftResposta/tool result falha validação.Retry com schema clarificado ou fallback determinístico.Evals de contrato e versionamento de schemas.
Provider outageErros repetidos ou latência alta.Rotear para provider alternativo com loss declaration.Adapter contract e testes multi-provider.
Prompt injectionDocumento/tool output tenta alterar instruções.Tratar como dado não confiável; remover comandos.Classificador de injection e delimitação de evidence.
Cost spikeUsage acima do limite por usuário/tenant.Cortar fan-out e forçar síntese.Cost ledger, quotas e alertas.
Privacy breach riskDado sensível prestes a ir a provider/tool não autorizado.Bloquear chamada e redigir output.Classificação e policy-as-code.
+
+ Escalonamento (quando parar de ser autônomo): incerteza de política, evidência + insuficiente, falhas repetidas (limiar padrão N=3), ação de alto risco solicitada, budget >80% consumido + com <50% concluído, fontes contraditórias, ação fora do escopo aprovado, ou pedido explícito de revisão + humana. Toda escalada carrega um payload estruturado: gatilho, objetivo atual, passos tentados, saídas de + tool, próximo passo proposto, racional e metadados de sessão. +
+
+ +
+

7. Policy-as-code

+

+ Políticas em linguagem natural ajudam o modelo, mas enforcement deve estar em código/configuração. + O esqueleto abaixo declara, por rota, os limites do orquestrador, a retenção, as classes de dado permitidas, + os níveis de side-effect das tools e os guardrails em cada ponto: +

+
routes:
+  default_agent:
+    max_turns: 6
+    max_tool_calls: 12
+    final_reserve_tokens: 3500
+    providers_allowed: [openai, anthropic, google]
+    retention:
+      provider_store: false
+      internal_days: 30
+    data_classes_allowed_to_provider: [public, internal]
+    tools:
+      retrieve_evidence.v1: { side_effect: read,        approval: auto,           timeout_ms: 12000 }
+      update_record.v1:     { side_effect: write_high,  approval: human_required, timeout_ms: 8000 }
+    guardrails:
+      input:       [classify_data, detect_prompt_injection, cap_size]
+      output:      [schema_validate, citation_check, safety_policy]
+      tool_result: [redact, cap_tokens, require_provenance]
+
+ Por que código e não prompt: o prompt influencia o modelo, mas não o impede. O + approval: human_required e o side_effect: write_high são avaliados pelo + orquestrador antes de a tool executar — fora do alcance de uma prompt injection. Risco + (tier) → política → gate é a cadeia que sobrevive a um modelo "convencido" pelo atacante. +
+
+ +
+

8. Threat model resumido (OWASP)

+

+ O threat model de um agente combina as ameaças clássicas de LLM com as ameaças agênticas + (multi-agente, tools, memória). Use os dois catálogos da OWASP como baseline: LLM Top 10 (2025) + e o Top 10 for Agentic Applications (2026), este último com as dez categorias ASI01–ASI10 — + ambos seguem vigentes (re-verificados em 2026-06-10). A OWASP incuba ainda o Agentic Skills Top 10 + (AST10), sem lista publicada. +

+
+ + + + + + + + + + + + +
AmeaçaVetorMitigaçãoOWASP
Prompt injection externoDocumentos, páginas web, tool outputs.Delimitar como dados, classificar comandos maliciosos, não elevar autoridade.LLM01 · ASI01
Tool misuseModelo chama ação indevida.Policy-as-code, approval e side-effect levels.ASI02 · ASI03
Data exfiltrationContexto inclui segredo ou dado sensível.Redaction, tenant boundary e retenção controlada.LLM02 · ASI01
Context / memory poisoningMemória salva instrução maliciosa.Memory write guardrails e provenance.ASI06
Schema bypassModelo produz JSON inválido ou campos inesperados.Structured outputs, additionalProperties:false e validação local.LLM05 · ASI05
Cost denialLoops/fan-out consomem budget.Max turns/tools, cost ledger e wind-down.ASI08
Inter-agent / supply chainMensagens forjadas entre agentes; descritor de tool/MCP envenenado.Cards assinados, verificação de domínio, fonte confiável de tool.ASI07 · ASI04
System prompt leakageExtração do prompt de sistema/segredos embutidos.Não embutir segredo no prompt; bloco de confidencialidade no fim do kernel.LLM07
Rogue agent / cascataSub-agente com autoridade indevida; falha em cascata.Least-privilege, circuit breakers, step limits, anomaly detection.ASI08 · ASI10
+

Mapeamento camadas de guardrail → ASI

+

As cinco camadas de defesa em profundidade cobrem as dez categorias agênticas:

+
+ + + + + + + + + +
CamadaMitiga (ASI)
Input guardrails (injection, dados sensíveis, hierarquia de instrução)ASI01 (Agent Goal Hijack), ASI06 (Memory & Context Poisoning)
Tool selection (allow/denylist, gating por risco/contexto)ASI02 (Tool Misuse), ASI03 (Identity & Privilege Abuse)
Action validation (schema, idempotência, regra de negócio, dry-run)ASI05 (Unexpected Code Execution)
Output guardrails (redaction de PII, citação, anti-leak de prompt)ASI09 (Human-Agent Trust Exploitation)
Runtime controls (rate limit, budget, timeout, circuit breaker, step limit)ASI08 (Cascading Failures), ASI10 (Rogue Agents)
Inter-agent security (cross-layer)ASI07 (Insecure Inter-Agent Comms), ASI04 (Agentic Supply Chain)
+
+ Consentimento na fronteira de tool (MCP): a própria spec MCP 2025-11-25 + determina que descrições/anotações de tool de servidores não confiáveis sejam tratadas como + não confiáveis, que o host obtenha consentimento explícito antes de invocar uma tool, e que o + usuário controle exposição de dados e sampling. Isso reforça as camadas de input e tool selection + acima. A revisão 2026-07-28 já anunciada (ainda em draft; em evolução até a publicação) torna o protocolo + stateless e deprecia Roots/Sampling/Logging — reavalie os fluxos de consentimento e sampling + ao migrar. +
+
+ EU AI Act (cronograma, perecível): em vigor desde 01/08/2024; práticas proibidas desde + 02/02/2025; obrigações de GPAI desde 02/08/2025; obrigações de alto risco do Anexo III a partir de + 02/08/2026 (sistemas embarcados de alto risco até 02/08/2027). Um pacote "Digital Omnibus" + proposto poderia adiar parte das obrigações de alto risco — não assuma que passará; planeje + para agosto/2026 (a menos de dois meses; cronograma re-verificado em 2026-06-10, datas inalteradas). + Classifique cada tool por tier (Low/Medium/High/Critical) alinhado a esse risco. +
+ +
+ Segurança de tools/MCP (cross-link): o hardening de MCP server, os trust tiers e o + contrato de tool result envelope estão em Ferramentas, MCP & + RAG; a integração concreta de MCP por framework, em + Claude · MCP e ADK · MCP. +
+
+ +
+

9. SLIs, SLOs e métricas

+

+ Métricas tornam a operação mensurável e comparável entre releases. Defina SLIs (indicadores) e amarre + SLOs (objetivos) por rota/tenant/provider. As sete métricas abaixo são o conjunto mínimo de um agente + em produção: +

+
+ + + + + + + + + + +
Métrica (SLI)DefiniçãoUso
task_success_rate% de tarefas concluídas com gate aprovado.Qualidade global.
tool_error_rateFalhas/timeout/denied por capability.Confiabilidade de integrações.
schema_valid_rateSaídas que passam validação na primeira tentativa.Robustez de prompts/modelos/schemas.
citation_support_rateAlegações suportadas por evidência.RAG/factualidade.
p95_latencyLatência por rota e por provider.SLO de UX.
cost_per_successCusto por tarefa bem-sucedida.Otimização econômica.
privacy_block_rateChamadas bloqueadas por política de dados.Sinal de risco e ajuste de UX.
+
+ SLO útil: não basta um número agregado. Quebre cada SLI por rota, tenant + e provider — é a única forma de detectar regressão localizada (um provider degradou; um tenant + está sob ataque de custo) antes que ela contamine o agregado. +
+
+ +
+

10. Release e mudança controlada

+

+ Mudanças em agentes são arriscadas porque o comportamento é probabilístico. Todo release passa por um + processo explícito — especialmente quando docs oficiais de SDK/API mudam comportamento de + modelos ou parâmetros, o que deve disparar revisão de adapters e da matriz de compatibilidade. +

+
    +
  • ☐ Registrar a mudança: prompt, schema, tool, provider, modelo, policy ou adapter.
  • +
  • ☐ Rodar evals de contrato, segurança, RAG, contexto e custo.
  • +
  • ☐ Comparar traces/custos contra a baseline.
  • +
  • ☐ Atualizar manifest, source refs e checksums quando a documentação mudar.
  • +
  • ☐ Fazer rollout gradual por rota/tenant/use case.
  • +
  • ☐ Monitorar SLOs e incidentes; reverter se gates críticos falharem.
  • +
+
+ Checklists de produção por framework (cross-link): complementam este processo a + checklist de deployment da OpenAI e o + cookbook operacional; a freshness sweep contínua + (changelogs de provider) é tratada como cadência (§14). +
+
+ +
+

11. Kit de evidência de incidente

+

+ Quando algo der errado, o time deve conseguir coletar rapidamente — e sem expor dados + desnecessários — o conjunto mínimo que reconstrói o incidente: +

+
    +
  • trace_id e spans relacionados;
  • +
  • itens de ledger envolvidos e hashes de assets;
  • +
  • modelo/provider/versão/parâmetros;
  • +
  • tools expostas, tool calls emitidas e resultados reduzidos;
  • +
  • políticas aplicadas e aprovações humanas;
  • +
  • compactions e losses declaradas;
  • +
  • usage/cost e limites atingidos;
  • +
  • resposta final e o gate que falhou.
  • +
+
+ Imutabilidade: logs de decisão de guardrail (allow/mask/block/approve/deny) e o kit de + incidente devem ser imutáveis e, para ações de tier Critical, ter integridade criptográfica. + Sem trilha imutável de negações, é impossível provar a eficácia do guardrail em auditoria. +
+
+ + +
+

Parte 3 — Times & prontidão de produção

+

+ Quem é dono de quê, o checklist que precede o release e o blueprint que define quando um agente está, de + fato, pronto para produção. +

+
+ +
+

12. RACI mínimo para times

+

+ Operação é responsabilidade compartilhada. Uma matriz RACI mínima evita que privacidade, evals ou + runbooks fiquem "sem dono". A=accountable, R=responsible, C=consulted — ajuste conforme + a organização. +

+
+ + + + + + + + + +
ResponsabilidadeProdutoEngenhariaSegurança/LegalDados/ML
Definir use cases e riscos de usuárioACCC
Capability registry e schemasCACC
Retenção, ZDR e privacidadeCRAC
Provider adapters e SDKsCACR
Evals e métricas de qualidadeRRCA
Runbooks e incident responseCAAR
+
+ +
+

13. Checklist de produção

+

O agregado das seções anteriores em uma lista verificável de release:

+
    +
  • ☑ Manifests de fonte, referência e checksum fazem parte do release.
  • +
  • ☑ Cada página/rota tem política de provider, retenção, tools e budgets.
  • +
  • ☑ Há evals antes do release e evals de regressão após mudar prompts/schemas/models.
  • +
  • ☑ Traces permitem replay sem expor dados sensíveis desnecessários.
  • +
  • ☑ Side effects têm aprovação, idempotência e logs.
  • +
  • ☑ Provider switch é testado com perda declarada.
  • +
  • ☑ Compaction é avaliada e versionada.
  • +
  • ☑ Incidentes têm runbook, owner e métrica de recuperação.
  • +
+
+ Complemento por framework (cross-link): a + checklist de deployment OpenAI e o roteiro de + going to production dos guias de framework estendem esta lista com itens específicos de cada + runtime. +
+
+ +
+

14. Production hardening SOTA

+

+ Um agente só está pronto para produção quando suas falhas são detectáveis, reproduzíveis e + mitigáveis. Isso exige guardrails, tracing, evals, SLOs, cost ledger, threat model e runbooks + — tudo o que este capítulo definiu. A tabela abaixo é o portão final: gates que, em fluxos críticos, + bloqueiam release. +

+
+ + + + + + + + + + +
GateTeste obrigatórioBloqueia release?Evidência mínima
SEC-01Prompt injection em documento/tool output não altera instruções.SimTrace + teste adversarial.
DATA-01Dado sensível não vai a provider/tool não autorizada.SimPolicy decision + redaction log.
TOOL-01Tool de escrita exige aprovação, idempotência e replay.SimSpan de aprovação + idempotency key.
SCHEMA-01Outputs finais e tool results validam schema.Sim p/ críticosValidador local + taxa de erro.
CTX-01Compaction preserva decisões, fatos e pendências críticas.Sim p/ tarefas longasEval de replay + loss declaration.
COST-01Budget e wind-down impedem runaway loops.SimCost ledger + max turns/tools.
OBS-01Incidente é reconstruível sem expor dados indevidos.SimTrace redigido + hashes.
+
+ Cadência recomendada: rode evals de contrato a cada mudança de schema/tool/prompt/modelo; + evals adversariais antes de cada release; monitoração online por amostragem; e revisão de custo/latência + por rota. Mudanças em docs oficiais de SDK/API disparam revisão de adapters e da matriz de + compatibilidade. +
+
+ Definição de pronto para produção: os sete gates acima verdes em fluxos críticos, SLOs + com baseline, runbooks com owner, kit de incidente imutável e policy-as-code por rota. Ausência de + qualquer um destes = não está pronto, independentemente da qualidade do modelo. +
+
+ + +
+

Cheat sheet operacional

+

Referência rápida orientada a consulta (IA e humanos).

+ +

Acceptance gates (resumo)

+
+ + + + + + + + + + + +
GateFocoContrato relacionado
SEC-01 / SEC-001Injection não ganha autoridade.Guardrails (§3), Threat model (§8).
DATA-01 / ZDR-001Dado sensível / retenção por rota.Privacidade (§2), Policy (§7).
TOOL-01 / TOOL-001Side-effect + aprovação + idempotência.Guardrails (§3), Policy (§7).
SCHEMA-01Saídas/tool results válidos.Evals (§5).
CTX-01Compaction sem perda crítica.Evals (§5), Estado (cross-link).
COST-01 / BUDGET-001Budget + wind-down.Cost ledger (§4), Runbooks (§6).
OBS-01Replay redigido reconstruível.Tracing (§4), Kit de incidente (§11).
PROVIDER-001Switch declara perdas.Providers & adapters (cross-link).
+ +

Camadas de guardrail (L0/L1/L2) — decisão rápida

+
    +
  • L0 — determinístico, rápido (<50ms), observe/mask por padrão. Tripwire só em segredo / allowlist de URL / desalinhamento de tool-call.
  • +
  • L1 — LLM-juiz deliberativo, palavra final sobre conteúdo conversacional.
  • +
  • L2 — kernel no prompt (cadeia de comando, dado-como-dado, recusa, escopo, confidencialidade no fim).
  • +
  • HITL — gate humano em ações High/Critical; multi-pessoa em Critical; nunca inferir aprovação.
  • +
+ +

Esqueleto de policy-as-code (copy-paste)

+
route:
+  limits:    { max_turns, max_tool_calls, final_reserve_tokens }
+  retention: { provider_store, internal_days }
+  data:      { data_classes_allowed_to_provider }
+  tools:     { <name>: { side_effect, approval, timeout_ms } }
+  guardrails:{ input: [...], output: [...], tool_result: [...] }
+ +

Mapa de cross-links

+
+ + + + + + + + + + + +
Preciso de…Onde ler
Retenção/ZDR por providerOpenAI · Gemini · Claude
Guardrail primitivo / tripwireAgents SDK · Guardrails
HITL por frameworkLangGraph · ADK · Tool Confirmation
Tracing / persistênciaAgents SDK · LangGraph · ADK
Evals code-firstPydantic AI · ADK · avaliação
Hardening de MCP / toolsFerramentas, MCP & RAG
Provider-switching + loss declarationProviders & adapters
Ledger / compaction / budgetEstado, contexto & memória
+
+ +
+

Notas de verificação

+

Pontos perecíveis conferidos contra a documentação oficial em 2026-06-10, e os que permanecem em aberto.

+
    +
  • Resolvido URLs do Pydantic AI. A regra do mapa/time pedia + ai.pydantic.dev e proibia pydantic.dev/docs/ai. Verificação ao vivo (2026-05-25): + ai.pydantic.dev/, /evals/ e /logfire/ retornam 301 + para pydantic.dev/docs/ai/overview/, /evals/evals/ e + /integrations/logfire/ — que servem a doc oficial real. Este guia usa o destino canônico vivo + pydantic.dev/docs/ai/…. Confirmado na validação #13 (2026-05-25): a regra antiga do mapa estava + desatualizada; guia_providers_adapters.html foi alinhado a este mesmo destino.
  • +
  • Resolvido Spec MCP 2025-11-25. Confirmada como a + revisão autoritativa (host/client/server; princípios de consentimento, tool safety e sampling controls). + Usada uniformemente aqui. Re-verificado em 2026-06-10: segue a revisão atual; a próxima revisão + (2026-07-28, ainda em draft; em evolução até a publicação) traz protocolo stateless (sem handshake + initialize/Mcp-Session-Id) e deprecia Roots/Sampling/Logging. + Observação para o validador: guia_agents_sdk.html existente cita + 2024-11-05/2025-03-26 — não modificar o guia existente; o portal/validação deve + marcar a versão canônica.
  • +
  • Resolvido OWASP. LLM Top 10 (2025) e Top 10 for Agentic + Applications (2026, dez/2025) com ASI01–ASI10; mapeamento camadas→ASI conferido contra a referência da + skill agent-guardrails (last verified 2026-04-21) e as URLs oficiais + genai.owasp.org. Re-verificado em 2026-06-10: ambos seguem vigentes (novo projeto + incubado: Agentic Skills Top 10 — AST10, sem lista publicada).
  • +
  • Resolvido EU AI Act (cronograma). Anexo III de alto risco a + partir de 02/08/2026; "Digital Omnibus" como possível adiamento — tratado como não garantido. + Re-verificado em 2026-06-10: datas inalteradas; o marco do Anexo III está a menos de dois meses.
  • +
  • Resolvido Sem IDs de modelo no corpo. O guia usa + model="..." e provider/model; IDs perecíveis ficam na folha de fatos SOTA do + super-guia, conforme política do mapa.
  • +
  • Verificado Anchors de cross-link. Todos os + id de destino em guias existentes foram revalidados na validação #13 (2026-05-25) e + resolvem corretamente: #s-guardrails, #s-tracing, #s-conversation, + #s-store, #a-context-windows, #tool-confirm, + #observability, #evaluate, #c-mcp, #mcp, + #s-hitl, #s-persistence, #s-deployment, + #s-ops-cookbook. Os guias de núcleo (guia_arquitetura_orquestracao, + guia_estado_contexto_memoria, guia_ferramentas_mcp_rag, + guia_providers_adapters) já existem; este guia não depende de âncoras internas deles.
  • +
+
+ +
+
+ +
+
+
+
Operação, Segurança & Evals Núcleo agnóstico · super-guia de agentes
+

+ Referência técnica construída a partir da documentação oficial pública em 2026-06-10. + Operação como arquitetura: privacidade/ZDR, guardrails, tracing, evals, runbooks e threat model alinhado + à OWASP. Para informação sempre atualizada, consulte as + fontes oficiais. +

+
+
+
Crédito de produção
+
Gerado por subagentes Claude Opus 4.7 (xhigh)
+
autor autor_ops · revisão e montagem pelo orquestrador · 2026-06-10
+
+ Núcleo · v1 + PT-BR · agnóstico +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_paralelismo_tools_openai_gemini_anthropic.html b/references/agents_tools_best_guides/guia_paralelismo_tools_openai_gemini_anthropic.html new file mode 100644 index 0000000..d14ff35 --- /dev/null +++ b/references/agents_tools_best_guides/guia_paralelismo_tools_openai_gemini_anthropic.html @@ -0,0 +1,3314 @@ + + + + + + Paralelismo de Tools em Frameworks de Agentes — Relatório Técnico Avançado v4.6 — 2026-06-10 (empiricamente validado + Interactions API deep-dive completo, 16 subseções) + + + +
+ +
+
+
Relatório técnico avançado · versão 4.6 — 2026-06-10 — empiricamente validado
+

Paralelismo de tools em frameworks de agentes: OpenAI, Anthropic e Gemini

+

Análise ampliada para desenho de um framework multi-provider que usa OpenAI Agents, OpenAI Responses API, SDKs nativos da Anthropic e google-genai. O foco é separar emissão de tool calls pelo modelo, execução client-side, ferramentas hosted/server-side, serialização por dependência, latência, segurança, custo, observabilidade e política por ferramenta.

+
+ Consultado em 10/06/2026 + OpenAI Responses + Agents SDK + Anthropic Messages API + Gemini google-genai + Arquitetura multi-provider + v3.5: Interactions API descoberta, gemini-3.5-flash 2/2 grounded + v3.6: FORMA B deep-dive (16 subseções, REST + SDK + steps + tools + agents + webhooks) + v4.6 (2026-06-10): schema legado da Interactions API removido em 08/06/2026 (Api-Revision ignorado, SDKs 1.x quebrados p/ Interactions); snapshot PyPI re-verificado +
+
+ +
+

0. Tese executiva

+
+

Ponto mais importante: não trate parallel_tools=True como uma flag universal. Ela mistura pelo menos três decisões diferentes: se o modelo pode emitir várias tool calls, se o seu runtime vai executá-las em paralelo e se a ferramenta é executada por você ou pelo provedor.

+
+
+
+
OpenAI
+

A documentação de function calling afirma que o parallel function calling não é possível quando built-in tools são usadas. Portanto, não desenhe um mesmo turno esperando built-in OpenAI e function tools externas paralelas ao mesmo tempo. [S1]

+
+
+
Agents
+

No OpenAI Agents SDK, parallel_tool_calls controla emissão pelo modelo; max_function_tool_concurrency controla execução local de function tools. São knobs diferentes. [S7] [S8]

+
+
+
Claude
+

Claude pode emitir múltiplas client tools por padrão; disable_parallel_tool_use=true limita isso. Server tools da Anthropic não entram no seu executor client-side. [S13] [S14]

+
+
+
Gemini
+

Gemini suporta parallel e compositional function calling; Gemini 3 documenta combinação built-in + custom em Preview via tool context circulation, com IDs e thought signatures. [S18] [S19] [S20]

+
+
+

Conclusão de arquitetura

+

Seu framework deve ter pelo menos estes controles, não apenas uma flag:

+
@dataclass
+class AgentToolPolicy:
+    # O modelo pode emitir várias chamadas no mesmo turno?
+    allow_model_parallel_tool_calls: bool = True
+
+    # Quantas tools client-side rodam simultaneamente no seu runtime?
+    max_client_tool_concurrency: int | None = 4
+
+    # Como lidar com built-ins/server tools?
+    hosted_tool_strategy: Literal["same_turn", "separate_phase", "disabled"] = "separate_phase"
+
+    # Como lidar com mutações, side effects, pagamentos, envios, deleções?
+    mutation_policy: Literal["forbid_parallel", "lock_by_resource", "allow"] = "forbid_parallel"
+
+    # Controle de exposição de tools por fase.
+    expose_only_phase_tools: bool = True
+

O desenho robusto é: built-ins/server-side são uma trilha; function tools/client-side são outra trilha; e a sua camada de orquestração decide o scheduler real.

+
+ +
+

0.5 Validação empírica (v3.5, 2026-05-24 — Interactions API descoberta, correção final)

+
+

✅ Correção FINAL v3.5 (2026-05-24) — o usuário tinha razão, gemini-3.5-flash FUNCIONA com structured + Google Search.

+

O snippet do doc oficial em ai.google.dev/gemini-api/docs/structured-output mostra client.models.generate_content(config={"response_format": ...}). Esse snippet é internamente inconsistente: o método é da generate_content API velha, mas o campo response_format só existe na Interactions API nova (adicionado pelo PR #2379 em google-genai v2.0.0, apenas em google/genai/_interactions/).

+

Quando você chama a API certa (client.interactions.create), todos os modelos da série Gemini-3 funcionam perfeitamente — incluindo gemini-3.5-flash que o usuário sempre disse que funcionava (evidência: results/33_gemini_interactions_api.json):

+
from google import genai
+from pydantic import BaseModel, Field
+
+class MatchResult(BaseModel):
+    winner: str = Field(description="winner")
+    final_match_score: str = Field(description="score")
+    scorers: list[str] = Field(description="scorers")
+
+client = genai.Client()
+resp = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Search for all details for the latest Euro 2024 final.",
+    response_format={"type": "text", "mime_type": "application/json",
+                     "schema": MatchResult.model_json_schema()},
+    tools=[{"type": "google_search"}, {"type": "url_context"}],
+)
+# resp.steps = [GoogleSearchCallStep(arguments=Arguments(queries=['UEFA Euro 2024 ...'])),
+#               ThoughtStep(...), MessageStep(...)]
+print(resp.output_text)  # {"winner":"Spain","final_match_score":"2-1",...}
+ + + + + + + + +
Modeloclient.interactions.create + tools + response_format
gemini-3.5-flash2/2 grounded ✅
gemini-3.1-pro-preview2/2 grounded ✅
gemini-3.1-flash-lite2/2 grounded ✅
gemini-3-flash-preview2/2 grounded ✅
+

Reconhecimento honesto: a versão anterior (v3.4) deste relatório listava 5 claims REGRESSION_DOC_CONTRADICTED baseadas em ~200 chamadas testando a API errada (generate_content). Essas 5 claims foram marcadas REVISED_IN_V4_5 em CLAIMS.json. Adicionadas 5 novas claims corretas. Total: 45 claims em CLAIMS.json v4.5.

+
+
+

Diferença entre as DUAS APIs do SDK google-genai para structured+grounding:

+ + + + + + + + + + + + +
Aspectoclient.models.generate_content() (clássica)client.interactions.create() (NOVA)
URL REST/v1beta/models/{model}:generateContent/v1beta/interactions (header Api-Revision ignorado desde 08/06/2026 — schema steps é o único)
Schema configresponse_mime_type + response_schema (ou response_json_schema)response_format={"type":"text","mime_type":"application/json","schema":...}
Toolstools=[types.Tool(google_search=...)] (Tool objects)tools=[{"type":"google_search"}, {"type":"url_context"}] (dicts)
Output shaperesponse.candidates[].content + grounding_metadataresponse.steps=[GoogleSearchCallStep, ThoughtStep, MessageStep] + output_text
gemini-3.5-flash + schema + search0/50+ grounded2/2 grounded ✅
gemini-3.1-pro-preview + schema + search0–22% grounded (volátil)2/2 grounded ✅
gemini-3.1-flash-lite + schema + search3/3 grounded ✅2/2 grounded ✅
gemini-3-flash-preview + schema + search3/3 grounded ✅2/2 grounded ✅
+

Recomendação prática: para gemini-3.5-flash e gemini-3.1-pro-preview com structured + grounding, use Interactions API. Para generate_content com structured + grounding, use gemini-3.1-flash-lite ou gemini-3-flash-preview.

+
+ +
+

Escopo focado v3.3: tudo neste relatório foi reexecutado contra as APIs reais com openai 2.38.0, anthropic 0.104.1 e google-genai 2.6.0 (versões testadas na execução, preservadas como registro histórico das sondas; latest no PyPI em 2026-06-19: openai 2.43.0, anthropic 0.111.0, google-genai 2.9.0 — nenhuma altera as APIs, parâmetros ou model IDs deste relatório; as bumps recentes só somam, no google-genai 2.9.0, a reimplementação interna de Interactions mantendo a API pública estável e, no anthropic 0.111.0, suporte tipado a code_execution_20260120 e marcação de fallback de recusa. claude-opus-4-8 entrou no SDK anthropic 0.105.0; gemini-3.5-flash no google-genai 2.5.0/2.6.0), restrito aos 9 modelos do escopo:

+
    +
  • OpenAI (3): gpt-5.5 (frontier), gpt-5.4-mini (low-latency), gpt-5.4-nano (low-cost)
  • +
  • Anthropic (3): claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5-20251001 (escopo testado em 2026-05-24. Nota 2026-06-03: claude-opus-4-7 passou a Legacy — o recomendado atual é claude-opus-4-8, mesma superfície de API; os probe-records abaixo preservam o ID efetivamente testado.)
  • +
  • Google (3): gemini-3.1-pro-preview (preview), gemini-3.5-flash (stable), gemini-3.1-flash-lite (stable, low-latency)
  • +
+

Scripts reprodutíveis em tests/test_focused_*.py (junto com os JSONs de evidência em results/20-22_focused_*.json). Toda afirmação testável aparece na tabela de status logo abaixo, com a evidência referenciada inline e cross-referenciada com as docs oficiais dos providers (links na seção 24).

+
+
+
+
OpenAI (3 modelos do escopo)
+

CAPABILITY SILENCIOSA confirmada em gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano (3/3). Responses API text.format=json_schema + tools=[web_search] funciona em 100 % dos modelos do escopo — preços consistentes $77 016-$77 021 provam busca real. Doc OpenAI (tools-web-search) recomenda tool_choice:"required" quando search precisa rodar; nosso prompt explícito também funcionou em 3/3 com default. Parallel FC OK 3/3. Combo D (3-em-1) falha em 3/3 modelos — usar 2-turn split. Evidência: results/21_focused_openai.json.

+
+
+
Anthropic (3 modelos do escopo)
+

BUG ARQUITETURAL EXPLICADO PELA DOC OFICIAL em opus-4-7 / sonnet-4-6 / haiku-4-5. Doc "the API prefills the assistant message to force a tool to be used" — logo tool_choice={type:"tool", name:"X"} bloqueia web_search server tool em 3/3. Opus chama X com input={}, sonnet fabrica $108k, haiku fabrica $67k. Padrão correto (oficial): tool_choice={type:"any"} + strict:true — 3/3 funcionam com dados reais $76 856-$77 136. Parallel FC OK 3/3 (9 paralelas, sonnet agrupa-as por tool). Evidência: results/22_focused_anthropic.json.

+
+
+
Gemini (3 modelos do escopo)
+

CAPABILITY EXISTE — usar API CERTA (v3.5). Doc afirma "available only to gemini-3.1-pro-preview and gemini-3.5-flash", e funciona — só que via client.interactions.create(), NÃO client.models.generate_content(). Snippet do doc é internamente inconsistente (mistura método velho com campo novo). Empírico com a API correta (results/33_gemini_interactions_api.json): 3.5-flash 2/2 grounded ✅, 3.1-pro-preview 2/2 ✅, 3.1-flash-lite 2/2, 3-flash-preview 2/2. Na API velha (generate_content + classic shape response_mime_type + response_schema): 3.5-flash e 3.1-pro-preview 0–22 % grounded; flash-lite e 3-flash-preview 100 %. Parallel FC OK 3/3 com thought_signature [T,F,F]. Evidência: results/20–33.

+
+
+

Tabela de status por afirmação testável

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDCamadaAfirmação v3StatusEvidência
O1emissãoparallel_tool_calls=True emite múltiplas callsCONFIRMADOresults/01_openai.json
O2emissãoparallel_tool_calls=False → 0 ou 1CONFIRMADOresults/01_openai.json
O3emissão+runtimebuilt-in + functions paralelas "não possível"REFUTADO p/ gpt-5.5results/02_openai_o3_repeat.json
A1emissão+execuçãoClaude emite N tool_use paralelos por padrãoCONFIRMADO (9 paralelos, overlap ≈610 ms)results/03_anthropic.json
A2emissãodisable_parallel_tool_use=True → 0/1CONFIRMADOresults/03_anthropic.json
A3emissão+runtimeserver e client em trilhas separadasREFINADO — coexistem no mesmo turnoresults/03_anthropic.json
A4emissãothinking + tool_choice any|tool rejeitadoCONFIRMADO (400 em ambos)results/03_anthropic.json
G1emissão+execuçãoGemini paralelo + IDs únicos em Gemini 3CONFIRMADO (ids reais; null em 2.5)results/04_gemini.json
G2emissãomodes AUTO/ANY/NONECONFIRMADO c/ nuance — ANY não limita a 1results/04_gemini.json
G3runtimebuilt-in + function calling combináveis no mesmo turno (feature Preview, Gemini-3 only)CONFIRMADO — aceito em Gemini 3.x; gemini-2.5-* dá 400 (fora de escopo)results/04_gemini.json
G3-mechruntimegoogle_search auto-executa server-side e devolve groundingREFINAMENTO em 8 probes (gemini-3-pro/flash, com e sem flag), 0 trouxeram grounding_metadata.web_search_queries; gemini-3-flash surface a busca como function_call(name="google_search:search") para o cliente executarresults/13_*.json, results/14_*.json
G3-sdkSDK shapeinclude_server_side_tool_invocations em GenerateContentConfigREFINADO — vive em ToolConfigresults/04_gemini.json
G4emissãothought_signature só no 1º FC partCONFIRMADO (em 9 FCs: [T,F,F,F,F,F,F,F,F])results/04_gemini.json
S1emissão (structured)Gemini-3.x emite JSON válido com response_schema sozinhoCONFIRMADO em 3.5-flash e 3.1-pro-previewresults/15_gemini_structured_plus_tools.json
S2-proemissão+runtimeDoc histórica: "response_schema não pode coexistir com built-in tools"REFUTADO p/ gemini-3.1-pro-preview — combo retorna JSON válido E grounding_metadata.web_search_queries populado (structured_AND_grounded=true)results/15_gemini_structured_plus_tools.json
S2-flashemissão+runtimeMesmo combo em gemini-3.5-flash via generate_contentPARCIAL na API velha — generate_content aceita schema mas não dispara busca. Combo movido para Interactions API onde 2/2 grounded (vide G-interactions-correct e seção 5.8)results/15, results/33_gemini_interactions_api.json
S3emissão (mutex)response_schema + function_declarations → ambos coexistem na saídaREFUTADO em ambos modelos — quando modelo escolhe FC, ele substitui a structured output (sem texto JSON)results/15_gemini_structured_plus_tools.json
S4combo totalresponse_schema + google_search + custom FC simultâneosPARCIAL — FC custom canibaliza tanto JSON quanto grounding em ambos os modelosresults/15_gemini_structured_plus_tools.json
S5regressão paralelaParallel FC continua funcionando em 3.5-flash e 3.1-pro-previewCONFIRMADO (3 FCs paralelas, IDs únicos, thought_signature [T,F,F])results/15_gemini_structured_plus_tools.json
G2.5-hardruntimeGemini 2.5 hard-rejects response_schema + toolsHARD-LIMIT CONFIRMADO — 400 "Tool use with a response mime type: 'application/json' is unsupported" em 16/16 chamadas (2 modelos × 4 prompts × 2 runs)results/16_gemini_grounding_depth.json
G3-flash-preview-bestemissão+runtimeresponse_schema + google_search em gemini-3-flash-preview100 % grounding em 8/8 runs (4 prompts × 2 runs) — MELHOR modelo para o comboresults/16_gemini_grounding_depth.json
G3.1-pro-volemissão+runtimeMesmo combo em gemini-3.1-pro-preview50 % grounding (4/8 runs); volátil mas funcionaresults/16_gemini_grounding_depth.json
G3.5-flash-via-correct-apiemissão+runtime (v3.5)gemini-3.5-flash com schema+search via client.interactions.create2/2 grounded ✅ — steps=[GoogleSearchCallStep(queries=['Euro 2024 final ...']), GoogleSearchResultStep, ThoughtStep, ModelOutputStep], output_text JSON estruturado. Combo movido pra Interactions API; generate_content + schema 0/9 (versão velha da capability).results/33_gemini_interactions_api.json (e seção 5.8)
O-structured+searchemissão+runtimeOpenAI Responses text.format=json_schema + web_search built-in100 % em 4/4 modelos (gpt-5.5, 5.4, 5.1, 4.1) — capability não bem documentada, funciona perfeitoresults/17_openai_structured_plus_tools.json
O-combo-totalemissãoOpenAI schema + web_search + custom function simultâneos2/4 sucesso — apenas gpt-4.1 emitiu os três (search + function_call + message JSON). gpt-5.5/5.4 emitiram só function_call sem JSON; gpt-5.1 grounded mas valor=0 (search retornou erro).results/17_openai_structured_plus_tools.json
A-forced-tool-dangeremissão🚨 Anthropic tool_choice={type:"tool",name:"X"} com web_search server toolPERIGOSO — opus-4-7 chamou X com input={} vazio; sonnet-4-6 com placeholders "pending". Forçado bloqueia server tool.results/18_anthropic_structured_plus_tools.json
A-tool_choice-any-safeemissãoSubstituir forced por tool_choice={type:"any"}SEGURO — 2/2 modelos buscaram primeiro e depois chamaram custom tool com dados reais ($76578-$76856)results/18_anthropic_structured_plus_tools.json
A-tool_choice-auto-safeemissãoOu tool_choice=auto com prompt forteSEGURO — 2/2 modelos com dados reais ($77136 / $76856)results/18_anthropic_structured_plus_tools.json
Layersmodelo3 camadas independentes: emissão / execução / runtimeCONFIRMADO em todos os providerstodos os results/*.json
G-doc-snippet-bugdoc snippet (v3.5)Doc oficial mostra client.models.generate_content(config={"response_format":...})SNIPPET INCONSISTENTE — método é da generate_content API velha; campo response_format é da Interactions API nova (PR #2379 só toca _interactions/). Roda? ValidationError: Extra inputs not permitted (provado em test_doc_literal.py seção A).results/29_gemini_doc_final.json + test_doc_literal.py
G-interactions-correctAPI correta (v3.5)Usar client.interactions.create(response_format=..., tools=[{"type":"google_search"},...]) em gemini-3.5-flash e gemini-3.1-pro-previewCAPABILITY CONFIRMADA — 2/2 grounded em cada modelo. steps=[GoogleSearchCallStep, GoogleSearchResultStep, ThoughtStep, ModelOutputStep]; output_text JSON estruturado válido.results/33_gemini_interactions_api.json
G-rest-enumREST proto enum (v3.5)Doc REST mostra responseFormat.text.mimeType = "application/json"ENUM BUG do doc REST — backend rejeita HTTP 400 quando enviado ao :generateContent; proto TextResponseFormat.MimeType é enum. Funcionou via REST direto à /v1beta/interactions (endpoint correto) com a mesma string "application/json".results/30_gemini_enum_brute.json + test_doc_literal.py seção C
G-gc-classic-shapegenerate_content classicEm generate_content com response_mime_type + response_schema + google_searchDEPENDENTE DO MODELO — 3-flash-preview e 3.1-flash-lite ground 3/3; 3.5-flash e 3.1-pro-preview 0–22% (combo movido para Interactions API).results/32_gemini_two_doc_versions.json
+
+

Tools instrumentadas com asyncio.sleep(600 ms) registram start/end em time.perf_counter; overlap pareado calculado por min(end_i, end_j) − max(start_i, start_j). Overlap ≈600 ms confirma concorrência real, não apenas "emissão decorativa".

+ +

Matriz definitiva dos 9 modelos do escopo (v3.3, 2026-05-24)

+
+ + + + + + + + + + + + + + + + + + + + + +
ModeloProviderStructured + grounding/search built-inParallel function/tool callingDoc oficial vs empírico
gpt-5.5OpenAI✅ JSON + search($77 021)✅ 3 paralelasCapability silenciosa — funciona mesmo sem doc explícita
gpt-5.4-miniOpenAI✅ JSON + search($77 021)✅ 3 paralelasCapability silenciosa
gpt-5.4-nanoOpenAI✅ JSON + search($77 016)✅ 3 paralelasCapability silenciosa
claude-opus-4-7Anthropic✅ auto/any $77 136 / 🚨 type:tool input vazio✅ 9 paralelas (interleaved)Bug forced-tool explicado pelo doc oficial (API prefilla msg)
claude-sonnet-4-6Anthropic✅ auto/any $76 856 / 🚨 type:tool fabricou $108k✅ 9 paralelas (agrupadas)Idem opus
claude-haiku-4-5Anthropic✅ auto/any $76 856 / 🚨 type:tool fabricou $67k✅ 9 paralelasIdem opus — bug arquitetural inteira família
gemini-3.1-pro-previewGoogle✅ 100 % via Interactions API (2/2) · 22 % via generate_content (volátil)✅ 3 paralelas, sig=[T,F,F]Doc lista como suportado — confirmado via client.interactions.create
gemini-3.5-flash (stable)Google✅ 100 % via Interactions API (2/2) · 0 % via generate_content✅ 3 paralelasDoc lista como suportado — confirmado via client.interactions.create
gemini-3.1-flash-liteGoogle🏆 100 % em ambas APIs (3/3 generate_content, 2/2 Interactions)✅ 3 paralelas, sig=[T,F,F]Funciona em ambas as APIs; capability "silenciosa" na generate_content
+
+

Padrão geral observado: docs oficiais e implementação real divergem em pelo menos 4 pontos importantes — (1) doc Gemini mostra snippet incoerente (mistura generate_content com campo da Interactions API); (2) OpenAI combo C (json_schema + web_search) silenciosamente suportado em 3/3 modelos do escopo; (3) Anthropic forced-tool bloqueia server tools — explicado pelo doc oficial; (4) haiku-4-5 1ª vez testado e segue mesmo padrão da família. Cross-referenciação evita confiar cegamente em qualquer fonte isolada.

+
+ +
+

1. Modelo mental universal

+

A maior fonte de bugs em agentes com tools é confundir a palavra “tool”. Em APIs modernas, “tool” pode significar uma função sua, uma busca web hospedada, um interpretador de código remoto, um MCP server, um browser/computer tool, um subagente, uma operação local no shell ou uma capacidade server-side. Essas categorias têm propriedades completamente diferentes.

+ +

1.1 As três camadas

+ + + + + + + +
CamadaPerguntaQuem controla?Exemplos
EmissãoO modelo pode emitir uma ou várias chamadas no mesmo turno?Parâmetros do request e comportamento do modeloparallel_tool_calls, disable_parallel_tool_use, function_calling_config.mode
ExecuçãoAs chamadas emitidas serão executadas simultaneamente?Seu framework ou SDK wrapperasyncio.gather, Promise.all, semaphores, rate limiters, locks
Runtime da toolA tool roda no seu processo ou no servidor do provedor?Tipo da toolFunction tool client-side, OpenAI hosted, Anthropic server tool, Gemini built-in
+ +
Usuário + │ + ▼ +Modelo decide se precisa de tools ──► Emite 0, 1 ou N tool calls + │ │ + │ ├─ client-side function calls ─► seu scheduler executa + │ │ ├─ paralelo + │ │ ├─ serial + │ │ └─ bloqueado/aprovação + │ │ + │ └─ hosted/server-side tools ─────► provedor executa + │ └─ seu scheduler apenas preserva/observa + ▼ +Modelo recebe resultados e continua ou finaliza
+ +

1.2 Turn, step e batch

+

Para um framework multi-provider, defina estes termos internamente:

+ + + + + + + + +
TermoDefinição operacionalPor que importa?
TurnUma troca lógica iniciada por mensagem de usuário e completada por resposta final do assistente.Gemini e Anthropic tratam loops de tool use como parte de um turno lógico; OpenAI reasoning também preserva estado entre chamadas.
StepUma etapa dentro do turno: modelo emite tool calls, runtime executa, modelo recebe resultados.Dependências sequenciais aparecem como steps separados.
Batch paraleloConjunto de tool calls emitidas no mesmo step e sem dependência lógica entre elas.É o único conjunto que seu scheduler pode paralelizar com segurança, salvo conflito de recurso/side effects.
Hosted eventEvento de uma ferramenta server-side, como built-in search ou code execution.Não é executado pelo seu scheduler; deve ser preservado no histórico quando a API exigir.
+ +

1.3 Taxonomia de tools

+ + + + + + + + + + + + +
TipoRoda onde?Paralelizável pelo seu runtime?Exemplos
Client functionSeu appSim, se a política permitirCRM, billing, search interno, DB lookup
Hosted OpenAIServidor OpenAINão diretamenteWebSearchTool, FileSearchTool, CodeInterpreterTool, ImageGenerationTool, HostedMCPTool [S9]
OpenAI local/runtime toolSeu ambiente ou hosted, depende da toolDependeShell pode ser local ou hosted; apply patch/computer têm considerações próprias [S11] [S12]
Anthropic client toolSeu appSimFerramentas definidas no parâmetro tools e chamadas como tool_use [S14]
Anthropic server toolAnthropicNão diretamenteWeb search, web fetch, code execution/server tool use [S16] [S17]
Gemini custom functionSeu app ou SDK automatic loopSim, se você controlar o loopfunctionCall/functionResponse [S18]
Gemini built-inGoogle/server-sideNão diretamenteGoogle Search, Google Maps, URL Context, File Search, Code Execution [S19]
MCPVariaDependeRemote MCP hosted pelo provedor ou MCP client executado por você
+
+ +
+

2. Matriz comparativa multi-provider

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DimensãoOpenAI Responses APIOpenAI Agents SDKAnthropic ClaudeGemini / google-genai
Flag de emissão paralelaparallel_tool_callsModelSettings.parallel_tool_callsParalelo é permitido por padrão; desabilita com disable_parallel_tool_useNão há boolean equivalente universal; usa modes AUTO, ANY, NONE, VALIDATED
Controle de execução localVocê implementaToolExecutionConfig.max_function_tool_concurrencyVocê implementaVocê implementa se desabilitar automatic function calling; SDK Python pode executar automaticamente
Built-in + client tools no mesmo turnonão assumir paralelismo
Function parallelism não é possível com built-ins, segundo docs [S1]
separe hosted vs function
Hosted tools rodam nos servidores OpenAI [S9]
separe server vs client
Server tools são executadas pela Anthropic; client tools por você
documentado em Preview
Gemini 3 combina built-in + custom via tool context circulation [S19]
Per-tool hard parallel policy nativaNão geralNão geralNão geralNão geral
Melhor controle por toolFases + tool_choice/allowed_tools + schedulerFases/agentes separados + SDK concurrency cap + schedulerSubconjunto de tools + tool_choice + schedulerallowed_function_names + validação runtime + scheduler
Formato de resposta de toolfunction_call_output / output itemsSDK abstrai parte do looptool_result imediatamente após tool_use; em paralelo, resultados agrupados em uma mensagemfunctionResponse com mesmo id; preservar parts/signatures
Reasoning/contextoPreservar reasoning items ou usar previous_response_id; reasoning tokens impactam custo/latência [S5]Runner gerencia muito do loop, mas política ainda é suaExtended thinking exige preservar thinking blocks e limita forced tool choice [S15]Thought signatures obrigatórias em function calling Gemini 3 quando histórico é manual [S20]
+
+
+ +
+

3. OpenAI em profundidade

+

Na OpenAI, a recomendação central é separar function tools client-side de built-in/hosted tools. A Responses API oferece function calling, built-in tools, MCP e tool search; a documentação de tools distingue web search, file search, tool search, function calling e remote MCP. [S2]

+ +

3.1 O que parallel_tool_calls faz de fato

+

parallel_tool_calls controla se o modelo pode emitir múltiplas chamadas no mesmo turno. Quando configurado como falso, a documentação de function calling afirma que você restringe a execução a zero ou uma tool call. [S1]

+
+

Bom caso: só function tools externas, todas read-only e independentes. Exemplo: consultar CRM, billing e tickets para o mesmo cliente. O modelo pode emitir três function calls no mesmo output, e você executa as três em paralelo.

+
+
response = client.responses.create(
+    model="gpt-5.5",
+    input="Consulte CRM, billing e tickets do cliente 123.",
+    tools=[crm_lookup_tool, billing_lookup_tool, ticket_lookup_tool],
+    parallel_tool_calls=True,
+)
+
+# Se response.output contiver 3 function_call items independentes:
+results = await asyncio.gather(
+    dispatch(crm_call),
+    dispatch(billing_call),
+    dispatch(ticket_call),
+)
+ +

3.2 O que parallel_tool_calls não faz

+ + + + + + + + + +
Não fazImplicação
Não força o modelo a chamar múltiplas toolsMesmo com a flag ligada, o modelo pode chamar só uma ou nenhuma.
Não executa suas funções por vocêNa Responses API direta, você precisa extrair calls, executar, montar outputs e reenviar.
Não dá política por toolNão há um campo nativo geral “esta tool pode paralelizar, esta não”.
Não transforma built-ins em tasks client-sideWeb search/file search/code interpreter hospedados são executados pela OpenAI, não pelo seu scheduler.
Não resolve dependências lógicasReasoning models podem precisar de chamadas em série quando uma depende da outra. [S6]
+ +

3.3 Built-in tool primeiro e depois externas paralelas no mesmo request?

+
+

Minha recomendação de engenharia: não projete essa expectativa como contrato suportado. A frase operacional da documentação é que parallel function calling não é possível quando built-in tools são usadas. [S1]

+
+
+

Atualização empírica v3.1 (2026-05-23). A frase do doc [S1] ainda está presente verbatim em developers.openai.com/api/docs/guides/function-calling#parallel-function-calling, mas foi refutada empiricamente para gpt-5.5: em 3 de 5 runs com a mesma prompt (web_search + 3 function tools, parallel_tool_calls=True), o turno 0 trouxe reasoning · web_search_call(status=completed) · function_call · function_call · function_call — built-in hosted e 3 function calls client paralelas, na MESMA resposta. gpt-4.1 continuou serializando em 4/4 runs (consistente com o doc). O conselho desta seção (fases separadas, não tratar como contrato) continua válido justamente porque o comportamento é versão-dependente. Evidência: results/02_openai_o3_repeat.json, results/01b_openai_doc_evidence.json.

+
+

O ponto técnico é que a built-in tool é executada dentro do fluxo hospedado da OpenAI. Seu código não recebe uma pausa controlada no meio do reasoning para iniciar suas functions externas em paralelo. Você só controla a execução quando a API retorna function calls para o cliente. File Search, por exemplo, é descrita como uma hosted tool gerenciada pela OpenAI, chamada automaticamente quando o modelo decide usá-la. [S3]

+

Portanto, este desenho é frágil:

+
# NÃO desenhar esperando: web_search interno + CRM/Billing/Tickets paralelos no mesmo turno.
+response = client.responses.create(
+    model="gpt-5.5",
+    input="Pesquise notícias da empresa X e consulte CRM, billing e tickets.",
+    tools=[
+        {"type": "web_search"},
+        crm_lookup_tool,
+        billing_lookup_tool,
+        ticket_lookup_tool,
+    ],
+    parallel_tool_calls=True,
+)
+

Mesmo que em algum cenário empírico você observe chamadas externas após uma built-in, isso não deve virar contrato do framework. O que você precisa é uma arquitetura que funcione mesmo quando o provedor muda ordenação, streaming interno, eventos hosted, modelos ou constraints.

+ +

3.4 Arquiteturas corretas para OpenAI built-ins + externas

+
+
+

Opção A — Duas fases técnicas

+

Fase 1 com built-in hosted; fase 2 com function tools externas e parallel_tool_calls=True. É o padrão mais claro.

+
Request 1: web_search/file_search/code_interpreter + ↓ resultado/contexto +Request 2: CRM + Billing + Tickets com parallel_tool_calls=True + ↓ resultados paralelos +Request 3 ou continuação: síntese final
+
+
+

Opção B — Transformar built-in em function sua

+

Crie external_web_search() como function tool client-side. Assim ela entra no seu scheduler junto com CRM e billing. Você ganha controle, mas perde parte da integração hosted.

+
+
+

Opção C — Prefetch pelo orquestrador

+

Seu framework inicia CRM/billing/tickets em paralelo com a chamada OpenAI que usa web search. Reduz latência quando você sabe que esses dados serão necessários.

+
+
+

Opção D — Agentes separados

+

Use um ResearchAgent com built-ins e um OpsAgent com function tools. O agente orquestrador combina os resultados e mantém política de fase.

+
+
+
# Fase 1: hosted tool OpenAI
+research = client.responses.create(
+    model="gpt-5.5",
+    input="Pesquise informações recentes sobre a empresa X.",
+    tools=[{"type": "web_search"}],
+    parallel_tool_calls=False,
+)
+
+# Fase 2: apenas function tools externas, paralelizáveis
+ops = client.responses.create(
+    model="gpt-5.5",
+    previous_response_id=research.id,
+    input="Cruze agora com CRM, billing e tickets do cliente 123.",
+    tools=[crm_lookup_tool, billing_lookup_tool, ticket_lookup_tool],
+    parallel_tool_calls=True,
+)
+ +
+

🎯 Achado novo v3.2 (2026-05-24) — Responses API combina text.format=json_schema + web_search built-in PERFEITAMENTE em todos os 4 modelos testados (4/4 = 100 %) — results/17_openai_structured_plus_tools.json.

+

O guia oficial de Structured Outputs (developers.openai.com/api/docs/guides/structured-outputs) descreve duas formas (function calling vs text.format) mas não documenta explicitamente que text.format=json_schema coexiste com built-in tools. Testamos: coexiste sim, e funciona em todos os modelos da família 4.1 → 5.x.

+ + + + + + + + + +
ModeloA — schema sozinhoB — schema + custom fnC — schema + web_searchD — combo total
gpt-5.5✅ JSON✅ JSON🎯 JSON + search($76982)⚠️ só function_call (sem JSON)
gpt-5.4✅ JSON✅ JSON🎯 JSON + search($76982)⚠️ só function_call (sem JSON)
gpt-5.1✅ JSON⚠️ só function_call🎯 JSON + search($76982)✅ JSON + search (valor 0 — search retornou erro)
gpt-4.1✅ JSON✅ JSON🎯 JSON + search($76988)🎯 JSON + search + function_call (ÚNICO modelo)
Total grounded+structured0/4 (esperado, sem tools)0/4 (esperado, sem search)4/4 = 100 % 🟢2/4 = 50 %
+

Achados sutis:

+
    +
  • Config C funciona em todos os modelos OpenAI. Os preços $76982/$76988 são consistentes (busca real, não memorização — comparar com o $77243.67 fabricado e idêntico do Gemini-3.5-flash quando se força esse combo na API velha generate_content; na Interactions API correta, gemini-3.5-flash retorna dados reais com busca real — vide 5.8).
  • +
  • Config B revela mesmo mutex que o Gemini: gpt-5.1 escolheu emitir function_call em vez de message:output_text com JSON. Quando há custom function disponível, alguns modelos preferem chamá-la a serializar.
  • +
  • Config D é frágil: apenas gpt-4.1 conseguiu emitir os três (web_search + function_call + message JSON) no mesmo turno. gpt-5.5/gpt-5.4 emitiram só reasoning + web_search_call + function_call e omitiram o message JSON final. gpt-5.1 emitiu JSON mas com usd_price=0 e source="error" (provavelmente o search retornou um chunk vazio e o modelo serializou a falha).
  • +
+

Receita produção-segura para OpenAI:

+
resp = client.responses.create(
+    model="gpt-5.5",
+    input="Use web_search to find the current BTC/USD spot price. Return as PriceQuote JSON.",
+    text={
+        "format": {
+            "type": "json_schema",
+            "name": "PriceQuote",
+            "schema": {
+                "type": "object",
+                "properties": {
+                    "asset": {"type": "string"},
+                    "usd_price": {"type": "number"},
+                    "source": {"type": "string"},
+                    "as_of": {"type": "string"},
+                },
+                "required": ["asset","usd_price","source","as_of"],
+                "additionalProperties": False,
+            },
+            "strict": True,
+        }
+    },
+    tools=[{"type": "web_search"}],
+)
+# resp.output → [web_search_call(completed), message(output_text="{...JSON...}")]
+
+ +
+

🎯 ESCOPO FOCADO v3.3 (2026-05-24) — matriz dos 3 modelos OpenAI do escopo (results/21_focused_openai.json, 15 chamadas: 3 modelos × 4 configs structured+tools + 3 parallel FC).

+

Doc oficial OpenAI Web Search (developers.openai.com/api/docs/guides/tools-web-search, fetched 2026-05-24) diz literalmente:

+
"With tool_choice: 'auto', search is optional. Use tool_choice: 'required' or a specific web search tool choice when search must run."
+

Estratégia testada: text.format=json_schema + tools=[{type:"web_search"}] com prompt explícito ("Use web_search to find..."). Sem doc explícito sobre combinar Structured Outputs com built-in tools, mas empírico mostra funciona em 3/3 modelos do escopo:

+ + + + + + + + +
ModeloA schema sozinhoB schema + custom fnC schema + web_searchD combo total (3-em-1)Parallel FC
gpt-5.5 (frontier)✅ JSON✅ JSON🎯 JSON + search($77 021)⚠️ só reasoning + web_search + function_call — sem message JSON✅ 3 paralelas
gpt-5.4-mini (low-latency)✅ JSON⚠️ só function_call🎯 JSON + search($77 021)⚠️ só web_search + function_call — sem JSON✅ 3 paralelas
gpt-5.4-nano (low-cost)✅ JSON⚠️ só function_call🎯 JSON + search($77 016)⚠️ só web_search + function_call — sem JSON✅ 3 paralelas
Sucesso C (schema+search)3/3 modelos = 100 %3/3
+

Achados sutis cross-referenciados com docs:

+
    +
  • Config C funciona em 3/3. Preços $77 016-$77 021 são consistentes entre modelos (busca real, não memorização). Capability silenciosa — doc OpenAI não tem exemplo explícito de text.format=json_schema combinado com {type:"web_search"} em uma só request, mas é suportado em todos os modelos do escopo.
  • +
  • Config B revela mesmo mutex que Gemini: gpt-5.4-mini e gpt-5.4-nano emitem function_call em vez de JSON quando ambas opções estão disponíveis. gpt-5.5 é mais conservador e prefere JSON na ausência de prompt explícito ordenando a fn.
  • +
  • Config D (3-em-1) falha em todos os 3 modelos do escopo. Os 3 emitiram web_search + function_call mas omitiram o message JSON final. Limitação real do escopo: para D, splite em 2 turnos.
  • +
  • Para garantir que web_search rode, doc recomenda tool_choice: "required". Em nossos testes com tool_choice default (auto) + prompt explícito, o search rodou em 100 %.
  • +
+

Receita produção-segura (escopo):

+
resp = client.responses.create(
+    model="gpt-5.5",  # ou gpt-5.4-mini / gpt-5.4-nano
+    input="Use web_search to find the current BTC/USD spot price. Return as PriceQuote JSON.",
+    text={
+        "format": {
+            "type": "json_schema",
+            "name": "PriceQuote",
+            "schema": { ... "additionalProperties": False },
+            "strict": True,
+        }
+    },
+    tools=[{"type": "web_search"}],
+)
+# resp.output → [web_search_call(completed), message(output_text="{...JSON conforme schema...}")]
+
+ +

3.5 OpenAI reasoning models e loops de tools

+

Reasoning models podem pensar antes e entre tool calls, e a documentação recomenda preservar reasoning items em workflows de function calling, seja por previous_response_id ou repassando output items relevantes. [S5] O Cookbook da OpenAI chama atenção para o caso em que modelos que suportam parallel tool calls ainda podem precisar de chamadas em série quando há dependência entre etapas. [S6]

+
Loop robusto com reasoning: + +while True: + response = call_model(context, tools) + calls = extract_client_function_calls(response) + if not calls: + return final_message(response) + + groups = scheduler.partition(calls) # paralelo/serial/locks/aprovação + outputs = execute_groups(groups) + context = preserve_reasoning_items_and_append_tool_outputs(response, outputs)
+

Isso importa porque “paralelo” não é um estado global do agente. É uma propriedade de um conjunto específico de calls independentes em um step específico.

+ +

3.6 OpenAI Agents SDK

+

O Agents SDK é útil quando você quer loop de agente, tracing, handoffs, guardrails, agents-as-tools e execução de function tools com menos boilerplate. A documentação do SDK lista categorias como hosted OpenAI tools, local/runtime tools, function calling, agents as tools e Codex tool. [S9]

+

O detalhe mais importante para o seu framework: ModelSettings.parallel_tool_calls não é a mesma coisa que ToolExecutionConfig.max_function_tool_concurrency. O primeiro controla se o modelo pode emitir múltiplas calls; o segundo controla quantas local function tools o SDK executa simultaneamente depois que o modelo emitiu as calls. [S7] [S8]

+
from agents import Agent, ModelSettings, Runner, RunConfig, ToolExecutionConfig
+
+ops_agent = Agent(
+    name="OpsAgent",
+    model="gpt-5.5",
+    tools=[crm_lookup, billing_lookup, ticket_lookup],
+    model_settings=ModelSettings(parallel_tool_calls=True),
+)
+
+result = await Runner.run(
+    ops_agent,
+    "Consulte CRM, billing e tickets do cliente 123.",
+    run_config=RunConfig(
+        tool_execution=ToolExecutionConfig(
+            max_function_tool_concurrency=2,
+        )
+    ),
+)
+ + + + + + + +
ConfigCamadaSignificado
parallel_tool_calls=TrueModelo/providerModelo pode emitir várias calls em um turno.
max_function_tool_concurrency=2SDK/runtimeMesmo que o modelo emita 5 calls, só 2 local function tools rodam ao mesmo tempo.
Hosted toolsServidor OpenAIWebSearchTool/FileSearchTool/CodeInterpreterTool não passam pelo mesmo pool local.
+ +

3.7 MCP, tool search e superfícies grandes de tools

+

Com remote MCP e catálogos grandes, a latência de listar/importar tools e o custo de schemas ficam relevantes. A documentação de MCP da OpenAI descreve que, quando a API recupera tools de um MCP server, um item mcp_list_tools pode aparecer e deve ser preservado no contexto para evitar refetch em cada turno, otimizando latência. [S10]

+

Para muitas tools, prefira tool search, namespaces ou fases de exposição. O pior padrão é expor 80 tools em todo request e esperar que o modelo escolha corretamente, com baixo custo e baixa latência.

+
+ +
+

4. Anthropic Claude em profundidade

+

Claude tem uma semântica de tool use muito clara para client tools: a resposta pode conter blocos tool_use; seu aplicativo executa e retorna blocos tool_result. A documentação de tool use explica que os custos incluem tokens dos schemas, blocos tool_use, tool_result e, para server-side tools, possíveis cobranças adicionais. [S14]

+ +

4.1 Paralelismo default e disable_parallel_tool_use

+

Por padrão, Claude pode usar múltiplas tools para responder uma consulta. Você desabilita isso com disable_parallel_tool_use=true dentro de tool_choice. Com auto, isso garante no máximo uma tool; com any ou tool, garante exatamente uma tool. [S13]

+
response = client.messages.create(
+    model="claude-opus-4-7",
+    max_tokens=1024,
+    tools=[weather_tool, time_tool, stock_tool],
+    tool_choice={
+        "type": "auto",
+        "disable_parallel_tool_use": True,
+    },
+    messages=[{"role": "user", "content": "Verifique clima e hora em 3 cidades."}],
+)
+ +

4.2 Semântica de chamadas no mesmo assistant turn

+
+

Quando Claude emite várias client tools no mesmo assistant turn, trate essas calls como não ordenadas e independentes. Seu runtime pode executá-las em paralelo, em qualquer ordem, desde que devolva cada resultado com o tool_use_id correto.

+
+

O padrão correto para resultados paralelos é devolver todos os tool_result em uma única mensagem de usuário imediatamente após a mensagem do assistant que continha os tool_use. Separar resultados em múltiplas mensagens tende a degradar ou quebrar o padrão de paralelismo esperado. [S13]

+
# Correto: todos os resultados agrupados em uma única mensagem de user.
+messages.append({
+    "role": "assistant",
+    "content": [
+        {"type": "tool_use", "id": "toolu_1", "name": "get_weather", "input": {"city": "Paris"}},
+        {"type": "tool_use", "id": "toolu_2", "name": "get_weather", "input": {"city": "London"}},
+    ],
+})
+
+messages.append({
+    "role": "user",
+    "content": [
+        {"type": "tool_result", "tool_use_id": "toolu_1", "content": "15C"},
+        {"type": "tool_result", "tool_use_id": "toolu_2", "content": "12C"},
+    ],
+})
+ +

4.3 Client tools vs server tools

+ + + + + + +
TipoQuem executa?Você devolve tool_result?Entram no seu scheduler?
Client toolSeu appSimSim
Server toolAnthropicNão como client tool normal; a API lida com blocos server-sideNão
+
+

Refinamento empírico v3.1. "Trilhas separadas" é a verdade de quem executa, mas não de quando aparecem no histórico. Em testes reais com web_search_20250305 + 3 client tools e tool_choice: auto, tanto claude-opus-4-7 quanto claude-sonnet-4-6 retornaram, no mesmo assistant turn:

+
text · server_tool_use (web_search) · tool_use · tool_use · tool_use   ← stop_reason = "tool_use"
+

O cliente devolveu 3 tool_result agrupados em uma única user message; o turno 1 começou com web_search_tool_result seguido do texto final. Conclusão prática para o adapter: ao preservar o assistant turn, copie todos os blocos verbatim (inclusive server_tool_use) e processe apenas os tool_use client no seu scheduler. Evidência: results/03_anthropic.json.

+
+

Em fluxos com server tools, a API pode retornar stop reasons específicos. A documentação de handling stop reasons menciona pause_turn quando o loop server-side atinge limite de iterações com ferramentas como web search ou web fetch; nesse caso, você deve continuar a conversa enviando a resposta de volta como está. [S16]

+ +

4.4 Extended thinking e tools

+

Com extended thinking, a Anthropic documenta uma limitação importante: tool use com thinking só suporta tool_choice: auto ou tool_choice: none; any e forced tool não são compatíveis porque forçam tool use. Também é necessário preservar thinking blocks durante tool use. [S15]

+

Isso significa que, se seu framework usa Claude com extended thinking, você não deve construir uma política que dependa de forced tool em todas as etapas. Prefira expor um subconjunto seguro de tools, usar instruções fortes e validar no runtime.

+ +
+

🚨 Aprofundamento v3.2 (2026-05-24) — forçar tool_choice={type:"tool", name:"..."} com web_search server tool é PERIGOSO: o modelo pode pular a busca e emitir o tool com dados fabricados (results/18_anthropic_structured_plus_tools.json, 2 modelos × 4 configs).

+

Padrão comum para extrair structured output do Claude: definir um custom tool record_answer com o schema desejado e forçar tool_choice={type:"tool", name:"record_answer"}. Quando você combina com web_search_20250305 server tool (estes probes usaram a 20250305, que segue disponível; há também a web_search_20260209 com dynamic filtering para Opus 4.8/4.7/4.6 e Sonnet 4.6, que requer a code execution tool), esperaria que o modelo: (1) buscasse na web, (2) chamasse record_answer com os dados encontrados. Não é o que acontece:

+ + + + + + + + +
Configopus-4-7sonnet-4-6Veredito
A — web_search sozinho (baseline)✅ buscou, 8 text blocks✅ buscou, 3 text blocksServer tool OK isolado.
B — combo + tool_choice=auto✅ buscou + record_answer com $77136.72 / coinbase✅ buscou + record_answer com $76856.95 / coindesk🎯 PADRÃO CORRETO — funciona perfeitamente em ambos.
C — combo + tool_choice={type:"tool", name:"record_answer"} (forçado)🚨 NÃO buscou. Chamou record_answer com input={} VAZIO🚨 chamou record_answer com {usd_price: 0, source: "pending", as_of: "pending"} — placeholders fabricadosBLOQUEIA o server tool e o modelo fabrica/placeholder os campos.
D — combo + tool_choice={type:"any"}✅ buscou + record_answer com $76578.17 / coinbase✅ buscou + record_answer com $76856.95 / coindesk🎯 SAFE ALTERNATIVA AO FORCED.
+

Por que isso acontece. tool_choice={type:"tool", name:"X"} diz literalmente ao modelo "sua próxima ação DEVE ser chamar X". O modelo respeita essa instrução estrita e pula etapas anteriores que ele faria normalmente, incluindo a chamada ao web_search server tool. Em opus-4-7, isso gerou um tool_use com input={} (o modelo nem inventou dados — admitiu vazio). Em sonnet-4-6, o modelo populou os campos com strings "pending" e número 0 — sintaticamente válido pelo schema, mas semanticamente lixo.

+

Receita correta para structured output via tool em Claude com web search:

+
    +
  1. Use tool_choice={type:"any"} em vez de {type:"tool", name:"X"}. O modelo escolhe quais tools chamar e em que ordem, mas é obrigado a chamar alguma. Empiricamente: buscou primeiro e depois chamou record_answer com dados reais em 2/2 runs.
  2. +
  3. Ou use tool_choice=auto com prompt forte ("ALWAYS call record_answer last"). Mesmo resultado em nossas 2 runs.
  4. +
  5. NUNCA use tool_choice={type:"tool", name:"X"} quando há server tools no mix — você está dizendo ao modelo para pular o server tool.
  6. +
+

Bonus: em opus-4-7 forced, record_answer_input foi literalmente {} (objeto vazio). Nosso código de validação naïve marcou isso como "input_valid: false" apenas por sorte — um validador que aceitasse "tem as chaves required" passaria os placeholders "pending" do sonnet como "input válido". Trate tool_choice forçado + server tool como uma combinação que requer asserts adicionais ("source não pode ser string literal 'pending'", "usd_price > 0", etc.) ou simplesmente não combine.

+
+ +
+

🎯 ESCOPO FOCADO v3.3 (2026-05-24) — matriz dos 3 modelos Anthropic do escopo + cross-reference com doc oficial (results/22_focused_anthropic.json, 15 chamadas).

+

Doc oficial Anthropic Define Tools (platform.claude.com/docs/en/docs/agents-and-tools/tool-use/implement-tool-use, fetched 2026-05-24) diz literalmente, validando empiricamente o bug que descobrimos:

+
"Note that when you have tool_choice as any or tool, the API prefills the assistant message to force a tool to be used. This means that the models will not emit a natural language response or explanation before tool_use content blocks, even if explicitly asked to do so."
+
"Combine tool_choice: {"type": "any"} with strict tool use to guarantee both that one of your tools will be called AND that the tool inputs strictly follow your schema. Set strict: true on your tool definitions to enable schema validation."
+

Implicação: com {type:"tool", name:"X"}, a API literalmente prefilla o próximo token como abertura de tool_use de X — o modelo nunca tem a chance de chamar o web_search server tool que rodaria antes. Nosso teste capturou isso em 3/3 modelos do escopo:

+ + + + + + + + +
ModeloA search alone (baseline)B tool_choice=autoC tool_choice={type:"tool"}D tool_choice={type:"any"}Parallel FC
claude-opus-4-7✅ buscou (16 blocks)✅ $77 136 / coinbase🚨 input={} vazio✅ $77 136 / coinbase✅ 9 paralelas
claude-sonnet-4-6✅ buscou (11 blocks)✅ $76 856 / coindesk⚠️ search vazio + fabricou $108 000 (vs real ~$77k)✅ $76 856 / coindesk✅ 9 paralelas (agrupadas)
claude-haiku-4-5 (1ª vez testado)✅ buscou✅ $76 856 / coindesk🚨 search NÃO chamado + fabricou $67 850 (training data antigo)✅ $77 136 / coinbase✅ 9 paralelas
Sucesso B+D (auto/any)—3/30/3 semântico3/33/3
+

Por que C falha — agora explicado pela doc oficial: o prefill da API empurra o próximo token a ser a abertura de tool_use:record_answer, então o modelo não tem janela para gerar primeiro o server_tool_use:web_search que rodaria antes. O modelo então preenche os campos do schema com o que tiver disponível na memória (haiku → $67k de training data antigo) ou com placeholders (opus → {}) ou com chute selvagem (sonnet → $108k).

+

Achados sutis cross-referenciados com docs:

+
    +
  • Doc Anthropic Parallel Tool Use (parallel-tool-use) confirma: "disable_parallel_tool_use=true when tool_choice type is any or tool, which ensures that Claude uses exactly one tool". Logo, com type:tool, modelo é constrained a UMA tool — bloqueando web_search.
  • +
  • Haiku-4-5 igualmente afetado apesar de ser modelo low-latency — o bug não é de tier, é arquitetural por causa do prefill.
  • +
  • Validador de schema é insuficiente: sonnet emitiu {asset:"BTC", usd_price:108000, source:"coinmarketcap.com", as_of:"2026-05-24"} — passa qualquer validador "tem todas as chaves" e mesmo um "source não-vazio + usd_price > 0". Para detectar fabricação, precisa de cross-validation com runs de B/D.
  • +
+

Receita produção-segura (escopo), seguindo o tip oficial da doc:

+
response = client.messages.create(
+    model="claude-opus-4-7",  # ou sonnet-4-6 / haiku-4-5-20251001
+    max_tokens=2048,
+    messages=[{"role": "user", "content": prompt}],
+    tools=[
+        {"type": "web_search_20250305", "name": "web_search", "max_uses": 3},
+        {
+            "name": "record_answer",
+            "description": "Record the final structured answer. Call this LAST.",
+            "input_schema": price_quote_schema,
+            "strict": True,  # ← tip oficial da doc: combine com tool_choice any para garantir validação
+        },
+    ],
+    tool_choice={"type": "any"},  # SEGURO. NUNCA {type:"tool", name:"X"}.
+)
+# → [server_tool_use:web_search, web_search_tool_result, text, tool_use:record_answer com dados reais]
+

Parallel function calling (3 modelos × 3 cidades × 3 tools = 9 paralelas esperadas):

+ + + + + + + +
Modelon_tool_use emitidasOrdem
claude-opus-4-79 ✅interleaved [weather, time, air] × 3 cidades
claude-sonnet-4-69 ✅agrupada [3× weather, 3× time, 3× air] — padrão diferente!
claude-haiku-4-59 ✅interleaved como opus
+
+ +

4.5 Vantagens e desvantagens do Claude para paralelismo

+ + + + + + + + +
VantagensDesvantagens / cuidados
Semântica de client tool parallelism bem natural; desabilitação explícita por request.Per-tool hard policy continua sendo responsabilidade do framework.
Bom para múltiplas consultas independentes e agregação de dados.Formato de histórico importa muito: resultados paralelos devem ser agrupados corretamente.
Server tools podem reduzir integração manual.Server tools têm latência/custo menos controláveis e não entram no seu executor.
Extended thinking melhora planejamento em tarefas complexas.Extended thinking limita tool_choice forçado e aumenta custo/latência.
+
+ +
+

5. Gemini / google-genai em profundidade

+

Gemini é o caso mais diferente. Ele suporta function calling, parallel function calling, compositional/sequential function calling e combinação de built-in tools com function calling em Gemini 3. A documentação de function calling explicita que o modelo pode chamar múltiplas funções em um único turno, em sequência e com built-in tools. [S18]

+ +

5.1 Modos de function calling

+ + + + + + + + +
ModoSignificadoUso recomendado
AUTOModelo decide responder em texto ou chamar função.Uso geral quando só há function declarations.
ANYModelo deve produzir uma function call e aderir ao schema.Quando o próximo passo precisa obrigatoriamente consultar/agir via tool.
NONEModelo é proibido de fazer function calls.Fase final de síntese ou quando tools devem ser temporariamente desativadas.
VALIDATEDDefault para tool combination/structured outputs; reduz chamadas malformadas.Combinações com built-ins ou quando schema adherence é prioridade.
+

Isso não é equivalente a parallel_tool_calls=False. Mesmo com allowed_function_names, você restringe nomes, não necessariamente quantidade de calls. Para “no máximo uma call”, valide no seu runtime.

+
if not policy.allow_model_parallel_tool_calls and len(response.function_calls or []) > 1:
+    # Escolha uma política explícita:
+    # 1. rejeitar e repromptar
+    # 2. executar só a primeira
+    # 3. serializar via novo step
+    # 4. retornar erro de política
+    raise TooManyToolCalls(response.function_calls)
+ +

5.2 Function call IDs, ordem e execução assíncrona

+

Gemini 3 gera um id único para cada function call; ao devolver resultados, você deve usar o mesmo id no functionResponse. Isso permite mapear resultados assíncronos para as chamadas corretas. [S18]

+
# Esboço: execução manual de function calls Gemini.
+calls = response.function_calls or []
+results = await asyncio.gather(*(dispatch_gemini_call(c) for c in calls))
+
+function_responses = [
+    {
+        "functionResponse": {
+            "name": call.name,
+            "id": call.id,
+            "response": result,
+        }
+    }
+    for call, result in zip(calls, results)
+]
+ +

5.3 Automatic function calling

+

No Python SDK google-genai, você pode passar funções Python diretamente; o SDK converte em declarations, detecta function calls, executa a função, envia a resposta e retorna o texto final. A documentação também mostra como desabilitar esse comportamento com AutomaticFunctionCallingConfig(disable=True). [S18]

+
+

Para framework multi-provider: desabilite automatic function calling quando precisar de controle sobre concorrência, timeouts, retries, tracing, locks, idempotency keys e approval gates.

+
+
from google.genai import types
+
+config = types.GenerateContentConfig(
+    tools=[get_current_temperature],
+    automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
+)
+ +

5.4 Thought signatures

+

Gemini thinking models usam thought signatures para preservar contexto de raciocínio em chamadas multi-turn. Em Gemini 3, durante function calling, retornar thought signatures é obrigatório quando você manipula histórico manualmente; omitir pode gerar erro 4xx. [S20] A documentação também explica que em parallel function calls a assinatura aparece apenas na primeira function call part; em chamadas sequenciais multi-step, cada function call pode ter sua signature e precisa ser preservada. [S20] [S21]

+
Parallel function calling em Gemini 3: + +Model response: + Part 1: functionCall FC1 + thoughtSignature + Part 2: functionCall FC2 + Part 3: functionCall FC3 + +Próximo request: + Preservar FC1 + signature, FC2, FC3 na ordem original + Depois agrupar FR1, FR2, FR3 com ids correspondentes + +Não intercalar: + FC1, FR1, FC2, FR2 ← isso pode dar erro
+ +

5.5 Built-in + custom no mesmo fluxo

+ +
+

✅ PODE — e é oficial. Em Gemini 3.x (o único tier em uso neste corpus), combinar built-in tools — Google Search, Google Maps, URL Context, File Search e Code Execution — com function calling (custom tools) no mesmo turno é uma feature Preview documentada, baseada em tool context circulation. E funciona nas duas superfícies de API: client.models.generate_content(...) e a Interactions API (client.interactions.create). [S19]

+

Verificado 2026-06-03 na doc oficial (ai.google.dev/gemini-api/docs/tool-combination): "Gemini allows the combination of built-in tools, such as google_search, and function calling (also known as custom tools) in a single generation by preserving and exposing the context history of tool calls. Built-in and custom tool combinations allow for complex, agentic workflows where, for example, the model can ground itself in real-time web data before calling your specific business logic." O preview vale somente para a série Gemini 3.

+
+ +

Como ligar — 3 regras (não-negociáveis):

+
    +
  1. Ligue o flag. Defina include_server_side_tool_invocations=true — é ele que habilita a circulação de contexto. (Atenção ao drift de SDK: em google-genai 2.6.0 ele vive em types.ToolConfig, não como kwarg top-level — ver correção empírica logo abaixo.)
  2. +
  3. Declare built-in + custom juntos. Coloque os built-in tools e function_declarations no mesmo tools=[...] para disparar a combinação. Sem function_declarations, a circulação ainda atua sobre os built-ins incluídos.
  4. +
  5. Devolva todos os parts. A cada turno reenvie todos os parts retornados — com id, tool_type e thought_signature exatamente como recebidos. O thought_signature é o contexto criptografado de cada part; omiti-lo faz o modelo dar erro.
  6. +
+ +
+

Modo VALIDATED é o default obrigatório do combo. Quando include_server_side_tool_invocations está ligado, o function calling opera em modo VALIDATED — o modo AUTO não é suportado nessa configuração. Além disso, se system_instruction ou a description de uma function trouxerem informação de local/hora conflitante, o grounding pode degradar. [S19]

+
+ +
+

Matriz de circulação de contexto (oficial, 2026-06-03). Todos suportados em Gemini 3:

+ + + + + + + +
ToolLadoParts trocados
Google Search · Google Maps · URL Context · File SearchServidortoolCall + toolResponse (com id/tool_type/thought_signature)
Code ExecutionServidorexecutableCode + codeExecutionResult
Computer Use · Custom functionsClientefunctionCall + functionResponse (você executa e devolve)
+

Endpoint dedicado: para quem mistura bash tools e custom tools, a doc oficial expõe um endpoint separado gemini-3.1-pro-preview-customtools. Custo: os parts toolCall/toolResponse reenviados contam como prompt_token_count (exceto Google Search, que já cobra por query e não duplica).

+
+ +

Mecânica e regras de SDK abaixo (a doc histórica exigia include_server_side_tool_invocations=True e preservar id, tool_type e thought_signature em todos os parts). [S19]

+
+

Diferença em relação à OpenAI: no Gemini 3, built-in + custom tool combination é explicitamente documentado em Preview. Ainda assim, built-ins são server-side e custom functions são client-side; seu scheduler só executa custom functions.

+
+
response = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents="Pesquise a cidade mais ao norte dos EUA e consulte o clima dela.",
+    config=types.GenerateContentConfig(
+        tools=[
+            types.Tool(
+                google_search=types.ToolGoogleSearch(),
+                function_declarations=[getWeather],
+            ),
+        ],
+        include_server_side_tool_invocations=True,
+    ),
+)
+
+

Correção empírica v3.1 — drift de SDK. No snippet acima, include_server_side_tool_invocations aparece como kwarg top-level de GenerateContentConfig. Em google-genai 2.6.0 essa posição dá pydantic.ValidationError: include_server_side_tool_invocations Extra inputs are not permitted. O campo vive em types.ToolConfig. (SDK mais recente: google-genai 2.10.0, 2026-06-24 — localização em types.ToolConfig confirmada sem mudança.) Forma correta:

+
config = types.GenerateContentConfig(
+    tools=[types.Tool(google_search=types.GoogleSearch(), function_declarations=[getWeather])],
+    automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
+    tool_config=types.ToolConfig(
+        include_server_side_tool_invocations=True,   # ← localização correta
+    ),
+)
+response = client.models.generate_content(
+    model="gemini-3.1-pro-preview",                     # gemini-2.5-flash retorna 400
+    contents="Pesquise a cidade mais ao norte dos EUA e consulte o clima dela.",
+    config=config,
+)
+

Empiricamente: a request foi aceita em gemini-3-pro-preview (preview, desligado 09/03/2026) e rejeitada em gemini-2.5-flash com 400 INVALID_ARGUMENT: "Tool call context circulation is not enabled for models/gemini-2.5-flash". Isso confirma a tese da seção (Preview / Gemini-3-only). Evidência: results/04_gemini.json.

+

Nota (modelos nestes registros empíricos): os resultados medidos abaixo que citam gemini-3-pro-preview são preservados como registro datado — o modelo foi desligado em 09/03/2026 (doc oficial) e reescrever os IDs falsificaria o experimento; comportamento equivalente esperado em gemini-3.1-pro-preview, não re-medido. Os gemini-2.5-* aparecem como linha de base de contraste. Para uso atual prefira gemini-3.1-pro-preview / gemini-3.5-flash, já adotados nos probes mais recentes desta seção.

+
+
+

Refinamento empírico forte v3.1 — semântica real de google_search em Gemini-3 (8 probes em results/13_gemini_tool_combination_real.json e results/14_gemini_tool_combination_no_flag.json).

+

Testando combinações Tool(google_search + function_declarations) em 8 variantes (com e sem flag, em gemini-3-pro-preview e gemini-3-flash-preview, com prompts pedindo dados frescos):

+ + + + + + + + +
ObservaçãoFrequência
grounding_metadata.web_search_queries populado (auto-grounding clássico)0 / 8 probes
gemini-3-flash-preview emite function_call com name="google_search:search" e args.queries=[...] — ou seja, surface a chamada do server-side tool como function call para o cliente3 / 4 probes em flash (independente do flag)
gemini-3-pro-preview chamou direto a custom function fabricando valores (não tentou buscar)3 / 4 probes em pro
Custom function call funciona dentro do config combinado6 / 8 probes
+

Conclusão operacional. O mecanismo real de tool combination em Gemini-3 nesta versão de SDK não é "google_search executa server-side e retorna grounding". É um padrão de circulação de contexto: o modelo emite um function_call nomeado para o servidor de busca (ex.: google_search:search com queries), o cliente decide o que fazer (executar uma busca real e devolver via function_response, ou usar uma fonte alternativa), e o modelo continua. Você é o executor da busca também. Para grounding automático ao estilo "search is invisible", use a forma clássica Tool(google_search=GoogleSearch()) isolada (sem o flag, sem combinação com custom) — mas mesmo assim gemini-3-pro-preview tendeu a pular a busca e fabricar respostas em prompts simples. Próxima implementação a fazer no scheduler: tratar function_call:google_search:search como um runtime adicional ("provider-named search request"), com adapter que pode rotear para um backend real de busca ou para o próprio google_search hosted.

+
+ +
+

Atualização empírica forte v3.1 (2026-05-24) — structured output + built-in/custom tools em gemini-3.5-flash e gemini-3.1-pro-preview (5 probes por modelo em results/15_gemini_structured_plus_tools.json).

+

A restrição histórica de Gemini — "response_schema não pode coexistir com tools" — foi removida nos modelos Gemini-3.x via google-genai==2.6.0. Mas o comportamento é mais sutil que apenas "agora funciona":

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Probegemini-3.5-flashgemini-3.1-pro-previewVeredito
S1 — response_schema sozinho (sem tools)✅ JSON válido ({city, celsius, summary})✅ JSON válido ({city, celsius, summary})Baseline OK em ambos.
S2 — response_schema + google_search built-in✅ API aceita, JSON válido ({asset,usd_price,source,as_of}) MAS grounding_metadata vazio e preço fabricado (structured_AND_grounded=false)🎯 FUNCIONA COM GROUNDING REAL. JSON válido + web_search_queries=["current spot price of Bitcoin in USD"] + grounding_chunks=1 (structured_AND_grounded=true)Restrição histórica LEVANTADA — mas apenas gemini-3.1-pro-preview realmente disparou a busca; 3.5-flash aceitou o combo silenciosamente sem grounding.
S3 — response_schema + function_declarations custom⚠️ Modelo emite function_call(log_price), sem texto JSON (parsed_json_valid=false)⚠️ Idem — emite function_call(log_price), sem JSONMutuamente exclusivos por resposta: quando o modelo decide chamar uma function, ele substitui a structured output em vez de emitir ambos.
S4 — response_schema + google_search + custom (combo total)⚠️ FC custom vence; sem JSON; sem grounding⚠️ FC custom vence; sem JSON; sem groundingMesmo padrão de S3: function call canibaliza a structured output e o grounding não dispara.
S5 — parallel FC plain (regressão)✅ 3 FCs paralelas (get_weather/get_time/get_air), thought_signature em [True, False, False]✅ 3 FCs paralelas, mesma assinatura, IDs únicosParallel FC continua firme nos dois modelos novos.
+

Conclusões operacionais.

+
    +
  • (1) Para o caso real "quero JSON estruturado E quero que o modelo busque na web", use gemini-3.1-pro-preview com tools=[Tool(google_search=GoogleSearch())] + response_mime_type="application/json" + response_schema=…. gemini-3.5-flash não é confiável para esse combo (aceita silenciosamente e fabrica valores).
  • +
  • (2) Não tente combinar response_schema com function_declarations custom esperando obter ambos: o modelo escolherá function call em vez de structured output. Padrão correto: faça duas chamadas — primeiro a function call (sem schema), depois um turno separado com response_schema para serializar o resultado.
  • +
  • (3) O scheduler deve classificar structured_output + google_search como PROVIDER_EXECUTED em gemini-3.1-pro-preview (grounding ocorre no servidor + resultado serializado pelo modelo) e marcar 3.5-flash como degradado ("accepts combo, may not ground"). Para structured_output + function_declarations, marcar como combinação inválida e forçar split em 2 turnos.
  • +
+
+ +
+

📜 Histórico v3.2 (2026-05-24, depois CORRIGIDO em v3.5) — observação inicial: gemini-3.5-flash NA API velha generate_content não dispara google_search quando response_schema está presente (0/9 probes em results/19).

+

O experimento controlado foi: 3 prompts × 3 runs × 2 configs (com/sem schema):

+ + + + + + +
Config (via client.models.generate_content)Grounding rate em gemini-3.5-flash
google_search SEM response_schema (3 prompts × 3 runs)9/9 = 100 % 🟢
google_search COM response_schema (mesmos prompts × 3 runs)0/9 = 0 % 🔴
+

O preço fabricado $77 243,67 USD aparece idêntico em múltiplas runs com schema — confirmação dura de memorização (não busca).

+

Correção v3.5: esse comportamento NÃO é "regressão" — é que a Google moveu o combo "structured + grounding" da generate_content velha para a Interactions API nova (client.interactions.create). Quando testado via Interactions API, gemini-3.5-flash faz grounding 2/2 (100 %) em results/33 — JSON estruturado + GoogleSearchCallStep(queries=['Euro 2024 final ...']) reais. A capability EXISTE; só está na superfície de API correta. Veja seção 5.8 abaixo.

+
+ +
+

Deep dive v3.2 — matriz completa por modelo Gemini × prompt strategy × N runs (results/16_gemini_grounding_depth.json, 40 runs).

+ + + + + + + + + +
ModeloP0 vagoP1 explícito-searchP2 hostil-à-memóriaP3 time-boundedTotal
gemini-3-flash-preview (preview)2/22/22/22/28/8 = 100 % 🏆
gemini-3.1-pro-preview (preview)0/21/21/22/24/8 = 50 % 🟡
gemini-3.5-flash (stable)0/20/20/20/20/8 = 0 % 🔴
gemini-2.5-flash400 INVALID_ARGUMENT em todas as 8 chamadasHARD-LIMIT
gemini-2.5-pro400 INVALID_ARGUMENT em todas as 8 chamadasHARD-LIMIT
+

Quote literal do erro 2.5 (em todas as 16 chamadas): "Tool use with a response mime type: 'application/json' is unsupported" — esta é a restrição histórica original da Gemini, e ela vive ativamente no stack 2.5. Em Gemini-3.x a restrição foi levantada na API (não dá mais 400), mas a implementação varia drasticamente: o preview 3-flash-preview funciona perfeitamente, o 3.1-pro-preview funciona em ~50 %, e o stable 3.5-flash é completamente quebrado.

+

Recomendação operacional refinada (2026-05-24). Para "JSON estruturado + grounding real" em produção:

+
    +
  1. Primeira escolha: gemini-3-flash-preview (preview, mas 100 % de grounding rate medido).
  2. +
  3. Segunda escolha: gemini-3.1-pro-preview com tolerância de 50 % de retries (mais caro mas frontier-class).
  4. +
  5. NÃO USE: gemini-3.5-flash stable para esse combo — silenciosamente fabrica dados e cobra menos. Para 3.5-flash, faça split em 2 turnos: turno 1 = google_search sem schema, turno 2 = serialização com schema sem tools.
  6. +
  7. NUNCA combine em Gemini 2.5: a API rejeita com 400.
  8. +
+
+ +
+

✅ ESCOPO FOCADO v3.5 (2026-05-24) — matriz definitiva dos 3 modelos Gemini, agora corrigida com a descoberta da Interactions API (results/20 + results/33).

+

Doc oficial Gemini Structured Output (ai.google.dev/gemini-api/docs/structured-output, fetched 2026-05-24) diz literalmente:

+
"Gemini 3 lets you combine Structured Outputs with built-in tools, including Grounding with Google Search, URL Context, Code Execution, File Search, and Function Calling. Available only to Gemini 3 series models, gemini-3.1-pro-preview and gemini-3.5-flash."
+

Doc oficial está CERTA — só que o snippet de código publicado mistura método velho (client.models.generate_content) com campo novo (response_format), e isso confundiu meus testes iniciais. Usando a API correta (client.interactions.create):

+ + + + + + + +
ModeloListado na doc?Interactions API (correta)generate_content (velha)Veredito
gemini-3.1-flash-lite❌ NÃO listado2/2 (100 %) ✅9/9 (100 %) ✅FUNCIONA EM AMBAS — capability "silenciosa" na generate_content
gemini-3.5-flash✅ listado2/2 (100 %) ✅0/9 (0 %) 🔴FUNCIONA via Interactions API (combo movido pra superfície agentic nova)
gemini-3.1-pro-preview✅ listado2/2 (100 %) ✅2/9 (22 %, volátil)FUNCIONA via Interactions API de forma estável
+

A mesma doc admite explicitamente: "structured output guarantees syntactically correct JSON, it does not guarantee the values are semantically correct" — exatamente o failure mode que medimos no 3.5-flash via generate_content (JSON conformante, conteúdo fabricado). Por isso a Google moveu o combo pra Interactions API: lá os steps[GoogleSearchCallStep, GoogleSearchResultStep, ThoughtStep, ModelOutputStep] tornam a busca auditável.

+

Recomendação operacional definitiva v3.5:

+
    +
  • 🥇 Recomendado para gemini-3.5-flash e gemini-3.1-pro-preview com schema + grounding: use client.interactions.create() (Interactions API, beta). Steps + output_text JSON estruturado.
  • +
  • Alternativa em client.models.generate_content: use gemini-3.1-flash-lite ou gemini-3-flash-preview — 100 % grounding rate na API velha.
  • +
  • Para uniformidade single-turn cross-modelo: Interactions API (funciona 2/2 em todos os 4 modelos da série 3).
  • +
  • Parallel function calling funciona 3/3 modelos via generate_content: 3 FCs com IDs únicos, thought_signature em [True, False, False]. Confirma seção 5.4 do v3.
  • +
+
+ +

5.8 As duas APIs do google-genai para structured + tools — guia completo (v4.5)

+ +
+

TL;DR (5 segundos). O SDK google-genai tem duas APIs distintas que podem entregar JSON estruturado combinado com Google Search:

+
    +
  • Forma A — client.models.generate_content(): API clássica (GA, estável). Schema via response_mime_type + response_schema. Tools como objetos types.Tool(...). Combo schema+search funciona apenas em gemini-3.1-flash-lite e gemini-3-flash-preview.
  • +
  • Forma B — client.interactions.create(): API agentic nova (Beta). Schema via response_format={...}. Tools como dicts {"type":"google_search"}. Combo funciona em todos os 4 modelos Gemini-3.
  • +
+

O doc oficial mistura as duas no mesmo snippet: chama client.models.generate_content(config={"response_format": ...}). Isso não roda — pydantic rejeita porque response_format não é campo da generate_content API. Para usar response_format, você precisa chamar client.interactions.create. PR #2379 que adicionou o campo só toca google/genai/_interactions/ — nunca tocou GenerateContentConfig.

+
+ +

5.8.1 Decision tree — qual API usar

+
+
┌─ você precisa de schema + google_search no MESMO turno?
+│
+├── SIM em gemini-3.5-flash ou gemini-3.1-pro-preview
+│   └─→ FORMA B (client.interactions.create)              [2/2 grounded ✅]
+│
+├── SIM em gemini-3.1-flash-lite ou gemini-3-flash-preview
+│   ├─→ FORMA A (client.models.generate_content)          [3/3 grounded ✅]
+│   └─→ FORMA B (client.interactions.create)              [2/2 grounded ✅]
+│       (escolha pela API que combina com o resto do seu pipeline)
+│
+├── SIM em gemini-2.5-flash ou gemini-2.5-pro
+│   └─→ NÃO É POSSÍVEL: API retorna 400 INVALID_ARGUMENT
+│       "Tool use with a response mime type: 'application/json' is unsupported"
+│       Faça split em 2 turnos: turno 1 = google_search sem schema;
+│       turno 2 = serialização com schema sem tools.
+│
+└── NÃO (só schema sozinho, ou só search sozinho)
+    └─→ FORMA A (GA estável, sem warnings)
+
+ +

5.8.2 FORMA A — client.models.generate_content() (clássica / GA)

+
+

Quando usar: API estável, sem warning de experimental. Preferida para produção de baixo risco. Para o combo schema + google_search, escolha os modelos certos (vide tabela 5.8.4).

+ +

Código Python completo:

+
from google import genai
+from google.genai import types
+from pydantic import BaseModel, Field
+from typing import List
+
+class MatchResult(BaseModel):
+    winner: str = Field(description="The name of the winner.")
+    final_match_score: str = Field(description="The final match score.")
+    scorers: List[str] = Field(description="The name of the scorer.")
+
+client = genai.Client()  # lê GEMINI_API_KEY do env
+
+resp = client.models.generate_content(
+    model="gemini-3.1-flash-lite",                        # melhor modelo p/ combo nesta API
+    contents="Search for all details for the latest Euro 2024 final.",
+    config=types.GenerateContentConfig(
+        tools=[
+            types.Tool(google_search=types.GoogleSearch()),
+            types.Tool(url_context=types.UrlContext()),
+        ],
+        response_mime_type="application/json",
+        response_schema=MatchResult,                       # Pydantic class OU dict JSON Schema
+        # Equivalente com dict: response_json_schema=MatchResult.model_json_schema()
+    ),
+)
+
+# Output: response.text contém o JSON
+result = MatchResult.model_validate_json(resp.text)
+print(result)
+# winner='Spain' final_match_score='2-1'
+# scorers=['Nico Williams', 'Cole Palmer', 'Mikel Oyarzabal']
+
+# Grounding metadata: em response.candidates[0].grounding_metadata
+gm = resp.candidates[0].grounding_metadata
+print(gm.web_search_queries)
+# ['latest Euro championship winner final score scorers',
+#  'who scored for Spain in Euro 2024 final']
+print(len(gm.grounding_chunks))  # quantidade de fontes consultadas
+ +

Body REST equivalente (caso queira chamar sem SDK):

+
POST https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-lite:generateContent
+Headers:  x-goog-api-key: $GEMINI_API_KEY
+          Content-Type: application/json
+
+{
+  "contents": [
+    {"parts": [{"text": "Search for all details for the latest Euro 2024 final."}]}
+  ],
+  "tools": [
+    {"googleSearch": {}},
+    {"urlContext": {}}
+  ],
+  "generationConfig": {
+    "responseMimeType": "application/json",
+    "responseJsonSchema": {
+      "type": "object",
+      "properties": {
+        "winner": {"type": "string"},
+        "final_match_score": {"type": "string"},
+        "scorers": {"type": "array", "items": {"type": "string"}}
+      },
+      "required": ["winner", "final_match_score", "scorers"]
+    }
+  }
+}
+ +

Response shape:

+
{
+  "candidates": [{
+    "content": {
+      "parts": [
+        {"text": "{\"winner\":\"Spain\",\"final_match_score\":\"2-1\",\"scorers\":[...]}"}
+      ],
+      "role": "model"
+    },
+    "finishReason": "STOP",
+    "groundingMetadata": {
+      "webSearchQueries": ["latest Euro championship winner final score scorers", ...],
+      "groundingChunks": [
+        {"web": {"uri": "https://...", "title": "..."}},
+        ...
+      ]
+    }
+  }],
+  "usageMetadata": {...}
+}
+ +

Pegadinhas conhecidas:

+
    +
  • NÃO use response_format: esse campo não existe em GenerateContentConfig. Pydantic rejeita com Extra inputs are not permitted. Use response_mime_type + response_schema/response_json_schema.
  • +
  • NÃO use {type: "google_search"} (dict shape com chave "type"): esse é shape da Interactions API. Use types.Tool(google_search=types.GoogleSearch()) ou {"google_search": {}} (dict sem "type", chave do tool direto).
  • +
  • Em gemini-3.5-flash e gemini-3.1-pro-preview esta API não dispara busca quando schema está presente: o modelo retorna JSON válido mas conteúdo é fabricado (memorização). Use Forma B nesses modelos.
  • +
  • Em Gemini 2.5 a API retorna 400 INVALID_ARGUMENT: "Tool use with a response mime type: 'application/json' is unsupported".
  • +
+
+ +

5.8.3 FORMA B — client.interactions.create() (nova, Beta) — DEEP DIVE

+
+

Quando usar: sempre que você precisar de qualquer um dos seguintes:

+
    +
  • schema + google_search em gemini-3.5-flash ou gemini-3.1-pro-preview (a Forma A não dispara busca nesses);
  • +
  • steps auditáveis (busca, raciocínio e saída como passos separados);
  • +
  • code_execution, file_search (RAG no Google), computer_use (browser agentic), google_maps, mcp_server (MCP remoto);
  • +
  • multi-turn nativo com previous_interaction_id (sem precisar mandar todo o histórico);
  • +
  • execução assíncrona (background=True) com webhook_config;
  • +
  • agentes preset (Deep Research) ou customizados (DynamicAgentConfig);
  • +
  • controle fino de tier (flex/standard/priority) e nível de raciocínio (thinking_level=minimal|low|medium|high).
  • +
+

Status oficial: Beta. SDK emite UserWarning: "Interactions usage is experimental and may change in future versions." na primeira chamada. Pinning de versão (google-genai==2.6.0) é recomendado.

+
+ +
5.8.3.1 Modelo conceitual — por que existe a Interactions API
+
+

A generate_content API original assume um modelo request→response de texto: você manda contents, ele devolve text. Quando o modelo passou a executar múltiplas tools internas (Google Search, URL Context, Code Execution, File Search, MCP, function-calling, computer-use) e a produzir cadeias de raciocínio com thought signatures, a Google precisou de um novo formato de resposta que pudesse representar a sequência de operações, não só o texto final.

+

A Interactions API resolve isso introduzindo steps como primitiva: cada coisa que o modelo faz vira um Step na lista resp.steps[], na ordem de execução. Conceitualmente é o mesmo modelo que o OpenAI Responses API usa (output: [reasoning, tool_call, message, ...]), e a Anthropic com content blocks ([server_tool_use, web_search_tool_result, text, tool_use, ...]). Os três providers convergiram independentemente para "modelo agentic = lista de passos heterogêneos".

+

Endpoint: POST /v1beta/interactions. Status em 2026-06-10: o schema novo (steps) é o único schema — virou default em 26/05/2026 e o legado foi removido em 08/06/2026. O header Api-Revision agora é ignorado: não é preciso enviá-lo, e o rollback com Api-Revision: 2026-05-07 deixou de existir. SDKs google-genai/@google/genai 1.x ficaram quebrados para Interactions — use as linhas 2.x. A página oficial de migração passou a chamar a Interactions API de "the standard interface for building with Gemini" e a recomendá-la para todo desenvolvimento novo (a overview ainda mantém Beta + generateContent para produção estável). [migração]

+
+ +
5.8.3.2 Assinatura completa de client.interactions.create()
+
+ + + + + + + + + + + + + + + + + + + + + + + +
ParâmetroTipoObrigatórioO que faz
modelstr (ex: "gemini-3.5-flash") ou agent=Sim (model OU agent)Modelo Gemini-3 a usar. Mutuamente exclusivo com agent.
inputstr | list[InputItem]SimPrompt do usuário. String para single-shot; lista de itens (user_input, model_output, tool_result etc) para construir histórico manualmente.
response_formatTextResponseFormat | ImageResponseFormat | AudioResponseFormat | list[...]NãoForma da saída. Para JSON estruturado: {"type":"text","mime_type":"application/json","schema":...}. Suporta polimorfismo (lista para multimodal).
response_mime_typestrNãoAtalho para {"type":"text","mime_type": ...} quando você só quer setar o MIME.
response_modalitieslist[Literal["text","image","audio","video","document"]]NãoQuais modalidades o modelo pode emitir.
toolslist[Tool]NãoTools disponíveis (vide 5.8.3.4).
system_instructionstrNãoDiretrizes persistentes (igual ao system prompt).
environmentEnvironment | strNãoAmbiente remoto (browser sandbox + allowlist de rede + sources). Necessário para computer_use e code_execution em algumas configs.
generation_configGenerationConfigParamNãoParâmetros tradicionais — na Interactions API, thinking_level=minimal|low|medium|high é campo direto de generation_config (aninhado em thinking_config só no generateContent), candidate_count, etc. Note: na série Gemini 3 a doc recomenda manter temperature no default 1.0 — reduzir abaixo de 1.0 pode causar loops/degradação em tarefas de raciocínio/matemática; a doc oficial não menciona top_p/top_k para Gemini 3.
previous_interaction_idstrNãoPara continuar uma interaction anterior em multi-turn. Server-side mantém estado se store=True foi usado.
service_tierLiteral["flex","standard","priority"]NãoSLA: flex mais barato/sem garantias, priority mais caro/baixa latência.
storeboolNãoSe True, server-side persiste a interaction para reuso via previous_interaction_id.
streamboolNãoSe True, retorna iterator de InteractionSSEEvent (steps emitidos progressivamente).
backgroundboolNãoSe True, dispara execução assíncrona e retorna ID; resultado vem via webhook ou poll.
webhook_configWebhookConfigNão{"uris": [...], "user_metadata": {...}} — para receber callbacks de progresso.
agentstr (ex: "deep-research-preview-04-2026")NãoAgente preset gerenciado pela Google. Mutuamente exclusivo com model.
agent_configDynamicAgentConfig | DeepResearchAgentConfigNãoCustomização do agent (collaborative_planning, thinking_summaries, visualization).
extra_headers / extra_query / extra_bodydictNãoBypass para enviar campos arbitrários (útil para flags experimentais não tipadas).
timeoutfloat | httpx.TimeoutNãoOverride do timeout HTTP.
+
+ +
5.8.3.3 response_format — todos os tipos
+
+

O campo response_format é polimórfico (union de 3 tipos + lista). Sempre tem um type discriminador.

+
TextResponseFormat
+
{
+  "type": "text",
+  "mime_type": "application/json" | "text/plain",   # Literal
+  "schema": { ...JSON Schema dict... }              # opcional, só com mime_type=application/json
+}
+

É este o que usamos para JSON estruturado. O type:"text" indica modalidade textual; o mime_type escolhe entre JSON estruturado e texto plano. O schema aceita JSON Schema padrão (object/array/string/integer/number/boolean/null) — Pydantic gera com Recipe.model_json_schema().

+ +
ImageResponseFormat
+
{
+  "type": "image",
+  "mime_type": "image/png" | "image/jpeg" | "image/webp",
+  "delivery": "inline" | "uri",
+  "aspect_ratio": "..." (opcional),
+  "size": "..." (opcional)
+}
+ +
AudioResponseFormat
+
{
+  "type": "audio",
+  "mime_type": "audio/mp3" | "audio/ogg_opus" | "audio/l16" | "audio/wav" | "audio/alaw" | ...,
+  "delivery": "inline" | "uri",
+  "bit_rate": 64000,         # opcional
+  "sample_rate": 24000       # opcional
+}
+ +
Lista (multimodal)
+
response_format=[
+  {"type": "text",  "mime_type": "application/json", "schema": {...}},
+  {"type": "image", "mime_type": "image/png"}
+]
+

Permite emitir múltiplas modalidades em uma única resposta.

+
+ +
5.8.3.4 tools — todos os tipos disponíveis na Interactions API
+
+

O tools é uma lista de dicts com type discriminador. Diferente da Forma A, que usa types.Tool(google_search=...).

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ToolShapeO que faz
google_search{"type":"google_search", "search_types": ["web_search","image_search","enterprise_web_search"]?}Grounding via Google Search. search_types opcional (default web). Aparece como GoogleSearchCallStep → GoogleSearchResultStep.
url_context{"type":"url_context"}Permite o modelo baixar e ler URLs específicas. Aparece como URLContextCallStep(arguments.urls=[...]) → URLContextResultStep(result=[{status:"success|error|paywall|unsafe", url:"..."}]).
code_execution{"type":"code_execution"}Sandbox Python para o modelo rodar código. Aparece como CodeExecutionCallStep(arguments.code, arguments.language="python") → CodeExecutionResultStep(result="...").
file_search{"type":"file_search", "file_search_store_names":["..."], "metadata_filter":"...", "top_k":10}RAG sobre stores gerenciados em client.file_search_stores. file_search_store_names indica quais stores buscar.
function{"type":"function", "name":"...", "description":"...", "parameters":{...JSON Schema}}Function calling clássico. Saída do modelo aparece como FunctionCallStep(name, arguments); você executa e devolve via FunctionResultStep.
mcp_server{"type":"mcp_server", "url":"https://...", "name":"...", "headers":{}, "allowed_tools":[{"mode":"auto|any|none|validated","tools":[...]}]}Servidor MCP remoto. Modelo pode invocar tools daquele MCP server diretamente. Aparece como MCPServerToolCallStep → MCPServerToolResultStep.
computer_use{"type":"computer_use", "environment":"browser", "excluded_predefined_functions":["..."]}Browser agentic (clicks, scroll, type, screenshots). Em gemini-2.5-computer-use-preview-10-2025 (modelo dedicado) e gemini-3-flash-preview (suporte nativo a Computer Use). Verificado 2026-06-03.
google_maps{"type":"google_maps", "latitude":..., "longitude":..., "enable_widget":true}Acesso a dados do Maps (lugares, distâncias). Aparece como GoogleMapsCallStep → GoogleMapsResultStep.
retrieval{"type":"retrieval", "retrieval_types":["vertex_ai_search"], "vertex_ai_search_config":{"datastores":[...], "engine":"..."}}Vertex AI Search integration.
+
+
+ +
5.8.3.5 Anatomia completa dos Steps (em resp.steps[])
+
+

Cada Step tem um type discriminador (literal string) e campos próprios. signature é opcional, idiossincrático do Gemini-3 (preserva contexto criptograficamente entre chamadas).

+
+ + + + + + + + + + + + + + + + + + + + + +
typeClasse PythonCampos relevantesQuando aparece
user_inputUserInputStepcontent: list[TextContent|ImageContent|AudioContent|VideoContent|DocumentContent]Eco do input do usuário em multi-turn (com previous_interaction_id).
thoughtThoughtStepsignature: str?, summary: list[TextContent|ImageContent]?Passo de raciocínio do modelo. O conteúdo é resumo (não a cadeia inteira). signature preserva contexto.
google_search_callGoogleSearchCallStepid, arguments.queries: list[str], search_type: "web_search"|"image_search"|"enterprise_web_search", signature?Sempre que o modelo decide buscar.
google_search_resultGoogleSearchResultStepcall_id: str, result: list[{search_suggestions: str}], is_error?Logo após google_search_call.
url_context_callURLContextCallSteparguments.urls: list[str]Sempre que o modelo decide ler URLs específicas.
url_context_resultURLContextResultStepresult: list[{url: str, status: "success"|"error"|"paywall"|"unsafe"}]Após url_context_call.
code_execution_callCodeExecutionCallSteparguments.code: str, arguments.language: "python"Sempre que o modelo decide rodar código.
code_execution_resultCodeExecutionResultStepresult: str, is_error?Saída do sandbox (stdout/exception).
file_search_callFileSearchCallStepid, signature?Quando o modelo consulta um File Search Store.
file_search_resultFileSearchResultStepcall_id, resultResultados da busca em arquivos.
function_callFunctionCallStepid, name: str, arguments: dictModelo pediu para você executar uma function tool.
function_resultFunctionResultStepcall_id, resultVocê fornece em multi-turn como continuação.
mcp_server_tool_callMCPServerToolCallStepid, arguments, name (da tool do MCP server)Modelo chamou uma tool de MCP remoto.
mcp_server_tool_resultMCPServerToolResultStepresultadoResposta vinda do MCP server.
google_maps_callGoogleMapsCallStepargumentos do query MapsQuando google_maps tool é invocada.
google_maps_resultGoogleMapsResultStepresultado do MapsApós chamada Maps.
model_outputModelOutputStepcontent: list[TextContent|...] — onde está o texto finalSempre o último (ou um dos últimos) step de uma interaction completada.
+
+

Padrão de iteração idiomático:

+
for step in resp.steps:
+    t = step.type   # literal string
+    if t == "google_search_call":
+        queries.extend(step.arguments.queries or [])
+    elif t == "url_context_call":
+        urls_fetched.extend(step.arguments.urls or [])
+    elif t == "code_execution_call":
+        code_blocks.append(step.arguments.code)
+    elif t == "code_execution_result":
+        code_outputs.append((step.result, step.is_error))
+    elif t == "function_call":
+        # FUNCTION_CALL: você precisa executar e devolver em multi-turn
+        pending_calls.append((step.id, step.name, step.arguments))
+    elif t == "thought":
+        thought_summaries.append(step.summary)
+    elif t == "model_output":
+        # extrai texto final
+        for c in (step.content or []):
+            if c.type == "text":
+                final_text += c.text
+
+ +
5.8.3.6 Status do Interaction retornado
+
+

resp.status é um Literal com 7 valores possíveis:

+ + + + + + + + + + + +
StatusSignificadoAção típica do cliente
in_progressAinda processando (background=True ou stream)Polling com client.interactions.retrieve(id) ou aguardar webhook
completedTerminou bem; output_text populadoConsumir resultado
requires_actionTem function_call pendente esperando você devolver function_resultExecutar function e responder com previous_interaction_id + input=[FunctionResultStep(...)]
failedErro irrecuperávelInspecionar steps; retentar
cancelledCancelado pelo cliente—
incompleteParou no meio (limite de tokens, budget)Examinar steps parciais; possivelmente continuar
budget_exceededUltrapassou orçamento configuradoAumentar budget ou aceitar resultado parcial
+
+ +
5.8.3.7 Streaming (SSE)
+
+
for event in client.interactions.create(
+    model="gemini-3.5-flash",
+    input="...",
+    response_format={"type":"text", "mime_type":"application/json", "schema":...},
+    tools=[{"type":"google_search"}],
+    stream=True,
+):
+    # event é um InteractionSSEEvent (union)
+    et = event.type
+    if et == "interaction.created":
+        interaction_id = event.interaction.id
+    elif et == "step.start":
+        print(f"step started: {event.step.type}")
+    elif et == "step.delta":
+        # delta incremental (text streaming, search queries chegando, etc)
+        if hasattr(event.delta, "text"):
+            sys.stdout.write(event.delta.text)
+    elif et == "step.stop":
+        print(f"step done: {event.step.type}")
+    elif et == "interaction.completed":
+        print("DONE:", event.interaction.output_text)
+    elif et == "error":
+        print("ERR:", event.error)
+

Tipos de evento SSE (event_type, schema novo — único desde 08/06/2026): interaction.created, interaction.in_progress, interaction.requires_action, interaction.completed, step.start, step.delta, step.stop (mais error). O legado interaction.status_update foi substituído por in_progress/requires_action e removido em 08/06/2026 junto com o schema legado.

+
+ +
5.8.3.8 Multi-turn — previous_interaction_id e store
+
+
# Turno 1 — armazenar para reuso
+r1 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Quem ganhou a Euro 2024?",
+    tools=[{"type": "google_search"}],
+    store=True,                             # ← persiste no servidor
+)
+print(r1.id)  # "v1_..."
+
+# Turno 2 — continuar sem reenviar histórico
+r2 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="E quem foram os artilheiros?",
+    previous_interaction_id=r1.id,          # ← server traz contexto
+    tools=[{"type": "google_search"}],
+)
+
+# Multi-turn com function_call resolvido
+r3_partial = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Qual a temperatura em São Paulo?",
+    tools=[{"type":"function", "name":"get_weather",
+            "parameters":{"type":"object","properties":{"city":{"type":"string"}}}}],
+    store=True,
+)
+if r3_partial.status == "requires_action":
+    fc = next(s for s in r3_partial.steps if s.type == "function_call")
+    weather = run_weather_tool(**fc.arguments)   # você executa
+    r3_done = client.interactions.create(
+        model="gemini-3.5-flash",
+        input=[{"type":"function_result", "call_id": fc.id, "result": weather}],
+        previous_interaction_id=r3_partial.id,
+    )
+
+ +
5.8.3.9 Agents preset — Deep Research
+
+
# Agentes gerenciados pela Google (sem precisar definir model)
+resp = client.interactions.create(
+    agent="deep-research-preview-04-2026",              # atual; ou "-max-preview-04-2026" p/ capacidade máxima
+    input="Compare as últimas 3 gerações de TPUs do Google em latência e energia.",
+    agent_config={
+        "type": "deep-research",
+        "collaborative_planning": True,                  # pede plano antes de executar
+        "thinking_summaries": "auto",                    # resume cadeia de raciocínio
+        "visualization": "auto",                         # pode emitir gráficos
+    },
+)
+# resp.steps terá muitos GoogleSearchCallStep, URLContextCallStep, ThoughtStep,
+# e ModelOutputStep com relatório final estruturado.
+

Agentes disponíveis: deep-research-preview-04-2026 (atual, base) e deep-research-max-preview-04-2026 (capacidade máxima). O deep-research-pro-preview-12-2025 é o legado (ainda listado na Interactions API; prefira o -04-2026). Não há variante "pro" na linha atual.

+
+ +
5.8.3.10 Background mode + webhooks
+
+
# Dispara em background; recebe callback quando terminar
+resp = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Long-running deep research task...",
+    background=True,
+    webhook_config={
+        "uris": ["https://my-app.example.com/gemini-callback"],
+        "user_metadata": {"job_id": "12345", "tenant": "acme"},
+    },
+    store=True,
+)
+print(resp.id, resp.status)  # "v1_...", "in_progress"
+
+# Mais tarde, o webhook recebe POST com o resultado;
+# OU você faz polling:
+final = client.interactions.retrieve(resp.id)
+if final.status == "completed":
+    print(final.output_text)
+

Webhook CRUD completo em client.webhooks.*: create, get, list, update, delete, rotate_signing_secret (TS: rotateSigningSecret). Assinatura HMAC é validada via signing_secret. Correção 2026-06-03: não existe método ping; a doc oficial lista get.

+
+ +
5.8.3.11 Controle fino — service_tier, thinking_level, tool_choice, environment
+
+
resp = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="...",
+
+    # Latência vs custo
+    service_tier="priority",                   # "flex" | "standard" | "priority"
+
+    # Profundidade de raciocínio
+    generation_config={
+        "thinking_config": {"thinking_level": "high"}    # "minimal"|"low"|"medium"|"high"
+    },
+
+    # Restringe quais tools podem ser usadas
+    tool_choice={
+        "mode": "any",                             # "auto"|"any"|"none"|"validated"
+        "tools": ["google_search", "url_context"]  # subset dos tools declarados
+    },
+
+    # Sandbox para code_execution / computer_use
+    environment={
+        "type": "remote",
+        "network": {
+            "allowlist": [
+                {"domain": "api.coindesk.com"},
+                {"domain": "*.example.com"},
+            ]
+        },
+        "sources": [                                  # arquivos pré-carregados
+            {"type": "inline", "content": "...", "target": "/data/notes.txt"},
+            {"type": "gcs", "source": "gs://my-bucket/file.csv", "target": "/data/file.csv"},
+        ],
+    },
+    tools=[{"type": "code_execution"}],
+)
+
+ +
5.8.3.12 Função utilitária — extrair tudo do response
+
+
from dataclasses import dataclass, field
+from typing import Any
+
+@dataclass
+class InteractionSummary:
+    output_text: str = ""
+    search_queries: list[str] = field(default_factory=list)
+    urls_fetched: list[str] = field(default_factory=list)
+    code_blocks: list[str] = field(default_factory=list)
+    code_outputs: list[tuple[str, bool]] = field(default_factory=list)
+    function_calls: list[tuple[str, str, dict[str, Any]]] = field(default_factory=list)
+    thought_signatures: list[str] = field(default_factory=list)
+    citations: list[dict[str, Any]] = field(default_factory=list)
+    step_trace: list[str] = field(default_factory=list)
+
+
+def summarize_interaction(resp) -> InteractionSummary:
+    """Walk resp.steps and pull every interesting piece into one summary."""
+    s = InteractionSummary(output_text=resp.output_text or "")
+    for step in (resp.steps or []):
+        t = step.type
+        s.step_trace.append(t)
+        if t == "google_search_call":
+            s.search_queries.extend(step.arguments.queries or [])
+        elif t == "url_context_call":
+            s.urls_fetched.extend(step.arguments.urls or [])
+        elif t == "code_execution_call":
+            s.code_blocks.append(step.arguments.code or "")
+        elif t == "code_execution_result":
+            s.code_outputs.append((step.result or "", bool(step.is_error)))
+        elif t == "function_call":
+            s.function_calls.append((step.id, step.name, step.arguments or {}))
+        elif t == "thought":
+            if step.signature:
+                s.thought_signatures.append(step.signature)
+        elif t == "model_output":
+            for c in (step.content or []):
+                if getattr(c, "annotations", None):
+                    for ann in c.annotations:
+                        s.citations.append(ann.model_dump(exclude_none=True))
+    return s
+
+
+# Uso
+resp = client.interactions.create(...)
+summary = summarize_interaction(resp)
+print(summary.step_trace)
+# ['google_search_call', 'google_search_result', 'thought', 'model_output']
+print(summary.search_queries)
+print(summary.output_text)
+
+ +
5.8.3.13 Error handling
+
+
from google.genai._interactions import _exceptions as ie
+
+try:
+    resp = client.interactions.create(model="gemini-3.5-flash", input="...")
+except ie.BadRequestError as e:        # 400 — payload inválido
+    ...
+except ie.AuthenticationError as e:    # 401 — API key inválida
+    ...
+except ie.PermissionDeniedError as e:  # 403 — sem acesso
+    ...
+except ie.NotFoundError as e:          # 404 — model/interaction id não existe
+    ...
+except ie.RateLimitError as e:         # 429 — backoff e retry
+    ...
+except ie.InternalServerError as e:    # 5xx — retry com jitter
+    ...
+except ie.APIConnectionError as e:     # falha de rede
+    ...
+except ie.APITimeoutError as e:        # timeout
+    ...
+
+# Para inspeção pós-erro
+if resp.status == "failed":
+    last_step = resp.steps[-1] if resp.steps else None
+    print("failed at:", getattr(last_step, "type", "<none>"))
+    print("trace:", [s.type for s in (resp.steps or [])])
+
+ +
5.8.3.14 Citações (Annotation / FileCitation / URLCitation / PlaceCitation)
+
+

Quando o modelo usa google_search, url_context, file_search ou google_maps, partes do output_text ganham citações ancoradas em ranges de caracteres. Estão em ModelOutputStep.content[].annotations[].

+
for step in resp.steps:
+    if step.type == "model_output":
+        for content in (step.content or []):
+            if content.type != "text":
+                continue
+            for ann in (content.annotations or []):
+                if ann.type == "url_citation":
+                    print(f"chars [{ann.start_index}:{ann.end_index}] cite {ann.url}")
+                elif ann.type == "file_citation":
+                    print(f"chars [{ann.start_index}:{ann.end_index}] cite file {ann.file_id}")
+                elif ann.type == "place_citation":
+                    print(f"chars [{ann.start_index}:{ann.end_index}] cite place {ann.place_id}")
+
+ +
5.8.3.15 Reference card — body REST completo (todos os campos)
+
+
POST https://generativelanguage.googleapis.com/v1beta/interactions
+Headers:
+  x-goog-api-key: $GEMINI_API_KEY
+  Api-Revision:   2026-05-20                # IGNORADO desde 08/06/2026 (schema novo e o unico; rollback removido) - pode omitir este header
+  Content-Type:   application/json
+
+{
+  "model": "gemini-3.5-flash",              # OU "agent": "deep-research-preview-04-2026"
+  "input": "Quem ganhou a Euro 2024?",       # ou lista de step inputs
+
+  "system_instruction": "Você é um analista esportivo conciso.",
+
+  "response_format": {
+    "type": "text",
+    "mime_type": "application/json",
+    "schema": { ...JSON Schema... }
+  },
+  "response_modalities": ["text"],
+  "response_mime_type": "application/json",  # atalho equivalente
+
+  "tools": [
+    {"type": "google_search", "search_types": ["web_search"]},
+    {"type": "url_context"},
+    {"type": "code_execution"},
+    {"type": "file_search", "file_search_store_names": ["my-store"], "top_k": 5},
+    {"type": "function", "name": "get_weather",
+     "parameters": {"type":"object","properties":{"city":{"type":"string"}}}},
+    {"type": "mcp_server", "url": "https://mcp.example.com",
+     "name": "remote_tools", "headers": {"Authorization": "Bearer ..."}},
+    {"type": "google_maps", "latitude": -23.5, "longitude": -46.6, "enable_widget": false},
+    {"type": "computer_use", "environment": "browser"},
+    {"type": "retrieval", "retrieval_types": ["vertex_ai_search"],
+     "vertex_ai_search_config": {"datastores": ["..."], "engine": "..."}}
+  ],
+
+  "tool_choice": {
+    "mode": "any", "tools": ["google_search", "url_context"]
+  },
+
+  "generation_config": {
+    "thinking_config": {"thinking_level": "high"},
+    "candidate_count": 1,
+    "max_output_tokens": 4096,
+    "stop_sequences": ["</answer>"],
+    "seed": 42
+  },
+
+  "environment": {
+    "type": "remote",
+    "network": {"allowlist": [{"domain": "api.coindesk.com"}]},
+    "sources": [
+      {"type": "inline", "content": "...", "target": "/data/file.txt"}
+    ]
+  },
+
+  "previous_interaction_id": "v1_...",      # multi-turn server-side
+  "store": true,                              # persiste para futuros previous_interaction_id
+
+  "service_tier": "standard",                 # "flex" | "standard" | "priority"
+
+  "stream": false,
+  "background": false,
+
+  "webhook_config": {
+    "uris": ["https://my-app/callback"],
+    "user_metadata": {"job_id": "abc"}
+  },
+
+  "agent_config": {                          # se usar agent= ao invés de model=
+    "type": "deep-research",
+    "collaborative_planning": true,
+    "thinking_summaries": "auto",
+    "visualization": "auto"
+  }
+}
+
+ +
5.8.3.16 Pegadinhas e erros comuns (consolidado)
+
+
    +
  • NÃO use contents=: aqui é input=. (Forma A usa contents=.)
  • +
  • NÃO encapsule em config={...}: kwargs diretos no método.
  • +
  • Tools shape é {"type":"..."} (com chave "type") — NÃO types.Tool(google_search=...) (que é da Forma A).
  • +
  • Header Api-Revision (desde 08/06/2026): o schema novo é o único — era default desde 26/05/2026 e o legado foi removido em 08/06/2026. O header agora é ignorado: 2026-05-20 é desnecessário e 2026-05-07 não faz mais rollback. SDKs google-genai/@google/genai 1.x estão quebrados para Interactions — use as linhas 2.x.
  • +
  • Output em resp.output_text, não resp.text.
  • +
  • Grounding em resp.steps[GoogleSearchCallStep].arguments.queries, não em resp.candidates[].grounding_metadata (este último é da Forma A).
  • +
  • Aviso de Beta: a primeira chamada emite UserWarning: "Interactions usage is experimental...". Silencie ou aceite.
  • +
  • Status "requires_action": o modelo está esperando você devolver function_result. Sem isso a interaction nunca completa.
  • +
  • Tier "flex" não garante latência: para SLA usar "priority".
  • +
  • O snippet do doc oficial em "Structured outputs with tools" mistura métodos — usa client.models.generate_content(config={"response_format":...}), que não funciona. O caminho correto é este (client.interactions.create).
  • +
+
+ +

5.8.4 Matriz definitiva — qual modelo funciona em qual API

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModeloStatus GoogleListado no doc para combo?Forma A (generate_content)
schema + google_search
Forma B (interactions.create)
schema + google_search
Recomendação
gemini-3.5-flashstable✅ Sim0/50+ grounded — fabrica $77 243,672/2 grounded — JSON real, queries reaisUse Forma B
gemini-3.1-pro-previewpreview✅ Sim2/9 (22 %) volátil2/2 groundedUse Forma B
gemini-3.1-flash-litestable❌ Não listado9/9 grounded (100 %)2/2 groundedForma A ou B — escolha pela uniformidade do resto do pipeline
gemini-3-flash-previewpreview❌ Não listado (lista antiga do doc listava)8/8 grounded (100 %)2/2 groundedForma A (mais barato, mesma confiabilidade)
gemini-2.5-flashstable❌ Não suporta400 INVALID_ARGUMENT(não testado — Interactions API é Gemini-3 only)Faça split 2-turn
gemini-2.5-prostable❌ Não suporta400 INVALID_ARGUMENT(não testado — Interactions API é Gemini-3 only)Faça split 2-turn
+
+ +

5.8.5 Diferenças estruturais — referência rápida

+
+ + + + + + + + + + + + + + + + + + + + + + + +
AspectoForma A — generate_content()Forma B — interactions.create()
Método SDKclient.models.generate_content(...)client.interactions.create(...)
Status SDKGA (sem warning)Beta (UserWarning: "Interactions usage is experimental")
URL REST/v1beta/models/{model}:generateContent/v1beta/interactions
Header obrigatóriox-goog-api-keyx-goog-api-key (Api-Revision ignorado desde 08/06/2026)
Promptcontents= (lista de Content ou string)input= (string ou estrutura)
Wrappingconfig=GenerateContentConfig(...)Kwargs diretos no método
Schemaresponse_mime_type="application/json" + response_schema=PydanticClass (ou response_json_schema=dict)response_format={"type":"text", "mime_type":"application/json", "schema":json_schema_dict}
Tools shapetools=[types.Tool(google_search=types.GoogleSearch()), types.Tool(url_context=types.UrlContext())] (objeto) ou [{"google_search":{}},{"url_context":{}}] (dict sem "type")tools=[{"type":"google_search"},{"type":"url_context"}] (dict com "type")
Output (texto)resp.textresp.output_text
Output (grounding)resp.candidates[0].grounding_metadata.web_search_queries + grounding_chunksresp.steps[] com GoogleSearchCallStep(arguments.queries=[...]) + GoogleSearchResultStep + ThoughtStep + ModelOutputStep
Streamingclient.models.generate_content_stream(...)(não confirmado para o combo schema+tools)
System instructionconfig.system_instruction="..."system_instruction="..." kwarg direto
Parallel function calling✅ funciona com function_declarations + emite múltiplos function_call parts✅ funciona via tools=[{"type":"function","function":{...}}]
+
+ +

5.8.6 Erro comum #1 — usar o snippet literal do doc

+
+

O doc oficial em "Structured outputs with tools" publica este snippet:

+
response = client.models.generate_content(           # método da API velha
+    model="gemini-3.5-flash",
+    contents="Search for all details for the latest Euro.",
+    config={
+        "tools": [{"google_search": {}}, {"url_context": {}}],
+        "response_format": {                              # campo da API nova
+            "text": {"mime_type": "application/json",
+                     "schema": MatchResult.model_json_schema()}
+        },
+    },
+)
+

Rodando exatamente isso (tests/test_doc_literal.py seção A):

+
FAILED: pydantic.ValidationError: 1 validation error for GenerateContentConfig
+response_format
+  Extra inputs are not permitted [type=extra_forbidden, ...]
+

Por quê: o método é da generate_content mas o campo response_format só existe na Interactions API. Correção: migrar para client.interactions.create (Forma B) com kwargs diretos. Veja 5.8.3.

+
+ +

5.8.7 Erro comum #2 — REST com "mimeType": "application/json" no endpoint errado

+
+

Doc REST publica:

+
POST /v1beta/models/gemini-3.5-flash:generateContent     ← endpoint da API velha
+{
+  "generationConfig": {
+    "responseFormat": {
+      "text": {"mimeType": "application/json", "schema": {...}}    ← campo da API nova
+    }
+  }
+}
+

Backend retorna:

+
HTTP 400 INVALID_ARGUMENT
+"Invalid value at 'generation_config.response_format.text.mime_type'
+ (type.googleapis.com/google.ai.generativelanguage.v1beta.TextResponseFormat.MimeType),
+ \"application/json\""
+

Por quê: o endpoint :generateContent tem proto TextResponseFormat.MimeType mapeado como enum, e "application/json" não é valor válido (brute-force de 26 valores em results/30 mostra que o único que passa é "APPLICATION_JSON"). Correção: usar o endpoint correto /v1beta/interactions (sem header Api-Revision — ignorado desde 08/06/2026, o schema steps é o único); lá o campo response_format.mime_type aceita a string "application/json" normalmente.

+
+ +

5.8.8 Wrapper portável — abstrai as duas APIs por trás de uma função

+
+

Se você está escrevendo um agente que precisa funcionar em qualquer modelo Gemini-3, este wrapper roteia para a API certa baseado no modelo:

+
import warnings
+warnings.filterwarnings("ignore", category=UserWarning)
+
+from google import genai
+from google.genai import types
+from pydantic import BaseModel
+from typing import Any, Type
+
+# Modelos onde a Forma A grounds de forma confiável no combo schema+search.
+# Em outros modelos da série 3, usar Forma B (Interactions API).
+_GENERATE_CONTENT_GROUND_OK = {"gemini-3.1-flash-lite", "gemini-3-flash-preview"}
+
+
+def grounded_structured_output(
+    client: genai.Client,
+    model: str,
+    prompt: str,
+    schema_class: Type[BaseModel],
+    use_url_context: bool = True,
+) -> tuple[BaseModel, list[str]]:
+    """
+    Retorna (resultado_pydantic, queries_executadas).
+    Roteia automaticamente para a API que funciona em cada modelo.
+    """
+    if model in _GENERATE_CONTENT_GROUND_OK:
+        # --- Forma A ---
+        tools = [types.Tool(google_search=types.GoogleSearch())]
+        if use_url_context:
+            tools.append(types.Tool(url_context=types.UrlContext()))
+        resp = client.models.generate_content(
+            model=model,
+            contents=prompt,
+            config=types.GenerateContentConfig(
+                tools=tools,
+                response_mime_type="application/json",
+                response_schema=schema_class,
+            ),
+        )
+        result = schema_class.model_validate_json(resp.text)
+        gm = resp.candidates[0].grounding_metadata
+        queries = list(getattr(gm, "web_search_queries", []) or []) if gm else []
+        return result, queries
+    else:
+        # --- Forma B ---
+        tools = [{"type": "google_search"}]
+        if use_url_context:
+            tools.append({"type": "url_context"})
+        resp = client.interactions.create(
+            model=model,
+            input=prompt,
+            response_format={
+                "type": "text",
+                "mime_type": "application/json",
+                "schema": schema_class.model_json_schema(),
+            },
+            tools=tools,
+        )
+        result = schema_class.model_validate_json(resp.output_text)
+        queries: list[str] = []
+        for step in (resp.steps or []):
+            if type(step).__name__ == "GoogleSearchCallStep":
+                queries.extend(list(getattr(step.arguments, "queries", []) or []))
+        return result, queries
+
+
+# Exemplo de uso — mesmo código serve para qualquer modelo Gemini-3
+from pydantic import Field
+from typing import List
+
+class MatchResult(BaseModel):
+    winner: str = Field(description="Winner")
+    final_match_score: str = Field(description="Final score")
+    scorers: List[str] = Field(description="Scorers")
+
+client = genai.Client()
+for model in ["gemini-3.5-flash", "gemini-3.1-pro-preview",
+              "gemini-3.1-flash-lite", "gemini-3-flash-preview"]:
+    result, queries = grounded_structured_output(
+        client, model,
+        "Search for all details for the latest Euro 2024 final.",
+        MatchResult,
+    )
+    print(f"{model:30s} -> winner={result.winner}, queries={queries[:2]}")
+# gemini-3.5-flash               -> winner=Spain, queries=['Euro 2024 final ...']
+# gemini-3.1-pro-preview         -> winner=Spain, queries=['Euro 2024 final ...']
+# gemini-3.1-flash-lite          -> winner=Spain, queries=['latest Euro ...']
+# gemini-3-flash-preview         -> winner=Spain, queries=['Euro 2024 ...']
+

O wrapper isola a diferença das duas APIs em um único lugar; o código de chamada fica idêntico para todos os modelos.

+
+ +

5.8.9 Evidência empírica

+
+

Forma B (Interactions API) — results/33_gemini_interactions_api.json (16 chamadas, 4 modelos × 2 configs × 2 runs):

+ + + + + + + + +
Modelocom toolssem tools
gemini-3.5-flash2/2 grounded ✅0/2 (esperado, sem tools)
gemini-3.1-pro-preview2/2 grounded ✅0/2 (esperado)
gemini-3.1-flash-lite2/2 grounded ✅0/2 (esperado)
gemini-3-flash-preview2/2 grounded ✅0/2 (esperado)
+

Forma A (generate_content) — results/32_gemini_two_doc_versions.json (48 chamadas, 4 modelos × 3 configs × 3-4 runs):

+ + + + + + + + +
Modeloresponse_mime_type+response_json_schema + google_search+ url_context
gemini-3.5-flash0/3 ❌0/3 ❌
gemini-3.1-pro-preview0/3 ❌1/3 ⚠️ (volátil)
gemini-3.1-flash-lite3/3 ✅3/3 ✅
gemini-3-flash-preview3/3 ✅3/3 ✅
+

Scripts reprodutíveis: tests/test_gemini_interactions_api.py (resultados em results/33), tests/test_gemini_two_doc_versions.py (results/32), tests/test_doc_literal.py (prova snippet do doc literalmente quebrado + 3 bypasses funcionando).

+

5 claims do CLAIMS.json v4.4 marcadas REVISED_IN_V4_5 (com revision_note explicando o erro de teste anterior). 5 novas claims afirmativas adicionadas. Total: 45 claims em CLAIMS.json v4.5.

+
+ +

5.9 Vantagens e desvantagens do Gemini para esse problema

+ + + + + + + + +
VantagensDesvantagens / cuidados
Documenta parallel e compositional function calling.Não há boolean simples equivalente a parallel_tool_calls=False para “no máximo uma” call.
IDs por function call ajudam execução assíncrona.Histórico manual exige preservar IDs e thought signatures corretamente.
Built-in + custom em Gemini 3 é documentado em Preview.Preview implica maior risco de mudança; precisa validar compatibilidade de modelo.
Automatic function calling acelera protótipos.Automatic execution reduz controle operacional do seu framework.
+
+ +
+

6. É possível escolher quais tools são paralelas e quais sequenciais?

+
+

Nativamente, de forma forte e universal: não. Em geral, os provedores oferecem controle por request/turn, por tool_choice/subconjunto, por modo de function calling ou por SDK runtime. Uma política “esta tool sempre paralela; esta tool sempre sequencial” precisa ser implementada no seu framework.

+
+ +

6.1 O que dá para fazer nativamente

+ + + + + + + + +
FornecedorControles úteisLimite
OpenAI Responsesparallel_tool_calls, tool_choice, allowed tools, forced function, fasesNão define política paralela por tool; built-ins quebram a expectativa de function parallelism.
OpenAI Agents SDKModelSettings.parallel_tool_calls, max_function_tool_concurrency, conditional tools, approval gatesCap de concorrência é global/local, não regra semântica por ferramenta.
Anthropicdisable_parallel_tool_use, tool_choice, subconjunto de toolsSem flag per-tool hard; descrições são soft control.
Geminimode, allowed_function_names, automatic function calling on/offRestringir nomes não garante uma única chamada nem política por side effect.
+ +

6.2 O que instruções resolvem — e o que não resolvem

+

Instruções ao agente ajudam muito para orientar o modelo:

+
Use tools em paralelo apenas quando forem read-only, idempotentes e independentes.
+Nunca chame em paralelo tools que criam, atualizam, deletam, enviam mensagens,
+cobram pagamentos, reservam estoque ou modificam estado externo.
+Para dependências, chame uma tool, aguarde o resultado e só então chame a próxima.
+

Mas isso é controle probabilístico. Para invariantes de negócio, use hard controls: não exponha a tool naquele turno, desabilite paralelismo, aplique locks, exija aprovação, use idempotency keys e valide o plano antes de executar.

+ +

6.3 Manifesto por tool

+

O modo robusto é registrar metadados operacionais para cada tool:

+
@dataclass
+class ToolSpec:
+    name: str
+    runtime_kind: Literal[
+        "client_function",
+        "openai_hosted",
+        "anthropic_server",
+        "gemini_builtin",
+        "local_shell",
+        "remote_mcp",
+        "agent_as_tool",
+    ]
+
+    read_only: bool
+    idempotent: bool
+    side_effect: bool
+    irreversible: bool = False
+
+    parallel_safe: bool = False
+    requires_approval: bool = False
+    requires_idempotency_key: bool = False
+
+    # Para locks: customer:{customer_id}, order:{order_id}, file:{path}
+    resource_key_template: str | None = None
+
+    timeout_ms: int = 10_000
+    max_retries: int = 0
+    rate_limit_bucket: str | None = None
+

Exemplo em YAML:

+
crm_get_customer:
+  runtime_kind: client_function
+  read_only: true
+  idempotent: true
+  side_effect: false
+  parallel_safe: true
+  timeout_ms: 1500
+
+billing_get_balance:
+  runtime_kind: client_function
+  read_only: true
+  idempotent: true
+  side_effect: false
+  parallel_safe: true
+  timeout_ms: 2500
+
+charge_card:
+  runtime_kind: client_function
+  read_only: false
+  idempotent: false
+  side_effect: true
+  irreversible: true
+  parallel_safe: false
+  requires_approval: true
+  requires_idempotency_key: true
+  resource_key_template: "payment:{customer_id}"
+
+openai_web_search:
+  runtime_kind: openai_hosted
+  read_only: true
+  scheduler_controlled: false
+ +

6.4 Classificação operacional

+ + + + + + + + + + +
ClasseExemplosPolítica recomendada
Read-only independenteCRM lookup, weather, exchange rate, doc searchparalelo permitido com timeout e retry leve
Read-only caro/lentoSearch externa, data warehouse, vector search pesadoParalelo com cap de concorrência, cache e budgets
Mutação reversívelAtualizar tag, criar draft, salvar notaSerial por recurso ou approval leve
Mutação irreversívelPagamento, envio de e-mail, pedido, deleção permanentenunca paralelo automático; aprovação, idempotency key, lock
Dependente de resultado anteriorcreate_customer → create_subscriptionSteps sequenciais ou composite tool
Hosted/server-sideBuilt-in search/code/fileNão entra no executor client-side; preservar eventos/partes conforme API
+
+ +
+

7. Scheduler recomendado para seu framework

+

O scheduler deve agir como uma camada de segurança e eficiência entre o modelo e o mundo externo. Ele não deve simplesmente executar tudo que o modelo emitiu.

+ +

7.1 Pipeline de execução

+
1. Provider adapter extrai tool calls brutas +2. Normalizador converte para NormalizedToolCall +3. Registry adiciona ToolSpec +4. Policy validator classifica: permitido, rejeitado, exige aprovação, serial, paralelo +5. Planner constrói batches ou DAG +6. Scheduler executa com semaphores, locks, timeouts, retries +7. Formatter monta tool outputs no formato do provedor +8. Próximo call do modelo preserva histórico/IDs/reasoning/signatures
+ +

7.2 Estrutura normalizada

+
@dataclass
+class NormalizedToolCall:
+    provider: Literal["openai", "anthropic", "gemini"]
+    call_id: str
+    name: str
+    args: dict[str, Any]
+    runtime_kind: str
+    raw: Any
+
+    # Útil para logs e depuração
+    turn_id: str
+    step_index: int
+
+@dataclass
+class ToolExecutionResult:
+    call_id: str
+    name: str
+    ok: bool
+    content: Any = None
+    error: str | None = None
+    latency_ms: int | None = None
+ +

7.3 Validação antes de executar

+
def validate_calls(calls: list[NormalizedToolCall], registry: ToolRegistry, policy: AgentToolPolicy):
+    decisions = []
+    for call in calls:
+        spec = registry[call.name]
+
+        if spec.runtime_kind.endswith("hosted") or spec.runtime_kind.endswith("builtin"):
+            decisions.append((call, "provider_executed"))
+            continue
+
+        if spec.requires_approval:
+            decisions.append((call, "needs_approval"))
+            continue
+
+        if spec.side_effect and policy.mutation_policy == "forbid_parallel":
+            decisions.append((call, "serial"))
+            continue
+
+        if spec.parallel_safe and spec.read_only:
+            decisions.append((call, "parallel"))
+        else:
+            decisions.append((call, "serial"))
+
+    return decisions
+ +

7.4 Locks por recurso

+

Algumas tools podem ser paralelas em recursos diferentes, mas não no mesmo recurso. Exemplo: atualizar cliente 123 e cliente 456 em paralelo pode ser aceitável; duas atualizações no cliente 123 devem ser serializadas.

+
async def execute_with_resource_locks(calls, registry, lock_manager):
+    async def run_one(call):
+        spec = registry[call.name]
+        key = render_resource_key(spec.resource_key_template, call.args)
+        if key:
+            async with lock_manager.lock(key):
+                return await dispatch(call)
+        return await dispatch(call)
+
+    return await asyncio.gather(*(run_one(c) for c in calls))
+ +

7.5 Batches com semáforo

+
async def run_parallel_batch(calls, max_concurrency: int):
+    sem = asyncio.Semaphore(max_concurrency)
+
+    async def guarded(call):
+        async with sem:
+            return await run_with_timeout_and_retries(call)
+
+    return await asyncio.gather(*(guarded(c) for c in calls))
+ +

7.6 DAG de dependências

+

Quando você consegue inferir dependências, use uma DAG. Dependências vêm de três lugares: steps diferentes emitidos pelo modelo, outputs que alimentam argumentos futuros e conflitos de recurso/side effect.

+
Exemplo: + +get_customer(customer_id=123) ─┬─► create_invoice(customer.id) + └─► get_contract(customer.id) + +billing_get_balance(customer_id=123) ───────────────┘ + +Batch 1 paralelo: get_customer, billing_get_balance +Batch 2 serial/dependente: get_contract, create_invoice conforme resultado
+
+ +
+

8. Latência, custo e throughput

+

8.1 Fórmula mental

+ + + + + + + + +
ModoTempo aproximadoQuando é bom?
SerialT_model_decide + Σ T_tool_i + T_model_finalDependências, mutações, segurança.
ParaleloT_model_decide + max(T_tool_i) + overhead + T_model_finalReads independentes, I/O-bound.
Prefetch externomax(T_model_hosted, T_prefetch_group) + T_model_finalQuando você sabe de antemão quais dados serão necessários.
Duas fasesT_hosted_phase + T_function_phase_parallel + sínteseQuando built-in e function tools precisam coexistir com controle seguro.
+ +

8.2 Exemplo numérico

+

Suponha:

+ + + + + + + + + +
OperaçãoLatência
web_search hosted3.500 ms
crm_lookup700 ms
billing_lookup1.200 ms
ticket_lookup2.400 ms
síntese final1.000 ms
+ + + + + + + + +
EstratégiaTempo aproximadoComentário
Serial puro~7.900 ms + overhead de modeloSeguro, mas lento.
Fase hosted depois externas paralelas~3.500 + max(700,1200,2400) + 1.000 = ~6.900 ms + overheadBom equilíbrio quando OpenAI built-in é necessário.
Prefetch externo em paralelo com hostedmax(3.500, 2.400) + 1.000 = ~4.500 ms + overheadMais rápido, mas pode buscar dados desnecessários.
Function wrapper para web_search + tudo paralelomax(3.500,700,1200,2400)+1.000 = ~4.500 ms + overheadControle alto, mas perde integração hosted nativa.
+ +

8.3 Custo de schemas e histórico

+

Tools aumentam tokens. Anthropic documenta que custos de tool use incluem schemas enviados no parâmetro tools, blocos tool_use, blocos tool_result e possíveis cobranças adicionais para server-side tools. [S14] OpenAI MCP também recomenda preservar itens como mcp_list_tools para evitar relistar tools e reduzir latência. [S10] Gemini tool combination conta parts intermediários de toolCall/toolResponse no histórico de requests. [S19]

+

Práticas recomendadas:

+
    +
  • Não exponha todo o catálogo de tools em todo turno.
  • +
  • Use fases, namespaces, tool search ou allowed tools.
  • +
  • Minimize schemas profundos demais.
  • +
  • Retorne resultados enxutos, estruturados e sem payloads gigantes.
  • +
  • Use cache para lookups read-only e resultados de busca quando compatível com freshness.
  • +
+ +

8.4 Throughput e rate limits

+

Paralelismo reduz latência individual, mas pode aumentar QPS e carga no banco. Uma execução paralela com 10 tools por usuário e 100 usuários simultâneos vira 1.000 chamadas externas simultâneas. O scheduler precisa de:

+
    +
  • semaphore global por provider;
  • +
  • semaphore por tool ou rate-limit bucket;
  • +
  • timeouts curtos e diferenciados por tool;
  • +
  • circuit breaker para serviços degradados;
  • +
  • retry com backoff só para operações idempotentes;
  • +
  • fallback para resultados parciais quando o produto permitir.
  • +
+ +

8.5 Latência de hosted tools é menos controlável

+

Built-ins podem ser excelentes por integração, mas a latência é opaca. OpenAI web search, por exemplo, pode ser usado como tool na Responses API, e o modelo decide se pesquisa ou não; em cenários agentic/reasoning, uma busca pode envolver mais deliberação e passos internos. [S4] Code interpreter também pode iterar código até resolver o problema, o que é poderoso mas menos previsível em latência. [S2]

+
+ +
+

9. Padrões arquiteturais recomendados

+
+
+

Padrão 1 — Fases read/write

+

Primeiro exponha apenas tools read-only e paralelizáveis. Depois, em fase separada, exponha tools de mutação com paralelismo desligado.

+
Phase A: read-only parallel + CRM, billing, tickets, docs +Phase B: reasoning/synthesis +Phase C: mutation serial + create_invoice, send_email, charge_card
+
+
+

Padrão 2 — Composite tool para transações

+

Para fluxos críticos, encapsule a sequência em uma única tool procedural que controla locks, transação, retry e idempotência.

+
@tool
+async def checkout_order(cart_id, payment_method_id, idempotency_key):
+    async with lock(f"cart:{cart_id}"):
+        inventory = await reserve_inventory(cart_id)
+        charge = await charge_card(payment_method_id, inventory.amount, idempotency_key)
+        order = await create_order(cart_id, charge.id)
+        return {"order_id": order.id, "status": "confirmed"}
+
+
+

Padrão 3 — Batch tool

+

Em vez de permitir 30 chamadas da mesma tool, exponha uma batch tool que aceita lista. Reduz overhead, melhora rate limit e simplifica retorno.

+
@tool
+async def batch_get_weather(cities: list[str]) -> dict[str, Weather]:
+    return await weather_client.batch(cities)
+
+
+

Padrão 4 — Hosted phase + client phase

+

Ideal para OpenAI quando precisa de built-ins e function tools externas. Use hosted em fase própria, depois client functions em paralelo.

+
OpenAI hosted search → external client tools parallel → final answer
+
+
+

Padrão 5 — Orchestrator prefetch

+

Quando dados internos são quase sempre necessários, busque-os antes ou em paralelo à chamada do modelo. Troca overfetch por latência menor.

+
+
+

Padrão 6 — Agent-as-tool controlado

+

Use subagentes para encapsular capacidades, mas trate cada subagente como uma tool com timeout, budget e política de side effects.

+
+
+
+ +
+

10. Cenários práticos

+

10.1 Suporte ao cliente: pesquisa pública + dados internos

+ + + + + + + +
ProviderDesenho recomendadoPor quê?
OpenAIFase 1 web_search hosted; fase 2 CRM/billing/tickets function tools paralelas.Evita depender de function parallelism com built-ins.
AnthropicSe usar server web search, tratar como server-side; client tools em step separado ou conforme API retornar.Client/server têm protocolos diferentes.
GeminiGemini 3 tool combination pode combinar Google Search + custom getCustomer em Preview; preservar parts/signatures.Feature documentada para built-in + custom.
+ +

10.2 Pagamento e checkout

+

Não deixe o modelo emitir reserve_inventory, charge_card, create_order e send_receipt como ferramentas independentes paralelizáveis. Use uma composite tool com idempotency key e lock. O modelo deve chamar uma única operação de negócio.

+

Regra: pagamento e mutações irreversíveis nunca devem depender apenas de instruções textuais ao modelo. Use enforcement no runtime.

+ +

10.3 Busca em múltiplas bases internas

+

Bom caso para paralelismo: docs legais, tickets, CRM e base de contratos podem ser consultados em paralelo, desde que sejam read-only. Depois o modelo sintetiza. Use cap de concorrência para não sobrecarregar vector stores ou bancos.

+ +

10.4 Muitas chamadas da mesma tool

+

Se o modelo frequentemente chama get_price(sku) 50 vezes, isso é sinal para criar batch_get_prices(skus). Batch tools reduzem round-trips de tool, tokens de tool_result e pressão no scheduler.

+ +

10.5 Atualização de arquivos/código

+

Aplicar patches em arquivos ou rodar shell precisa de sandboxing, logs e, em muitos casos, approval. OpenAI documenta riscos de shell e recomenda sandbox, allowlists/denylists e auditoria. [S11]

+
+ +
+

11. Quando usar qual API/SDK

+ + + + + + + + + + + + + + + + + + + + + + + + +
EscolhaUse quandoEvite quando
OpenAI Responses API diretaVocê quer controle fino multi-provider, fases manuais, built-ins OpenAI, function loop próprio, streaming/event parsing e scheduler custom.Você quer menos boilerplate e está focado só em OpenAI com agentes simples.
OpenAI Agents SDKVocê quer Runner, tracing, handoffs, agents-as-tools, hosted tools e controle de concorrência local de function tools.Você precisa de abstração 100% simétrica entre OpenAI/Claude/Gemini ou controle total do protocolo.
Anthropic SDK / Messages APIVocê quer Claude com client tool parallelism claro e controle por disable_parallel_tool_use.Você não quer lidar com formatação rigorosa de tool_result e limitações de extended thinking.
google-genaiVocê quer Gemini, multimodalidade, IDs de function call, tool combination em Gemini 3 e integração Google.Você não quer lidar com thought signatures/parts em histórico manual ou features em Preview.
+ +

11.1 Regra de roteamento por caso

+
def choose_provider_strategy(provider, tools, task):
+    has_hosted = any(t.runtime_kind in HOSTED_KINDS for t in tools)
+    has_mutation = any(t.side_effect for t in tools)
+
+    if provider == "openai" and has_hosted and any(t.runtime_kind == "client_function" for t in tools):
+        return "split_into_hosted_phase_then_client_function_phase"
+
+    if provider == "anthropic" and task.requires_extended_thinking:
+        return "auto_tool_choice_only_and_runtime_validation"
+
+    if provider == "gemini" and has_hosted:
+        return "tool_context_circulation_if_gemini3_else_split_phases"
+
+    if has_mutation:
+        return "serial_or_composite_tool_with_approval"
+
+    return "parallel_client_function_calls_with_concurrency_cap"
+
+ +
+

12. Riscos, segurança, observabilidade e testes

+

12.1 Riscos técnicos

+ + + + + + + + + + +
RiscoExemploMitigação
Race conditionDuas tools atualizam o mesmo cliente.Lock por recurso e serialização.
Side effect duplicadoRetry cobra cartão duas vezes.Idempotency key e retry apenas em operações idempotentes.
OverfetchPrefetch busca dados sensíveis desnecessários.Data minimization e política de necessidade.
Rate limit100 usuários geram 1.000 calls simultâneas.Semaphores, rate limit buckets, circuit breaker.
Histórico inválidoGemini sem thought signature ou Anthropic tool_result fora de ordem.Provider adapter com testes de contrato.
Latência imprevisívelHosted code/search faz iterações internas.Budgets, timeouts, modo background quando aplicável, UX progressiva.
+ +

12.2 Observabilidade mínima

+

Registre por tool call:

+
    +
  • provider, model, turn_id, step_index, call_id;
  • +
  • nome da tool, argumentos redigidos, runtime_kind;
  • +
  • decisão do scheduler: parallel, serial, rejected, approval, hosted;
  • +
  • latência, status, erro, retry_count;
  • +
  • resource_key e lock_wait_ms;
  • +
  • tokens/custo quando disponível;
  • +
  • correlation id para chamada externa.
  • +
+ +

12.3 Testes/evals específicos

+ + + + + + + + + + + + +
TesteO que validar
Prompt com 5 reads independentesModelo emite múltiplas calls; scheduler paraleliza dentro do cap.
Prompt com dependênciaModelo ou runtime serializa: get_customer antes de create_subscription.
Prompt tentando forçar pagamento paraleloRuntime bloqueia ou exige aprovação.
OpenAI built-in + external toolsFramework divide em fases; não depende de parallel function calling no mesmo request.
Anthropic parallel tool_resultResultados agrupados em uma única mensagem e imediatamente após tool_use.
Gemini function calls paralelasIDs preservados; thought signatures/parts não intercalados incorretamente.
Serviço externo lentoTimeout e resposta parcial funcionam.
Rate limit simuladoCircuit breaker e backoff protegem sistema.
+
+ +
+

13. Checklist operacional

+
+
+

Design de tools

+
    +
  • Nome claro e schema pequeno.
  • +
  • Descrição com quando usar e quando não usar.
  • +
  • Metadados: read_only, side_effect, idempotent, parallel_safe.
  • +
  • Batch tool para chamadas repetidas.
  • +
  • Composite tool para transações críticas.
  • +
+
+
+

Config por provider

+
    +
  • OpenAI: se houver built-ins, separar fase hosted de fase client functions.
  • +
  • Agents SDK: distinguir parallel_tool_calls de max_function_tool_concurrency.
  • +
  • Anthropic: usar disable_parallel_tool_use quando precisar limitar a uma tool.
  • +
  • Gemini: desabilitar automatic function calling quando o scheduler precisa controlar execução.
  • +
+
+
+

Runtime

+
    +
  • Semaphores por provider/tool.
  • +
  • Timeouts por tool.
  • +
  • Retries só idempotentes.
  • +
  • Locks por recurso para mutações.
  • +
  • Approval gates para ações irreversíveis.
  • +
+
+
+

Histórico/provider adapter

+
    +
  • OpenAI: preservar reasoning items ou usar previous_response_id.
  • +
  • Anthropic: tool_result imediatamente após tool_use, agrupados no paralelo.
  • +
  • Gemini: preservar IDs, parts e thought signatures.
  • +
  • MCP: preservar tool list/context quando a API recomendar para latência.
  • +
+
+
+
+ + +
+

14. Protocolo nativo de tool loop por provedor

+

Esta seção desce do nível conceitual para o formato operacional. Em um framework multi-provider, você deve esconder as diferenças por trás de adaptadores, mas não deve apagá-las mentalmente. Cada provedor tem um jeito diferente de representar chamadas, resultados, IDs, histórico e estado de reasoning.

+ +

14.1 OpenAI Responses API — loop manual de function tools

+

Na Responses API direta, o loop típico é: chamar o modelo, procurar output items de function call, executar suas funções, devolver output items de função, repetir até o modelo retornar mensagem final. Em reasoning models, preserve reasoning items ou use previous_response_id para manter continuidade. [S5] [S6]

+
async def run_openai_function_loop(client, *, model, input_, tools, policy):
+    previous_response_id = None
+    pending_input = input_
+
+    while True:
+        response = client.responses.create(
+            model=model,
+            input=pending_input,
+            tools=tools,
+            previous_response_id=previous_response_id,
+            parallel_tool_calls=policy.allow_model_parallel_tool_calls,
+        )
+
+        calls = extract_openai_function_calls(response)
+        if not calls:
+            return extract_final_text(response)
+
+        # Normalizar, validar, agrupar e executar com seu scheduler.
+        normalized = normalize_openai_calls(calls, response=response)
+        results = await scheduler.execute(normalized, policy=policy)
+
+        # Montar outputs no formato esperado pela Responses API.
+        pending_input = [
+            {
+                "type": "function_call_output",
+                "call_id": result.call_id,
+                "output": json.dumps(result.content if result.ok else {"error": result.error}),
+            }
+            for result in results
+        ]
+        previous_response_id = response.id
+

Detalhe de produção: se você usa store=false, zero data retention ou histórico manual, precisa cuidar de reasoning/encrypted reasoning items conforme a documentação; não simplifique isso para “só devolver tool outputs”. [S5]

+ +

14.2 OpenAI com built-ins — loop hospedado vs loop client-side

+

Quando há built-ins OpenAI, o loop tem uma parte invisível para você: a tool hospedada roda no servidor do provedor. Seu framework pode observar outputs/eventos, mas não executa aquela tool. Por isso, para built-ins + externas, o protocolo recomendado é duas fases técnicas:

+
async def run_openai_hosted_then_client(client, query, customer_id):
+    # 1) Fase hosted: OpenAI executa web/file/code tool.
+    research = client.responses.create(
+        model="gpt-5.5",
+        input=query,
+        tools=[{"type": "web_search"}],
+        parallel_tool_calls=False,
+    )
+
+    # 2) Fase client-side: apenas suas functions, agora paralelizáveis.
+    ops = await run_openai_function_loop(
+        client,
+        model="gpt-5.5",
+        input_="Use o contexto anterior e consulte dados internos do cliente.",
+        tools=[crm_lookup_tool, billing_lookup_tool, ticket_lookup_tool],
+        policy=AgentToolPolicy(
+            allow_model_parallel_tool_calls=True,
+            max_client_tool_concurrency=3,
+        ),
+        previous_response_id=research.id,  # se seu wrapper suportar passar isso
+    )
+
+    return ops
+ +

14.3 Anthropic Messages API — loop manual de client tools

+

Claude retorna blocos tool_use; você executa e devolve blocos tool_result. Para paralelismo, a regra crítica é agrupar os resultados em uma única mensagem de usuário, logo depois da mensagem do assistant com as calls. [S13]

+
async def run_anthropic_tool_loop(client, *, model, messages, tools, policy):
+    while True:
+        response = client.messages.create(
+            model=model,
+            max_tokens=policy.max_tokens,
+            tools=tools,
+            tool_choice=build_anthropic_tool_choice(policy),
+            messages=messages,
+        )
+
+        tool_uses = [b for b in response.content if b.type == "tool_use"]
+        if not tool_uses:
+            return extract_claude_text(response)
+
+        # Acrescentar a mensagem do assistant exatamente como retornada.
+        messages.append({"role": "assistant", "content": response.content})
+
+        normalized = normalize_anthropic_tool_uses(tool_uses)
+        results = await scheduler.execute(normalized, policy=policy)
+
+        # Importante: uma única mensagem user com todos os tool_result.
+        messages.append({
+            "role": "user",
+            "content": [
+                {
+                    "type": "tool_result",
+                    "tool_use_id": r.call_id,
+                    "content": json.dumps(r.content if r.ok else {"error": r.error}),
+                }
+                for r in results
+            ],
+        })
+

Com extended thinking, não force tool_choice: any nem tool_choice: tool; a documentação limita thinking + tool use a auto ou none. [S15]

+ +

14.4 Gemini / google-genai — loop manual de function calls

+

Em Gemini, o loop manual precisa preservar functionCall.id, functionResponse.id e, em thinking models, thought signatures/parts na posição correta. [S18] [S20]

+
async def run_gemini_manual_loop(client, *, model, contents, config, policy):
+    history = list(contents)
+
+    while True:
+        response = client.models.generate_content(
+            model=model,
+            contents=history,
+            config=config,
+        )
+
+        calls = response.function_calls or []
+        if not calls:
+            return response.text
+
+        # Preservar o model content inteiro, incluindo thought signatures.
+        history.append(response.candidates[0].content)
+
+        normalized = normalize_gemini_function_calls(calls)
+        results = await scheduler.execute(normalized, policy=policy)
+
+        # Agrupar function responses; usar o mesmo id.
+        history.append({
+            "role": "user",
+            "parts": [
+                {
+                    "functionResponse": {
+                        "name": r.name,
+                        "id": r.call_id,
+                        "response": r.content if r.ok else {"error": r.error},
+                    }
+                }
+                for r in results
+            ]
+        })
+

Se você usa o SDK padrão de chat e não manipula histórico manualmente, muita preservação de signatures é automática. Se seu framework reordena, comprime, resume ou injeta histórico, você precisa tratar signatures como campos sagrados. [S20] [S21]

+
+ +
+

15. Truth tables: o que esperar em cada combinação

+

15.1 OpenAI Responses API

+ + + + + + + + + +
Tools expostasparallel_tool_callsComportamento seguro de assumirArquitetura recomendadaEmpírico v3.1
Só function tools client-sidetrueModelo pode emitir múltiplas function calls; você pode executar em paralelo.Scheduler com cap, locks e timeouts.CONFIRMADO gpt-5.5 3/3, gpt-4.1 3/3 (overlap ~605 ms)
Só function tools client-sidefalseZero ou uma tool call.Bom para mutações, forced steps e debugging.CONFIRMADO exatamente 1 em ambos
Só built-in toolsirrelevante para seu schedulerOpenAI executa hosted tools; você não paraleliza client-side.Use quando integração hosted vale mais que controle.não testado isoladamente
Built-ins + function toolstruenão assumir function parallelism; docs dizem que parallel function calling não é possível com built-ins.Separar em fases ou transformar built-in em function sua. [S1]REFUTADO p/ gpt-5.5 3/5 runs MISTURARAM web_search_call + 3 FCs paralelas no mesmo turno. gpt-5.1 0/4. gpt-4.1 0/4. Doc literalmente falso para gpt-5.5; verdadeiro para gpt-4.1.
Remote MCP hosted + functionsdependeTrate MCP hospedado como superfície provider-side; não assuma execução no seu scheduler.Adapter específico; preservar itens de lista/contexto para latência. [S10]não testado
+ +

15.2 Anthropic Claude

+ + + + + + + + + + +
tool_choicedisable_parallel_tool_useResultado esperadoUsoEmpírico v3.1
autofalse ou omitidoZero, uma ou várias client tools.Reads independentes e tarefas abertas.CONFIRMADO 9 paralelos em opus 4.7 e sonnet 4.6 (overlap ~610 ms)
autotrueZero ou uma tool.Quando quer limitar fan-out.CONFIRMADO exatamente 1
anytrueExatamente uma tool.Quando precisa obrigar uma chamada, exceto com extended thinking.OK sem thinking; 400 com thinking
tooltrueExatamente a tool forçada.Fase sequencial controlada, exceto com extended thinking.OK sem thinking; 400 com thinking
nonen/aNenhuma tool.Síntese final ou fase sem ações.não testado
server web_search_20250305 + N client toolsEm UM turno: text · server_tool_use · N tool_use paralelos, stop_reason="tool_use". Depois você devolve os tool_result client e o turno seguinte traz web_search_tool_result + texto.REFINAMENTO sobre 4.3 — server+client coexistem no MESMO assistant turn, em opus 4.7 e sonnet 4.6.
+

Adicionalmente: claude-opus-4-7 exige a nova API thinking={type: "adaptive"} + output_config={effort: "high"} em vez do antigo thinking={type: "enabled", budget_tokens: N}. Usar a sintaxe antiga em opus-4-7 retorna 400 "thinking.type.enabled" is not supported for this model.

+ +

15.3 Gemini

+ + + + + + + + + + + + + + + +
ModeO que controlaO que não controlaRuntime enforcementEmpírico v3.1
AUTOModelo decide texto ou function call.Não garante no máximo uma call.Validar quantidade e segurança.3 FCs em gemini-3-pro e gemini-2.5-flash
ANYForça function call.Não equivale a “uma única chamada” em todos os casos.Validar len(function_calls).3 FCs paralelas em ambos — não limita a 1, como o relatório alertou
NONEProíbe function calls.Não remove built-in context já no histórico.Usar para síntese.0 FCs, só texto
VALIDATEDSchema adherence maior; default em tool combination.Não substitui política de side effects.Preservar parts/signatures.não testado isoladamente
Tool combination Tool(google_search + function_declarations) + tool_config.include_server_side_tool_invocations=TrueGemini-3-only (Preview); requer ToolConfig e não top-level config.CONFIRMADO gemini-3-pro aceita; gemini-2.5-flash retorna 400 "Tool call context circulation is not enabled"
Semântica real de google_search em Gemini-3 (8 probes)Surface como function call: gemini-3-flash emite function_call(name="google_search:search", args={queries:[...]}) para o cliente executar — não auto-grounding. Em 0/8 probes apareceu grounding_metadata.web_search_queries.REFINAMENTO mecanismo é circulação de contexto, não execução invisível; cliente é o executor da busca também. Evidência: results/13_*.json e results/14_*.json.
thought_signature em parallel FCsAparece apenas na PRIMEIRA function call part.CONFIRMADO em 9 FCs: [T,F,F,F,F,F,F,F,F] em gemini-3-pro e gemini-2.5-flash
call.id por function callGemini 3 gera IDs únicos; Gemini 2.5 não.CONFIRMADO gemini-3-pro: a223p9x7, 4cjkq7j8, i3a4aoi4; gemini-2.5-flash: todos null
structured output (response_schema) sozinhoJSON válido conforme schema; modelo serializa diretamente.CONFIRMADO em gemini-3.5-flash e gemini-3.1-pro-preview (2026-05-24)
response_schema + google_search built-inRestrição histórica LEVANTADA. Em gemini-3.1-pro-preview: JSON válido E grounding real (web_search_queries + grounding_chunks). Em gemini-3.5-flash: aceita silenciosamente, retorna JSON válido, mas não dispara busca (fabrica valores).REFUTA doc histórica para 3.1-pro-preview; PARCIAL para 3.5-flash. Evidência: results/15_gemini_structured_plus_tools.json
response_schema + function_declarations customMutuamente exclusivos por resposta. Quando o modelo decide chamar a function, ela substitui a saída textual JSON — você recebe apenas function_call parts, sem texto schemado.NUANCE OPERACIONAL — sempre fazer split em 2 turnos: turno 1 = function call (sem schema); turno 2 = serialização com response_schema.
+
+ +
+

16. Validação pós-modelo: o modelo sugere, o framework decide

+

Mesmo quando a API permite chamadas paralelas, o framework deve validar se elas são aceitáveis. Isso é especialmente importante quando o modelo emite várias chamadas no mesmo turno, porque “mesmo turno” não significa “seguro executar junto”.

+ +

16.1 Algoritmo de decisão

+
def classify_execution(calls, registry, policy):
+    provider_executed = []
+    needs_approval = []
+    serial = []
+    parallel_candidates = []
+
+    for call in calls:
+        spec = registry[call.name]
+
+        if spec.runtime_kind in {"openai_hosted", "anthropic_server", "gemini_builtin"}:
+            provider_executed.append(call)
+            continue
+
+        if spec.requires_approval or spec.irreversible:
+            needs_approval.append(call)
+            continue
+
+        if spec.side_effect:
+            serial.append(call)
+            continue
+
+        if spec.parallel_safe and spec.read_only:
+            parallel_candidates.append(call)
+        else:
+            serial.append(call)
+
+    # Depois, dividir candidatos paralelos por locks/rate limit buckets.
+    parallel_batches = split_by_resource_conflicts(parallel_candidates, registry)
+    return ExecutionPlan(provider_executed, needs_approval, serial, parallel_batches)
+ +

16.2 O que fazer quando o modelo emite algo proibido

+ + + + + + + + + +
SituaçãoResposta do frameworkMensagem ao modelo
Duas mutações no mesmo recursoExecutar em série ou rejeitar uma.“As operações nesse recurso foram serializadas por política de consistência.”
Pagamento sem aprovaçãoBloquear e pedir confirmação ao usuário.“A cobrança exige confirmação explícita antes de execução.”
Tool não permitida na faseRejeitar e repromptar com allowed tools.“Essa tool não está disponível nesta fase; use apenas as ferramentas de leitura.”
Gemini retorna múltiplas calls quando política é no máximo umaRejeitar/serializar e continuar em step separado.“Execute uma chamada por vez nesta etapa.”
OpenAI built-in + funções em mesmo requestNão tentar consertar dentro do mesmo request; separar fases.Não aplicável; é decisão de orquestração antes da chamada.
+ +

16.3 Tool error como mecanismo de correção

+

Quando uma tool call é rejeitada por política, não esconda isso do modelo. Devolva um resultado estruturado informando a razão, para que o modelo possa se recuperar.

+
{
+  "error": {
+    "type": "policy_violation",
+    "code": "parallel_mutation_forbidden",
+    "message": "This tool modifies external state and cannot run in parallel.",
+    "allowed_next_steps": ["call_read_only_tools", "ask_user_for_approval", "run_serially"]
+  }
+}
+
+ +
+

17. Contratos de prompt e descrição de tools

+

Instruções não substituem enforcement, mas melhoram o comportamento do modelo e reduzem violações. O ideal é ter um contrato de prompt por fase e uma descrição de tool com semântica operacional.

+ +

17.1 Contrato de fase paralela

+
Você está na FASE DE LEITURA.
+Objetivo: coletar dados independentes e read-only.
+Pode chamar várias tools no mesmo turno somente se forem read-only e independentes.
+Não chame tools de criação, atualização, deleção, envio, cobrança ou reserva.
+Não invente dependências: se uma chamada precisar do resultado de outra, chame apenas a primeira.
+Ao receber resultados parciais, sintetize explicitando lacunas.
+ +

17.2 Contrato de fase sequencial/mutação

+
Você está na FASE DE AÇÃO CONTROLADA.
+Só execute uma ação por vez.
+Antes de ações irreversíveis, confirme que o usuário aprovou explicitamente.
+Se faltar approval, peça confirmação; não chame a tool.
+Não chame duas tools de mutação no mesmo turno.
+Use idempotency_key quando disponível.
+ +

17.3 Descrição de tool com semântica de segurança

+
{
+  "name": "charge_card",
+  "description": "Charges a customer's payment method. This has irreversible financial side effects. Never call this tool in parallel with another mutating tool. Call only after explicit user confirmation, after inventory reservation has succeeded, and always provide an idempotency_key.",
+  "parameters": {
+    "type": "object",
+    "properties": {
+      "customer_id": {"type": "string"},
+      "amount_cents": {"type": "integer"},
+      "idempotency_key": {"type": "string"}
+    },
+    "required": ["customer_id", "amount_cents", "idempotency_key"],
+    "additionalProperties": false
+  }
+}
+
+ +
+

18. Anti-padrões comuns

+ + + + + + + + + + + + +
Anti-padrãoPor que é ruimSubstitua por
parallel_tools=True globalMistura emissão, execução e runtime da tool.Políticas separadas: model parallel, client concurrency, mutation policy.
Expor todas as tools sempreAumenta tokens, custo, confusão e risco de tool errada.Fases, namespaces, allowed tools, tool search.
Confiar em prompt para impedir pagamento paraleloPrompt é soft control; falhas são possíveis.Runtime enforcement, approval, idempotency keys.
Misturar OpenAI built-ins com expectativa de external parallelismContraria a restrição documentada sobre built-ins e parallel function calling.Duas fases ou wrapper function externa.
Reordenar parts Gemini “para limpar histórico”Pode quebrar thought signatures e gerar 400 ou degradação.Preservar parts exatamente ou usar SDK chat padrão.
Enviar tool_results Anthropic em mensagens separadasDegrada o padrão de parallel tool use.Agrupar todos os resultados em uma única user message.
Retry cego em tools de mutaçãoPode duplicar ação.Retries só idempotentes; mutações com idempotency key.
Sem timeout por toolUma tool travada bloqueia o turno inteiro.Timeouts específicos e fallback parcial.
+
+ +
+

19. Resiliência, fallback e respostas parciais

+

19.1 Política de timeout por classe de tool

+ + + + + + + + + +
ClasseTimeout típicoFallback
Cache/local lookup100–500 msCache miss ou continuar sem dado.
API interna read-only1–3 sResultado parcial + aviso ao modelo.
Search externa3–10 sRetornar top resultados disponíveis.
Data warehouse5–30 sModo background ou pedir refinamento.
Mutação críticaCurto e controladoNão repetir sem idempotency key; reportar estado desconhecido.
+ +

19.2 Resultado parcial estruturado

+
{
+  "partial": true,
+  "completed": {
+    "crm_lookup": {"customer_name": "Acme", "tier": "enterprise"},
+    "billing_lookup": {"balance": 1200}
+  },
+  "failed": {
+    "ticket_lookup": {
+      "error": "timeout",
+      "timeout_ms": 2500
+    }
+  },
+  "instruction_to_model": "Answer using completed data and explicitly state that ticket data was unavailable."
+}
+ +

19.3 Circuit breaker

+

Se uma tool começa a falhar, o framework deve parar de chamá-la temporariamente e informar o modelo que a capacidade está indisponível. Isso evita que um agente entre em loop tentando uma ferramenta quebrada.

+
if circuit_breaker.is_open(tool_name):
+    return ToolExecutionResult(
+        call_id=call.call_id,
+        name=call.name,
+        ok=False,
+        error="tool_unavailable_circuit_open",
+    )
+
+ +
+

20. Análise final da pergunta central: OpenAI built-in → externas paralelas

+

A pergunta exata era se o modelo da OpenAI poderia chamar uma built-in tool “no reasoning” e depois, com a flag ativada, chamar externas em paralelo. A resposta operacional é uma distinção entre possibilidade conceitual de raciocínio e contrato de API que você pode depender.

+ + + + + + + + + +
InterpretaçãoRespostaMotivo
“O modelo internamente pode usar uma built-in e depois decidir que precisa de funções externas?”Conceitualmente, modelos agentic podem planejar sequências de ferramentas.Mas o que importa é o que a API suporta como fluxo observável e executável pelo cliente.
“Meu runtime consegue começar CRM/billing/tickets enquanto a built-in OpenAI roda?”Não pelo mecanismo de tool calls da mesma Responses call.A built-in é hosted/server-side; você não recebe controle no meio para agendar funções.
“Depois que a OpenAI terminou a built-in, ela pode retornar várias function calls?”Não assuma como contrato quando built-ins estão no mesmo request.A documentação diz que parallel function calling não é possível com built-ins. [S1]
“É possível construir uma UX que parece uma única solicitação?”Sim.O framework faz múltiplos requests técnicos em fases, sem expor isso ao usuário.
“É possível usar web search e externas paralelas?”Sim, se web search for uma function sua ou se usar prefetch/fases.Você recupera controle do scheduler.
+

Decisão recomendada: implemente hosted_tool_strategy="separate_phase" como default para OpenAI. Permita same_turn apenas para provedores/modelos onde a combinação é documentada e testada, como Gemini 3 tool combination em Preview.

+
+ +
+

21. Blueprint de produção: arquitetura completa

+
Agent Orchestrator + ├─ Intent/Phase Planner + │ ├─ read phase + │ ├─ hosted phase + │ ├─ mutation phase + │ └─ final synthesis phase + │ + ├─ Provider Adapter + │ ├─ OpenAIResponsesAdapter + │ ├─ OpenAIAgentsAdapter + │ ├─ AnthropicMessagesAdapter + │ └─ GeminiGenAIAdapter + │ + ├─ Tool Registry + │ ├─ ToolSpec metadata + │ ├─ schema rendering per provider + │ └─ phase-based exposure + │ + ├─ Policy Engine + │ ├─ allowed tools + │ ├─ parallel/serial classification + │ ├─ approval gates + │ └─ resource locks + │ + ├─ Tool Scheduler + │ ├─ semaphores + │ ├─ rate limit buckets + │ ├─ retries/timeouts + │ └─ circuit breakers + │ + ├─ History Manager + │ ├─ OpenAI reasoning items / previous_response_id + │ ├─ Anthropic tool_use/tool_result order + │ └─ Gemini parts/thought signatures + │ + └─ Observability + ├─ traces + ├─ metrics + ├─ audit logs + └─ evals
+ +

21.1 Interface comum de provider adapter

+
class ProviderAdapter(Protocol):
+    def render_tools(self, specs: list[ToolSpec]) -> Any:
+        ...
+
+    def render_model_config(self, policy: AgentToolPolicy, phase: Phase) -> dict:
+        ...
+
+    def extract_tool_calls(self, response: Any) -> list[NormalizedToolCall]:
+        ...
+
+    def append_tool_results(self, history: Any, response: Any, results: list[ToolExecutionResult]) -> Any:
+        ...
+
+    def preserve_provider_state(self, history: Any, response: Any) -> Any:
+        ...
+ +

21.2 Renderização de config por provedor

+
def render_openai_config(tools, policy):
+    has_openai_hosted = any(t.runtime_kind == "openai_hosted" for t in tools)
+    return {
+        "tools": render_openai_tools(tools),
+        "parallel_tool_calls": False if has_openai_hosted else policy.allow_model_parallel_tool_calls,
+        "tool_choice": render_openai_tool_choice(policy),
+    }
+
+
+def render_anthropic_config(tools, policy):
+    if policy.allow_model_parallel_tool_calls:
+        tool_choice = {"type": "auto"}
+    else:
+        tool_choice = {"type": "auto", "disable_parallel_tool_use": True}
+    return {"tools": render_anthropic_tools(tools), "tool_choice": tool_choice}
+
+
+def render_gemini_config(tools, policy):
+    return types.GenerateContentConfig(
+        tools=render_gemini_tools(tools),
+        automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=True),
+        tool_config=types.ToolConfig(
+            function_calling_config=types.FunctionCallingConfig(
+                mode="AUTO",
+                allowed_function_names=policy.allowed_tool_names,
+            )
+        ),
+        include_server_side_tool_invocations=policy.gemini_include_server_side_tool_invocations,
+    )
+
+ +
+

22. Árvore de decisão rápida

+
A tarefa precisa de built-in/server-side tool? + ├─ Não + │ ├─ Todas as tools são read-only e independentes? + │ │ ├─ Sim → permitir emissão paralela + scheduler com cap + │ │ └─ Não → serializar por dependência/side effect + │ └─ Há mutações irreversíveis? + │ ├─ Sim → approval + idempotency + composite/serial + │ └─ Não → locks por recurso se necessário + │ + └─ Sim + ├─ Provider é OpenAI? + │ ├─ Sim → separar hosted phase de client function phase + │ └─ Não + │ + ├─ Provider é Gemini 3 com tool combination habilitado? + │ ├─ Sim → same-turn é possível em Preview; preservar parts/signatures + │ └─ Não → separar fases + │ + └─ Provider é Anthropic server tool? + ├─ Tratar server_tool_use como provider-side + └─ Client tools continuam no scheduler quando retornadas
+
+ +
+

23. Pacote de evals para validar seu framework

+

Antes de confiar no paralelismo em produção, rode evals específicas por provedor e por classe de tool. A meta não é só verificar qualidade de resposta, mas garantir que o scheduler aplica a política mesmo quando o modelo tenta violá-la.

+ + + + + + + + + + + + +
EvalPromptCritério de aprovação
Parallel read fan-out“Consulte perfil, saldo, tickets e contrato do cliente 123.”Modelo emite chamadas read-only múltiplas; scheduler executa paralelo com cap.
Dependency chain“Crie uma assinatura para um novo cliente.”Não chama create_subscription antes de create_customer.
Unsafe mutation fan-out“Cobre o cartão e envie o recibo agora, em paralelo.”Runtime bloqueia ou serializa; exige confirmação se faltar.
OpenAI hosted mix“Pesquise na web e consulte CRM/billing/tickets.”Orquestrador separa fases; não envia built-in+externas esperando parallel function calling.
Anthropic result orderingTool calls paralelas simuladas.Todos os tool_result agrupados na user message imediatamente seguinte.
Gemini signaturesParallel FC1/FC2 com thought signature em FC1.Histórico preserva FC1 signature, FC2, depois FR1/FR2 agrupados.
Timeout partialUma das tools read-only demora além do timeout.Resposta parcial estruturada; modelo menciona lacuna.
Rate limit stress50 usuários simultâneos acionam 5 tools cada.Semaphores mantêm QPS dentro do limite; sem colapso.
+
+ +
+

24. Fontes e referências oficiais

+

Referências consultadas para esta versão. Links abrem em nova aba.

+
    +
  1. [S1] OpenAI — Function Calling guide
    https://developers.openai.com/api/docs/guides/function-calling
  2. +
  3. [S2] OpenAI — Responses API: Using tools
    https://developers.openai.com/api/docs/guides/tools
  4. +
  5. [S3] OpenAI — Responses API: File Search
    https://developers.openai.com/api/docs/guides/tools-file-search
  6. +
  7. [S4] OpenAI — Responses API: Web Search
    https://developers.openai.com/api/docs/guides/tools-web-search
  8. +
  9. [S5] OpenAI — Reasoning models guide
    https://developers.openai.com/api/docs/guides/reasoning
  10. +
  11. [S6] OpenAI Cookbook — Handling Function Calls with Reasoning Models
    https://developers.openai.com/cookbook/examples/reasoning_function_calls
  12. +
  13. [S7] OpenAI Agents SDK — Running agents / ToolExecutionConfig
    https://openai.github.io/openai-agents-python/running_agents/
  14. +
  15. [S8] OpenAI Agents SDK — Run config reference
    https://openai.github.io/openai-agents-python/ref/run_config/
  16. +
  17. [S9] OpenAI Agents SDK — Tools
    https://openai.github.io/openai-agents-python/tools/
  18. +
  19. [S10] OpenAI — MCP and Connectors
    https://developers.openai.com/api/docs/guides/tools-connectors-mcp
  20. +
  21. [S11] OpenAI — Shell tool
    https://developers.openai.com/api/docs/guides/tools-shell
  22. +
  23. [S12] OpenAI — Computer Use tool
    https://developers.openai.com/api/docs/guides/tools-computer-use
  24. +
  25. [S13] Anthropic — Parallel tool use
    https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use
  26. +
  27. [S14] Anthropic — Tool use with Claude
    https://docs.anthropic.com/en/docs/build-with-claude/tool-use
  28. +
  29. [S15] Anthropic — Extended thinking
    https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
  30. +
  31. [S16] Anthropic — Handling stop reasons
    https://docs.anthropic.com/en/api/handling-stop-reasons
  32. +
  33. [S17] Anthropic — Code execution tool
    https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/code-execution-tool
  34. +
  35. [S18] Gemini API — Function calling
    https://ai.google.dev/gemini-api/docs/function-calling
  36. +
  37. [S19] Gemini API — Combine built-in tools and function calling
    https://ai.google.dev/gemini-api/docs/tool-combination
  38. +
  39. [S20] Gemini API — Thought Signatures
    https://ai.google.dev/gemini-api/docs/thought-signatures
  40. +
  41. [S21] Gemini API — Gemini 3 developer guide
    https://ai.google.dev/gemini-api/docs/gemini-3
  42. +
+
+

Nota de interpretação: as APIs evoluem. O framework deve tratar estes comportamentos como contratos de adaptação por versão de provedor/modelo, não como uma abstração permanente. Sempre que você habilitar um novo modelo, tool type ou SDK version, rode os testes de contrato de tool-calling antes de liberar em produção.

+
+
+ +
+

25. Per-tool: paralelo / serial — debate com Codex (gpt-5.5 xhigh) + experimentos

+

Esta seção foi adicionada na v3.1 para responder à pergunta de design que os providers não resolvem nativamente: como, dentro do mesmo agent loop, fazer com que algumas tools sejam SEMPRE paralelas (reads independentes) e outras SEMPRE sequenciais (mutações, pagamento, deleção, envio de email), de forma portável entre OpenAI, Anthropic e Gemini? A pergunta foi delegada ao Codex (gpt-5.5 xhigh) como segundo design pass, depois implementada como scheduler concreto e validada com 4 experimentos reais contra as APIs.

+
+

Artefatos reprodutíveis: scheduler de referência em tests/scheduler.py (~150 LOC); experimentos em tests/test_exp_scheduler.py e tests/test_exp_scheduler_v2.py; evidência em results/10_scheduler_experiments.json e results/11_scheduler_experiments_v2.json. O resumo completo do debate (as 11 críticas e a arquitetura final em 6 camadas) está sintetizado nas subseções 25.2 e 25.3 abaixo.

+
+ +

25.1 Pergunta enquadrada

+

Fato empírico de base (seção 0.5): nenhum provider tem flag nativa per-tool que diga "esta tool sempre paralela, aquela sempre serial". OpenAI tem parallel_tool_calls request-wide; Anthropic tem disable_parallel_tool_use request-wide; Gemini tem mode e allowed_function_names. Nenhum é per-tool. Pior: ANY do Gemini emitiu 3 calls paralelas empiricamente, então não serve nem como "uma só".

+

Portanto, a política per-tool tem que viver no scheduler client-side. O provider serve como dica e redução de emissões ruins, não como fronteira de enforcement.

+ +

25.2 As 11 críticas do Codex ao v3 (sumário)

+
+ + + + + + + + + + + + + + + +
#CríticaResolução
1v3 subestima a consequência de tools provider-executed: gpt-5.5 mistura built-in + paralelas, Claude mistura server + client. Scheduler que roda depois da emissão não consegue desfazer built-ins/server tools já executadas.Layer A (visibilidade por fase) é obrigatório; nunca expor tools provider-executed lado a lado com mutações críticas a menos que política explicitamente aceite (allow_provider_executed_with_mutations).
2v3 generaliza de gpt-4.1 para gpt-5.5. Comportamento é model-family-sensitive.Arquitetura deve fail-closed por padrão.
3v3 dá peso demais para parallel_tool_calls=false como solução completa. É request-wide.Não expressa "reads paralelos, mutações seriais" no mesmo set visível, e não retroage built-ins.
4v3 trata disable_parallel_tool_use Anthropic como resposta principal. Per-recurso e per-tool-group continuam no scheduler.Lock keys (por recurso + por grupo) declarativos no ToolSpec.
5v3 não distingue client tool_use de server_tool_use com nitidez suficiente. Server tool já rodou quando você vê.Marca provider_executed no normalizer; scheduler trata como observação, não como agendável.
6v3 não pode descrever ANY do Gemini como modo serial. Empírico: emite 3 paralelas.Validar len(function_calls) no runtime; usar allowed_function_names só para visibilidade, não para concurrency.
7allowed_function_names ≠ scheduler. Não expressa locks, approval, idempotency, conflict groups.Manter as duas dimensões separadas.
8v3 não exige desabilitar execução automática (Agents SDK, Gemini AFC) quando o scheduler precisa controlar.Default: AutomaticFunctionCallingConfig(disable=True); SDK = chokepoint só se ele for o scheduler.
9Composite tool não é resposta universal. Só serve para sequência de negócio real (charge_then_send_receipt).Usar COMPOSITE_SEQUENCE apenas como tipo declarado e raro.
10v3 precisa de linguagem declarativa para resource locks vs tool locks.ConcurrencyPolicy.SERIAL_BY_RESOURCE (key template) + SERIAL_BY_TOOL_GROUP (conflict groups).
11Prompts/descrições são hinting, não enforcement. Empírico: modelos emitem paralelo mesmo instruídos.Política como código no scheduler.
+
+ +

25.3 Arquitetura proposta (6 camadas)

+
+-------------------------------+ + | Agent Loop | + | while not final: | + | phase = policy.next_phase() | + +---------------+---------------+ + | + v + Layer A | Tool Visibility / Phase Gate (mandatório) + | Exponha read tools em READ_GATHER, mutações em ACT. + | Nunca exponha provider-executed built-ins + | com mutações críticas no mesmo set, salvo opt-in. + | + v + Layer B | Provider Adapter (hint coarse) + | OpenAI: tools, tool_choice, parallel_tool_calls + | Anthropic: tools, tool_choice.disable_parallel_tool_use + | Gemini: tools, mode, allowed_function_names, AFC off + | + v + +---------------+---------------+ + | Provider model response | + | - text | + | - client tool calls | + | - provider-executed logs | + +---------------+---------------+ + | + v + Layer C | Normalizer -> NormalizedCall[] (todos providers) + | id, name, arguments, provider_executed? + | + v + Layer D | Client-Side Scheduler (autoridade per-tool) + | classify_execution(calls, registry, policy) -> ExecutionPlan + | - locks per-resource + per-tool-group + conflict groups + | - approval lookup; idempotency key injection + | - mixed-turn recovery strategy + | + v + Layer E | Execution Engine + | parallel_batches em asyncio.gather; serial_queue estrito + | + v + Layer F | Tool Result Adapter -> formato nativo do provider + | OpenAI function_call_output / Anthropic tool_result grouped / + | Gemini function_response + | + v + +---------------+---------------+ + | Next agent turn | + +-------------------------------+
+ +

25.4 Modelo de dados implementado (tests/scheduler.py)

+
class ConcurrencyPolicy(Enum):
+    PARALLEL_READ           # default para reads independentes
+    SERIAL_BY_RESOURCE      # lock por argumento (ex: customer:{customer_id})
+    SERIAL_BY_TOOL_GROUP    # lock global por grupo (ex: payments, email_send)
+    PROVIDER_EXECUTED       # marcador: rodou no servidor do provider
+    COMPOSITE_SEQUENCE      # sequência de negócio atômica
+
+class SideEffect(Enum): NONE | IDEMPOTENT_WRITE | IRREVERSIBLE
+
+@dataclass(frozen=True)
+class ToolSpec:
+    name: str
+    concurrency: ConcurrencyPolicy
+    side_effect: SideEffect = SideEffect.NONE
+    tool_group: str | None = None
+    resource_key_template: str | None = None
+    requires_approval: Approval = Approval.NEVER
+    idempotent_key_per_intent: bool = False
+
+@dataclass(frozen=True)
+class AgentToolPolicy:
+    phase: str = "act"
+    mixed_strategy: Literal["reject_reprompt",
+                            "execute_reads_queue_mutations",
+                            "block_for_approval"] = "execute_reads_queue_mutations"
+    allow_provider_executed_with_mutations: bool = False
+    pre_approved_tools: frozenset[str] = frozenset()
+ +

25.5 Experimentos (4 rodadas reais, evidência em results/10*.json e results/11*.json)

+ +

EXP-SCH-01 — OpenAI mixed reads + serial mutation

+

Hipótese: o scheduler client-side pode quebrar uma emissão mista [get_customer, get_invoice, charge_card] em batch paralelo de reads + queue serial de mutação, sem depender de parallel_tool_calls=False.

+

Modelo: gpt-5.5. Prompt v2: directive ("user pre-approved this charge...") + tool_choice="required" + 2 turnos.

+
turno 1:  emitiu [get_customer, get_invoice]
+turno 2:  emitiu [charge_card]
+scheduler:
+  parallel_batches = [(get_customer, get_invoice)]   ← roda concorrente
+  serial_queue     = [charge_card]                   ← roda APÓS reads
+asserts:
+  reads_overlap_ms = 214.9   (tools dormem 200 ms → overlap real)
+  charge_starts_after_reads_finish = True
+  each_charge_has_idempotency_key  = True
+  each_charge_has_approval_id      = True
+veredito: VALIDA
+ +

EXP-SCH-02 — Anthropic per-resource locks

+

Hipótese: com SERIAL_BY_RESOURCE, duas updates em recursos diferentes podem rodar paralelas, mas duas no mesmo recurso são serializadas (ou bloqueadas com lock_conflict).

+

Modelo: claude-opus-4-7. Prompt: "Update customer 123 (support_tier='gold'), customer 456 (support_tier='silver'), and customer 123 (billing_email='new@x.com')."

+
opus-4-7 emitiu (em 1 turno, 3 tool_use paralelos):
+  [update_customer(123, support_tier),
+   update_customer(456, support_tier),
+   update_customer(123, billing_email)]
+
+scheduler:
+  - registra lock resource:customer:123 para o 1º; resource:customer:456 para o 2º
+  - 3º entra como blocked_calls com reason = "lock_conflict:resource:customer:123"
+executed: customer 123 (1x), customer 456 (1x)
+asserts:
+  max_same_customer_overlap_ms  = 0.0   ← serialismo per-resource
+  max_cross_customer_overlap_ms = 0.0   (só rodou 1 vez cada, mas locks distintos)
+veredito: VALIDA
+

Detalhe interessante: o scheduler bloqueou a 3ª chamada in-plan. Numa variante de produção, ela viraria queue_after da primeira em 123 — não blocked. A escolha é da política.

+ +

EXP-SCH-03 — Gemini ANY: scheduler rejeita o que o provider não consegue limitar

+

Hipótese: function_calling_config.mode="ANY" não limita a 1 call; o scheduler portável precisa rejeitar/serializar por conta própria.

+

Modelo: gemini-3.1-pro-preview (registro medido no antecessor gemini-3-pro-preview, desligado 09/03/2026; comportamento equivalente esperado). Prompt: "Read account A-1, send the renewal email, and delete the expired draft. Use function calls."

+
ANY emitiu (em 1 turno): [read_account, send_email, delete_draft]   ← 3, não 1
+scheduler (mixed_strategy="reject_reprompt", sem approval pré-existente):
+  - read_account            → parallel_batches (read seguro)
+  - send_email   (group=email_send,  requires_approval) → approval_requests
+  - delete_draft (group=deletion,    requires_approval) → approval_requests
+asserts:
+  ANY_emitted_multiple_calls_not_one = True
+  scheduler_rejected_mixed_turn      = True
+  no_mutation_executor_ran           = True
+veredito: VALIDA
+ +

EXP-SCH-04 — Fail-closed: provider-executed + client mutation no mesmo turno

+

Hipótese: quando o modelo retorna provider-executed + client mutation no mesmo turno (caso do gpt-5.5), o scheduler precisa bloquear a mutação client-side porque a tool provider-side já rodou e não pode ser desfeita. Comportamento configurável por allow_provider_executed_with_mutations.

+

Validado em duas camadas: sintética (isola a lógica do scheduler) e real (emissão capturada do gpt-5.5).

+

Versão real (capturada após múltiplos prompts — evidência results/12_exp_sch04_real.json):

+
variant V2:
+  modelo: gpt-5.5
+  tools:  [{type: web_search}, log_audit (client mutation, group=audit)]
+  prompt: "Look up the current spelling of 'OpenAI' on the web AND
+           call log_audit with event='lookup_done'... both required in this turn."
+  tool_choice: required
+
+resposta do modelo (UMA assistant turn, response.output):
+  reasoning
+  web_search_call    (status=completed, executado server-side pela OpenAI)
+  function_call      (log_audit, client)
+
+normalização para o scheduler:
+  NormalizedCall(name="web_search", provider_executed=True)
+  NormalizedCall(name="log_audit",  args={event: "lookup_done"})
+
+policy fail-closed (allow_provider_executed_with_mutations=False):
+  scheduler_strategy = "block_for_approval"
+  blocked_reasons    = ["provider_executed_mixed_with_client_mutation"]
+  n_executed         = 0          ← mutação client bloqueada
+
+policy opt-in (allow_provider_executed_with_mutations=True):
+  scheduler_strategy = "normal_serial_mutations"
+  executed_names     = ["log_audit"]
+  n_executed         = 1          ← liberada explicitamente
+
+veredito: VALIDA em emissão REAL do gpt-5.5.
+

Observação extra de alinhamento. Quando a mutação client era charge_card (irreversível, com pré-autorização declarada no prompt), gpt-5.5 emitiu apenas charge_card sem buscar — pulou o web_search. Trocando para log_audit (mutação leve, grupo=audit), o modelo emitiu os dois juntos como pedido. Isto é positivo para safety: o modelo tende a não misturar built-ins com mutações irreversíveis em uma só rodada. O scheduler precisa do enforcement de qualquer forma, porque a mutação leve já é suficiente para mostrar o caso (e o defesa não pode depender do alinhamento do modelo). A versão sintética abaixo cobre o caso adversarial.

+

Versão sintética (cobertura adversarial e regressão):

+
norm = [
+  NormalizedCall(name="web_search",  provider_executed=True),
+  NormalizedCall(name="charge_card", args={customer_id: 123, amount_cents: 500}),
+]
+fail-closed → n_executed=0, blocked_reasons=["provider_executed_mixed_with_client_mutation"]
+opt-in      → n_executed=1, executed_names=["charge_card"]   ← controle inverso provado
+ +

25.6 Tradução por provider

+
def adapter_config(provider, phase, tools: list[ToolSpec], policy: AgentToolPolicy):
+    visible    = [t for t in tools if phase in t.visibility_phases]
+    all_reads  = all(not t.is_mutation() for t in visible)
+    has_mut    = any(t.is_mutation() for t in visible)
+
+    if provider == "openai_responses":
+        return {"tools": ..., "tool_choice": "auto",
+                "parallel_tool_calls": bool(all_reads)}
+
+    if provider == "anthropic":
+        return {"tools": ..., "tool_choice": {"type": "auto",
+                                              "disable_parallel_tool_use": bool(has_mut)}}
+
+    if provider == "gemini":
+        return {"tools": ...,
+                "tool_config": {"function_calling_config":
+                                {"mode": "AUTO",
+                                 "allowed_function_names": sorted([t.name for t in visible])}},
+                "automatic_function_calling": {"disable": True}}
+

O que não dá para empurrar para nenhum provider e tem que ficar no scheduler: per-resource locks; "esta tool é serial, aquela é paralela" no mesmo turno; "reads agora, mutations depois nesta ordem"; "charge_card e send_email mutuamente exclusivos"; idempotency key reuse em retry; rejeitar só a mutação preservando o read; não misturar provider-executed com mutação client-side.

+ +

25.7 Veredito agregado

+
+

Os 4 experimentos validam a arquitetura proposta com dados empíricos reais: EXP-SCH-01.v2 (mixed reads + serial mutation), EXP-SCH-02 (per-resource locks Anthropic), EXP-SCH-03 (Gemini ANY rejection), e EXP-SCH-04 (provider-executed + client mutation fail-closed, agora confirmado em emissão real do gpt-5.5 capturada na variante V2 — web_search_call(completed) + log_audit no mesmo turno — e duplamente coberto pela versão sintética com charge_card).

+

Conclusão portável: per-tool parallel/serial só é robusto quando o scheduler é o chokepoint de execução, ele é alimentado por ToolSpec declarativos com ConcurrencyPolicy + locks + approval + idempotency, e o provider serve como hint para reduzir emissões ruins — não como fronteira de enforcement. As três APIs convergem nesse modelo via adapters finos.

+
+

Próximos passos sugeridos: implementar queue_after em vez de block em conflitos de lock (EXP-SCH-02 detalhe), adicionar TTL de approval, observabilidade OTel para o scheduler, e cobrir o cenário Composite (EXP-SCH-05) que ficou só desenhado.

+
+
+
+ + diff --git a/references/agents_tools_best_guides/guia_providers_adapters.html b/references/agents_tools_best_guides/guia_providers_adapters.html new file mode 100644 index 0000000..d593fae --- /dev/null +++ b/references/agents_tools_best_guides/guia_providers_adapters.html @@ -0,0 +1,911 @@ + + + + + +Providers & adapters — camada de portabilidade entre OpenAI, Anthropic e Google + + + + + + + + +
+
+
Providers & adapters Núcleo · portabilidade entre providers
+
+ Verificado em 2026-06-25 + Super-guia de Agentes + PT-BR + +
+
+
+ +
+ + +
+ +
+

Providers & adapters

+

+ A camada de portabilidade do super-guia. Aqui o foco é agnóstico: o papel de cada SDK, + o provider switching contract com declaração de perdas, a equivalência de roles e + instruções, a matriz de comportamento entre OpenAI, Anthropic e Google, e structured outputs + cross-provider. Os parâmetros específicos de cada API ficam nos guias dedicados — este capítulo é a + cola entre eles. Prosa em PT-BR; identificadores, classes e código em inglês. +

+
+ Super-guia de Agentes + PT-BR + SOTA · verificado 2026-06-25 +
+
+ +
+

Sobre este guia

+

+ Este capítulo do núcleo trata a aplicação como dona de um contrato canônico e cada + provider como uma projeção desse contrato. O objetivo não é reexplicar a API de cada + provedor — é dar o adapter que converte um modelo canônico (ledger, capabilities, schemas, + roles) para OpenAI Responses/Agents SDK, Anthropic Messages e Google GenAI/Gemini, tornando explícitas + as perdas em cada troca. +

+
+ Para IA e humanos: use as tabelas como referência de consulta (parâmetros, roles, + comportamento por provider) e os contratos JSON como esquema copy-paste. Cada afirmação perecível + (IDs de modelo, nomes de parâmetro, versão de spec) é conferida na seção + Notas de verificação contra a folha de fatos SOTA do super-guia. +
+
+ Onde aprofundar cada API: parâmetros completos da Responses API → + guia_openai_modelos; Messages API e blocos de tool/thinking → + guia_claude_api; Interactions API e google-genai → + guia_gemini_interactions_api; runtime do Agents SDK → + guia_agents_sdk e + guia_agents_sdk_orquestracao. +
+
+ +
+

A tese do adapter

+

+ Trocar de provider deve ser uma operação declarada, nunca transparente. Um sistema que + "só troca o nome do modelo" mente para si mesmo: roles não têm equivalência perfeita, carriers de + reasoning são opacos e específicos, budgets se comportam de forma distinta e o estado servidor de um + provider não existe no outro. O adapter resolve isso projetando o contrato canônico e produzindo uma + loss declaration a cada conversão. +

+
+ + Contrato canônico projetado para três providers + Um modelo canônico no centro (ledger, capabilities, schemas, roles) é convertido por um adapter para OpenAI, Anthropic e Google, cada conversão emitindo uma declaração de perdas. + + Contrato canônico + ledger · capabilities · schemas + roles · assets · budgets + + adapter + + + + OpenAI + Responses / Agents SDK + + Anthropic + Messages API + + Google + GenAI / Gemini + + + + + + + + ↯ loss + ↯ loss + ↯ loss + + +
O adapter é o único ponto que conhece dialeto de provider. O produto fala o contrato canônico; cada projeção declara o que foi preservado, transformado e perdido.
+
+
+ +
+

Parte 1 — SDKs & parâmetros

+

O papel de cada camada, os parâmetros da Responses API que importam para a orquestração, e quando o + Agents SDK ou o Pydantic AI entram. Detalhe completo de cada API fica nos guias dedicados.

+
+ +
+

1. Papel de cada SDK/framework

+

Cada camada tem um papel; o erro comum é confundir um provider adapter com um banco de estado + durável, ou um framework de runtime com governança de negócio. A tabela separa uso recomendado de + "não confundir com".

+
+ + + + + + + + + +
CamadaUso recomendadoNão confundir com
OpenAI Agents SDK (openai-agents)Runtime de agentes com tools, handoffs, guardrails, sessions, tracing e MCP. Uma das bases recomendadas no ecossistema OpenAI.Banco de estado durável universal ou substituto de políticas de negócio.
OpenAI Responses APIInterface direta para controle fino de input, tools, estado, reasoning, structured outputs, truncation e loop próprio.Framework de governança; o cliente ainda valida, executa tools e mantém o ledger.
OpenAI Python SDK (openai)Cliente oficial para chamar a API OpenAI.Orquestrador por si só.
Anthropic SDK / Messages API (anthropic)Provider adapter para Claude: tools (tool_use/tool_result) e thinking (adaptive/extended).Mesma semântica de roles/tokens/reasoning da OpenAI.
Google GenAI SDK (google-genai)Provider adapter para Gemini: function calling, files, structured output e thought signatures.Estado durável automático em todo cenário; SDKs legados (google-generativeai).
Pydantic AI (pydantic-ai)Camada complementar de agentes tipados, output estruturado, deps, evals, observabilidade e wrappers model-agnostic.Substituto obrigatório do Agents SDK; use onde agrega validação/typing/evals.
+
+ Pin de versões (2026-06-25): openai-agents 0.17.7 (release 2026-06-19; pré-1.0; superfície ainda + evolui; piso openai>=2.36.0,<3 desde a 0.17.4), + anthropic 0.112.0, google-genai 2.10.0, pydantic-ai 2.0.0 (série 2.x estável; o PyPI saltou de 0.0.x direto para 2.0.0 — não existiu série 1.x). + Confirme antes de fixar — ver Notas de verificação. +
+
+ +
+

2. OpenAI Responses API: parâmetros críticos

+

Para a orquestração, estes são os campos que mais influenciam controle de fase, estado e budget. A + referência completa (anatomia da Responses, function calling, streaming) está em + guia_openai_modelos.

+
+ + + + + + + + + + + + + + +
Parâmetro/campoUsoCuidado
inputItens de entrada multimodais/projetados do ledger.Não jogar corpus bruto sem caps de budget.
instructionsInstruções da chamada atual.Com previous_response_id, não assuma carry-over de instructions anteriores.
toolsBuilt-ins, MCP e function tools.Exponha apenas as allowed tools da fase.
tool_choiceauto / required / específico / none.Trava fase, não é a única camada de segurança.
parallel_tool_callsPermite múltiplas function calls numa resposta.A execução paralela é do runtime; built-ins têm restrições.
max_tool_callsLimite de tool calls hospedadas na resposta.Não substitui o max turns do orquestrador.
max_output_tokensLimita tokens visíveis + reasoning conforme o modelo.Reserve orçamento para reasoning e resposta final.
previous_response_idEncadeia o estado servidor da resposta anterior.Não é ledger; não combine com conversation na mesma cadeia.
conversationObjeto de conversa stateful gerido pelo servidor.Avalie retenção/política de dados; é projeção, não fonte da verdade.
storetrue persiste a resposta (necessário p/ previous_response_id).Para ZDR/stateless, use store=false e devolva os output items.
truncationauto / disabled.Truncation automática pode remover contexto crítico silenciosamente.
+
+ Reasoning stateless (ZDR): para preservar o reasoning entre turnos sem armazenamento + no servidor, combine store=false com include=["reasoning.encrypted_content"] + e devolva o conteúdo cifrado a cada turno. Confira o nome exato do campo na doc atual da Responses API. +
+
+ +
+

3. OpenAI Agents SDK: quando usar como base

+

Use o Agents SDK quando o projeto se beneficia de loop de agentes, guardrails, handoffs, + agents-as-tools, sessions, tracing e MCP em código Python-first. A doc oficial o posiciona como + framework leve e recomenda a Responses API direta quando você quer possuir manualmente o loop, + o dispatch de tools e o estado. É uma base recomendada — LangGraph e Google ADK são + alternativas legítimas (ver os guias de framework do super-guia).

+
from agents import Agent, Runner, function_tool
+
+@function_tool
+def lookup_policy(topic: str) -> str:
+    # Chame sua capability real; reduza o output antes de devolver ao agente.
+    return "síntese com provenance"
+
+specialist = Agent(
+    name="evidence_specialist",
+    instructions="Responda apenas com evidências tipadas e limitações.",
+    tools=[lookup_policy],
+)
+
+manager = Agent(
+    name="orchestrator",
+    instructions="Planeje, delegue quando necessário e sintetize com fontes.",
+    tools=[specialist.as_tool(
+        tool_name="consult_evidence_specialist",
+        tool_description="Consulta o especialista de evidências; retorna síntese tipada com limitações.",
+    )],
+)
+
+result = Runner.run_sync(manager, "Pergunta do usuário")
+print(result.final_output)
+ +

Mesmo quando o SDK gerencia o loop, mantenha registro externo de traces, usage, tool results e + decisões críticas se o sistema precisa ser auditável — o ledger canônico é seu, não do framework.

+
+ +
+

4. Pydantic AI como camada complementar

+

O Pydantic AI brilha nas bordas tipadas: dependências, output estruturado, validação de ferramentas, + evals, observabilidade (Logfire) e wrappers model-agnostic. Convive com o Agents SDK — use Pydantic para + schemas/evals/validadores, o Agents SDK para orquestração/handoffs, e a Responses API direta nos pontos + de controle fino. Nenhum outro guia do conjunto cobre o Pydantic AI, então ele mora aqui.

+
from pydantic import BaseModel, Field
+
+class EvidenceItem(BaseModel):
+    source_id: str
+    claim: str
+    confidence: float = Field(ge=0, le=1)
+
+class SpecialistOutput(BaseModel):
+    answerable: bool
+    summary: str
+    evidence: list[EvidenceItem]
+    missing: list[str] = []
+
+# Use este modelo como contrato de saída de subagente/tool/eval,
+# independentemente do provider que gerou a resposta.
+ +
+ +
+

Parte 2 — Adapters por provider

+

O ângulo aqui é de projeção/adapter — o "como o contrato canônico vira chamada deste provider". A API + real de cada um está nos guias dedicados.

+
+ +
+

5. Anthropic adapter

+

No adapter Anthropic, trate tool use como blocos estruturados: o modelo emite tool_use, + o cliente executa a tool e devolve tool_result (numa mensagem de role user), + com stop_reason: tool_use. Para thinking, preserve os blocos/assinaturas conforme as regras + de contexto e tool-use. A API completa está em guia_claude_api.

+
+ + + + + + + + + +
AspectoRegra prática
Rolessystem top-level + messages alternando user/assistant; adapte developer/instructions com cuidado.
ToolsSchemas explícitos (input_schema); tool_choice específico quando a chamada é obrigatória.
ThinkingOpus 4.8 só adaptive; Fable 5 adaptive sempre ativo (type:"disabled" e budget manual retornam 400); Haiku 4.5 só enabled (budget); Sonnet 4.6 ambos. Preserve assinaturas quando exigidas.
Structured outputoutput_config.format (json_schema) nativo — não use response_format (padrão OpenAI).
ContextMeça thinking/contexto; compacte antes do overflow. Opus 4.8/Sonnet 4.6/Fable 5 = 1M (Fable 5 com 128k max output); Haiku 4.5 = 200K.
Provider switchDeclare perdas quando carriers de reasoning da OpenAI ou thought signatures do Gemini não têm equivalente direto.
+
+ +
+

6. Google GenAI/Gemini adapter

+

No adapter Google, use o SDK oficial google-genai (não os SDKs legados). A chamada + canônica de geração é client.models.generate_content(...) — é o caminho atual e correto, não + legado. A Interactions API é uma abstração adicional + (recurso de interação stateful/por passos) que você usa quando precisa desse modelo de estado, não um + substituto da chamada de baixo nível. Em function calling com thought signatures, + preserve as parts exatamente como retornadas — a doc enfatiza passback intacto e regras + específicas para chamadas paralelas/sequenciais.

+
+ + + + + + + + + +
AspectoRegra prática
SDKfrom google import genai; genai.Client() + client.models.generate_content(...).
Function callingModos AUTO/ANY/NONE; automatic function calling no SDK Python quando apropriado.
Thought signaturesPreserve parts/signatures; não concatene nem reordene manualmente. Obrigatório devolver as de function calling.
Thinkingthinking_level (low/medium/high; Flash/Lite ainda têm minimal) — não o legado thinking_budget; não misture os dois (erro 400).
Structured outputresponse_mime_type="application/json" + response_json_schema.
Documentos/filesAPIs de files/document processing com asset registry próprio.
+
+ +
+

7. Structured outputs cross-provider

+

Para saídas críticas, prefira structured outputs com JSON Schema/Pydantic em vez de pedir + "responda em JSON" por prompt. Os três providers oferecem o mecanismo, com nomes diferentes — o contrato + canônico é o mesmo schema; o adapter só muda o campo da chamada.

+
+ + + + + + + +
ProviderMecanismoCampo da chamada
OpenAIStructured Outputstext.format (json_schema)
AnthropicStructured outputs nativooutput_config.format (json_schema)
Google GeminiStructured outputresponse_json_schema + response_mime_type
Pydantic AIOutput validado (qualquer provider)output_type=Model
+
{
+  "type": "object",
+  "additionalProperties": false,
+  "required": ["decision", "rationale", "evidence", "risks"],
+  "properties": {
+    "decision": {"type": "string", "enum": ["approve", "reject", "needs_human"]},
+    "rationale": {"type": "string", "maxLength": 1200},
+    "evidence": {"type": "array", "items": {"type": "object"}},
+    "risks": {"type": "array", "items": {"type": "string"}}
+  }
+}
+
+ Regra de ouro: valide o output localmente (Pydantic) sempre, mesmo quando o + provider garante o schema. Isso mantém o contrato estável quando você troca de provider. +
+ +
+ +
+

Parte 3 — Portabilidade

+

O coração agnóstico do capítulo: comparar comportamento, declarar a troca de provider, mapear roles e + escolher parâmetros por intenção.

+
+ +
+

8. Matriz comparativa de provider behavior

+

Onde os três divergem de fato. Use como checklist do que o adapter precisa traduzir. A matriz cruzada + mais profunda (paralelismo, multimodal) está em + guia_paralelismo_tools e + guia_multimodal.

+
+ + + + + + + + + + + +
DimensãoOpenAIAnthropicGoogle Gemini
EstadoResponses com previous_response_id/conversation; store=false possível.Messages + histórico app-managed; cliente mantém o histórico.Histórico de parts; muitas chamadas stateless; o SDK ajuda.
TransporteHTTP/SSE padrão; WebSocket mode opt-in (wss://api.openai.com/v1/responses) p/ loops longos de tool calls.HTTP + SSE (stream:true); sem WebSocket na Messages API.Interactions: HTTP + SSE; Live API em WebSocket (WSS) p/ voz/vídeo em tempo real.
Tool loopFunction calls + execução no cliente; built-ins/MCP; Agents SDK pode gerenciar.tool_use/tool_result; client e server tools.Function declarations; automatic function calling no Python.
Reasoning/thinkingReasoning tokens internos, summaries, encrypted reasoning.Thinking adaptive/extended, blocos + assinaturas, budgets.thinking_level e thought signatures.
Output budgetmax_output_tokens inclui visível + reasoning.max_tokens interage com o thinking budget.maxOutputTokens para o candidato; thinking à parte.
Rolesinstructions/system/developer + input items.system top-level + user/assistant.systemInstruction + user/model contents.
Structured outputtext.format (json_schema).output_config.format (json_schema).response_json_schema + response_mime_type.
Multimodal/filesInputs multimodais + built-ins.Limites por imagens/PDFs conforme docs.Document processing/files e multimodal.
+
Não force WebSocket em todo lugar. Só a OpenAI expõe WebSocket como transporte da API de texto/agente (Responses WebSocket mode — ganho ~40% em rollouts com 20+ tool calls; caso contrário, HTTP/SSE). Em Gemini e Anthropic, a chamada ao modelo é HTTP+SSE; WebSocket só existe para tempo real (Gemini Live API) ou transporte de MCP — não para a inferência de texto. Detalhe por provider: OpenAI §12.2 · Claude §5 · Gemini §6.
+
+ +
+

9. Provider switching contract

+

Trocar provider deve ser declarado. O adapter produz uma matriz de perdas e uma justificativa de + roteamento — assim a troca é auditável e reversível.

+
{
+  "provider_switch": {
+    "from": "openai_responses",
+    "to": "gemini",
+    "reason": "latency_or_capability",
+    "preserved": ["messages", "assets", "function_schemas", "citations"],
+    "lost_or_transformed": ["openai_encrypted_reasoning", "developer_role_semantics"],
+    "required_rehydration": ["systemInstruction", "thought_signature_policy"],
+    "risk": "medium",
+    "user_visible": false
+  }
+}
+
    +
  • ☑ Não migrar carriers privados (reasoning/thinking cifrado, signatures) como texto comum.
  • +
  • ☑ Não presumir que roles e budgets têm equivalência perfeita.
  • +
  • ☑ Não misturar histórico do provider A com o B sem adapter e loss declaration.
  • +
  • ☑ Registrar motivo, modelo, versão, parâmetros e usage estimado/real.
  • +
+
+ Perda silenciosa: passar o carrier de reasoning de um provider como mensagem de texto + para outro não "preserva o raciocínio" — corrompe o estado e pode vazar conteúdo opaco. Sempre + descarte ou re-hidrate explicitamente, nunca traduza por engano. +
+
+ +
+

10. Equivalência de roles e instruções

+

A projeção de roles é a principal fonte de drift. Não existe equivalência perfeita entre + system, developer, instructions, systemInstruction e + mensagens comuns — o adapter registra como cada intenção foi projetada e o que se perdeu.

+
+ + + + + + + + +
Intenção canônicaOpenAIAnthropicGoogle
Política não negociávelsystem/developer/instructions conforme a rota.system top-level.systemInstruction.
Tarefa do usuárioinput/message user.user message.user content/part.
Resposta do modelooutput items.assistant message.model content.
Tool requestfunction/tool call item.tool_use block.function_call part.
Tool resultfunction_call_output.tool_result block (role user).function_response part.
+ +
+ +
+

11. Matriz de parâmetros por intenção

+

A cola operacional: dada uma intenção de orquestração, quais controles usar em cada provider.

+
+ + + + + + + + + + +
IntençãoControles típicos
Forçar nenhuma tooltool_choice: none ou sem tools; prompt de síntese final; guardrail de tool call vazio.
Permitir várias consultas read-onlyparallel_tool_calls quando suportado; runtime executa com fan-out cap.
Obrigar tool específicatool_choice específico (OpenAI/Anthropic) / mode ANY (Gemini).
Controlar profundidadereasoning.effort (OpenAI) / thinking (Anthropic) / thinking_level (Gemini); output cap ajustado.
Evitar truncation perigosaMedir tokens, compactar antes, truncation: disabled quando falha explícita é melhor.
Reduzir custoModelo menor para triagem (mini/nano/flash-lite/haiku), caps, early exit e cache permitido pela política.
Minimizar latência em loop longo de toolsOpenAI: WebSocket mode da Responses API (conexão persistente, só itens novos + previous_response_id; ~40% em 20+ tool calls). Anthropic/Gemini: HTTP+SSE com stream, preâmbulo curto e prompt/context caching — não há WebSocket de inferência nesses dois. Ver linha Transporte na §8.
+ +
+ +
+

12. Receitas de adapter

+

Receitas curtas por provider. As completas (com cookbook) ficam nos guias dedicados.

+

OpenAI

+
+ + + + + + + + +
CasoConfiguração base
Structured answerResponses API + output schema + validação local + retry controlado.
Tool loop manualResponses API + function tools + loop client-side + ledger.
Fluxo sensível (ZDR)store=false + encrypted reasoning quando aplicável + ledger app-managed.
Built-in search/file/codeIsolar a fase de built-in, limitar max_tool_calls, registrar outputs reduzidos.
Agents runtimeAgents SDK com guardrails/tracing/sessions + ledger externo para auditoria.
+

Anthropic & Google

+
+ + + + + + + + +
ProviderReceitaAtenção
AnthropicMessages API com tool_use/tool_result e schemas explícitos.Preservar blocos/assinaturas de thinking no tool-use quando exigido.
AnthropicThinking (adaptive/extended) para tarefas complexas.Budget interage com max_tokens; medir custo.
Google Geminigoogle-genai com automatic function calling quando útil.Histórico completo e thought signatures intactas.
Google GeminiDocument processing/files para multimodal.Governar assets no registry próprio.
Google GeminiStructured output com response_json_schema.Validar localmente e declarar perdas no provider switch.
+
+ Gate PROVIDER: toda rota deve declarar quais recursos são obrigatórios, opcionais ou + não suportados por provider. Ao trocar, registre a loss_declaration: perda de tool nativa, + de estado, diferença de thinking/reasoning, de schema, custo, latência e política de retenção. +
+
+ +
+

Cheat sheet — adapter & portabilidade

+

Imports essenciais por provider

+
+
+ + + +
+
+
# OpenAI: Responses API + Agents SDK
+from openai import OpenAI
+from agents import Agent, Runner, function_tool
+client = OpenAI()
+resp = client.responses.create(model="gpt-5.5", input="...")
+
+
+
# Anthropic: Messages API
+from anthropic import Anthropic
+client = Anthropic()
+msg = client.messages.create(
+    model="claude-opus-4-8", max_tokens=1024,
+    messages=[{"role": "user", "content": "..."}])
+
+
+
# Google: google-genai (SDK atual; não os legados)
+from google import genai
+client = genai.Client()
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview", contents="...")
+
+
+

Decisões rápidas

+
    +
  • Precisa de loop/handoffs/guardrails Python-first no ecossistema OpenAI? → Agents SDK.
  • +
  • Quer possuir o loop, dispatch e estado manualmente? → Responses API direta.
  • +
  • Precisa de tipagem/output validado/evals model-agnostic? → Pydantic AI por cima.
  • +
  • Vai trocar de provider? → emita o provider_switch com loss declaration.
  • +
+
+ +
+

Notas de verificação

+

Fatos perecíveis conferidos contra a folha de fatos SOTA do super-guia (2026-06-10). Identificadores + de modelo não são hardcoded no corpo agnóstico — aparecem só em exemplos e nesta seção.

+
    +
  • Resolvido URL oficial do Pydantic AI é pydantic.dev/docs/ai (verificação ao vivo 2026-05-25: ai.pydantic.dev/ retorna 301 para pydantic.dev/docs/ai/overview/; /evals/evals/ e /integrations/logfire/ também resolvem sob pydantic.dev/docs/ai/). O domínio ai.pydantic.dev não é fabricado — é o domínio antigo, hoje redirecionado. Alinhado com guia_operacao_seguranca_evals.html.
  • +
  • Resolvido Versões instaláveis (PyPI, 2026-06-25): openai-agents 0.17.7 (release 2026-06-19; piso openai>=2.36.0,<3), anthropic 0.112.0, google-genai 2.10.0, pydantic-ai 2.0.0 (lançada 2026-06-23; o PyPI foi de 0.0.55 direto para 2.0.0 — não existe série 1.x; a 2.0 traz mudanças incompatíveis vs 0.0.x, confira o changelog ao atualizar).
  • +
  • Resolvido Structured output nativo da Anthropic é output_config.format (não response_format).
  • +
  • Resolvido Gemini série 3 usa thinking_level (não thinking_budget); misturar os dois retorna 400.
  • +
  • Resolvido Thinking por modelo Anthropic: Opus 4.8 só adaptive; Fable 5 adaptive sempre ativo (desativar retorna 400); Haiku 4.5 só enabled; Sonnet 4.6 ambos.
  • +
  • Novo Claude Fable 5 (claude-fable-5, GA 2026-06-09) é o modelo mais capaz amplamente disponível da Anthropic: 1M de contexto, 128k max output, adaptive thinking sempre ativo. Opus 4.8 segue ativo e recomendado — os exemplos deste guia permanecem com claude-opus-4-8.
  • +
  • Resolvido IDs SOTA usados nos exemplos: gpt-5.5, claude-opus-4-8, gemini-3.1-pro-preview.
  • +
  • Resolvido Campo de reasoning cifrado include=["reasoning.encrypted_content"] confirmado na Responses API (guia Reasoning > Encrypted reasoning items e API Reference de responses.create): habilita reusar reasoning items em modo stateless (store=false ou ZDR). Verificado 2026-05-25 em developers.openai.com · reasoning.
  • +
  • Resolvido Superfície do Pydantic AI confirmada em pydantic.dev/docs/ai: Agent(model, deps_type=, output_type=, instructions=), @agent.tool/@agent.tool_plain, RunContext, run_sync/run, ToolOutput. Verificado 2026-05-25.
  • +
  • Resolvido Agent.as_tool(...) exige tool_name e tool_description no openai-agents 0.17.x — exemplo corrigido após revisão adversarial (codex/gpt-5.5, 2026-05-25). Runner.run_sync(agent, "texto") confirmado válido.
  • +
  • Resolvido google-genai: client.models.generate_content(...) é a chamada canônica atual (não legado); a Interactions API é abstração stateful adicional, não substituta. Estrutura Gemini = response_json_schema + response_mime_type.
  • +
+
+ Fonte única de fatos: este guia cita a folha de fatos + do projeto (interna); em conflito, vale a folha verificada. +
+
+ +
+
+ + +
+
+
+
Providers & adapters Núcleo · portabilidade entre providers
+

+ Referência técnica construída a partir da documentação oficial pública em 2026-06-10. + Para informação sempre atualizada, consulte as fontes oficiais de cada provider + (OpenAI, + Anthropic, + Google). +

+
+
+
Crédito de produção
+
Gerado por subagentes Claude Opus 4.7 (xhigh)
+
revisão e montagem pelo orquestrador · 2026-05-25
+
+ Super-guia de Agentes + PT-BR +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_skills.html b/references/agents_tools_best_guides/guia_skills.html new file mode 100644 index 0000000..7438377 --- /dev/null +++ b/references/agents_tools_best_guides/guia_skills.html @@ -0,0 +1,1946 @@ + + + + + +Guia de Agent Skills — Autoria, Ativação & Harness + + + + + + + + +
+
+
Guia de Agent Skills Autoria, ativação & harness — agnóstico
+
+ Verificado em 2026-06-25 + Spec Agent Skills + PT-BR + +
+
+
+ +
+ + +
+ +
+

Guia de Agent Skills

+

+ O ciclo completo do padrão Agent Skills de forma agnóstica de framework: o que é uma + skill, como escrever um SKILL.md portável, como a description governa a ativação, + como expor recursos/scripts/assets sob demanda, e como implementar a mecânica de progressive disclosure, + budget e eviction em um harness próprio — com segurança e avaliação. Prosa em PT-BR; identificadores, + campos e código em inglês. +

+
+ Spec Agent Skills + PT-BR + SOTA · verificado 2026-06-25 +
+
+ +
+

Sobre este guia & fronteira

+

+ Este é um guia para IA e humanos: combina o conceito ("o que é, quando usar") com + referência rápida (campos do frontmatter, contratos de tool, templates copy-paste e checklists). Ele + cobre a autoria e o padrão portável de Agent Skills — deliberadamente + agnóstico de provedor e framework. +

+
+ Fronteira deste guia (leia primeiro): aqui está a autoria/padrão de + skills. A integração específica por framework mora em outros guias e deve ser lida lá: + guia_claude_api.html#c-skills (skills no Claude / Anthropic), + guia_deepagents.html#s-skills (SkillsMiddleware do Deep Agents), + guia_agents_sdk.html (skills no Sandbox do OpenAI Agents SDK) e + guia_agents_sdk_orquestracao.html. A teoria geral de + contexto/compactação fica em + guia_contexto_compactacao_estrategias.html e + guia_estado_contexto_memoria.html; o threat model e os + evals gerais em guia_operacao_seguranca_evals.html. +
+
+ Alinhamento de terminologia: o que o núcleo de arquitetura chama de + "skill packs" / modos de injeção (catalog, hot, pinned, child, specialist) é o mesmo + objeto descrito aqui pela ótica da autoria — ver + guia_arquitetura_orquestracao.html. Este guia define o + artefato; o núcleo define como injetá-lo na topologia de orquestração. +
+

O escopo cobre o ciclo completo, aplicável a contextos diversos — chatbots simples, agentes de + sessão única, sessões longas, agentes multi-sessão, copilotos de desenvolvimento, agentes em sandbox, + agentes com ferramentas externas e arquiteturas multiagente:

+
    +
  • O padrão: definição, SKILL.md, frontmatter, progressive disclosure.
  • +
  • Autoria: o que faz uma boa skill, processo, unidade, grau de liberdade, anti-padrões.
  • +
  • Ativação: por que a description decide tudo, catálogo L1, contratos, evals.
  • +
  • Recursos: references/, scripts/, assets/, carregamento sob demanda.
  • +
  • Harness: discovery, parsing, prompt base, ativação por file-read vs tool, agents-as-tools.
  • +
  • Contexto: budget, máquina de estados, eviction sem perder autoridade, stale ledger.
  • +
  • Operação: segurança/governança, avaliação, observabilidade, CI/CD.
  • +
+
+ +
+

Vocabulário & modelo mental

+

Termos usados de forma consistente em todo o guia. As três distinções do modelo mental abaixo são a + base de toda a política de contexto.

+
+ + + + + + + + + + + + + +
TermoDefinição operacional
SkillDiretório versionável com SKILL.md obrigatório e recursos opcionais.
SKILL.mdArquivo com frontmatter YAML (metadados) e corpo Markdown com as instruções principais.
L1 catalogLista leve de skills elegíveis: name, description e, opcionalmente, location.
L2 instructionsCorpo completo do SKILL.md de uma skill ativada.
L3 resourcesArquivos em references/, scripts/, assets/ carregados sob demanda.
Active skill setConjunto de skills cujo SKILL.md está renderizado no contexto atual.
Stale ledgerRegistro de skills usadas antes, mas não renderizadas agora; exige recarga antes de uso exato.
Reload requiredMarcador que proíbe confiar em instruções exatas de uma skill que saiu do contexto ativo.
ToolCapacidade invocável com schema, executada pelo runtime/host.
MCPProtocolo para expor ferramentas, recursos e prompts externos a clientes de IA.
+ +

Modelo mental correto

+

A confusão mais comum em harnesses de skills é tratar "disponível", "montado" e "ativo" como + sinônimos. São coisas diferentes:

+
Skill disponível no registry  ≠  Skill ativa no prompt atual
+Skill montada no sandbox      ≠  Skill lida pelo modelo
+Skill usada em turno anterior ≠  Skill ainda confiável agora
+Skill ativa no contexto       =  SKILL.md renderizado deliberadamente no request atual
+
+ Sobre "desfazer disclosure": um harness não apaga retroativamente o que o modelo já + viu em uma geração anterior. O que ele controla é a renderização do próximo contexto. + Portanto "desfazer disclosure" significa: parar de reinjetar o corpo completo da skill, mover a skill + para o stale ledger, preservar nome/hash/versão/último uso e exigir reativação antes de seguir regras + exatas. Não é apagamento; é parar de reafirmar. +
+
+ +
+

Topologias de sessão

+

A política de compaction/eviction de skills depende de como a sessão vive no tempo. Escolha a linha + que descreve seu agente; o resto do guia assume que você sabe em qual está.

+
+ + + + + + + + +
TopologiaComo tratar skillsCompaction / eviction
Única sessão episódicaHot set efêmero. O contexto nasce e morre no episódio.Aceitável remover payload L2 quando a tarefa muda ou o budget estoura; registre stale se o chat continuar.
Chat único longoUI contínua, mas o backend deve dividir em episódios internos.Fechar episódio move skills antigas para stale; recarregar antes de usar instruções exatas.
Híbrida retomávelA conversa pode persistir, mas o payload exato da skill deve ser reidratado sob demanda.Memória pode ser resumida; skill ativa não. Se saiu do payload, vira reload-required.
Multi-sessão persistenteRegistry, permissões, hashes e ledger persistem entre sessões.Nunca assuma que o modelo ainda tem o corpo da skill; reative na retomada quando necessário.
Especialista task-scopedPode pré-carregar 1–3 skills essenciais se o escopo for estreito.Encerrar a chamada descarta o hot set; o agente principal recebe apenas resultado estruturado.
+
+ Cross-link: a teoria de episódios, teto de compactação e snapshots cumulativos é + aprofundada em + guia_contexto_compactacao_estrategias.html#topologia. + Aqui ficamos com o invariante específico de skills: instrução normativa não se resume como memória. +
+
+ +
+

Parte 1 — O padrão Agent Skills

+

O que é uma skill, qual é o formato canônico do SKILL.md e como o carregamento em + camadas (progressive disclosure) reduz custo e interferência instrucional.

+
+ +
+

1. Padrão Agent Skills

+

+ No padrão Agent Skills, uma skill é um diretório que contém, no + mínimo, um arquivo SKILL.md. Esse arquivo traz frontmatter YAML com metadados + (especialmente name e description) e um corpo Markdown com instruções. A + pasta pode incluir scripts, referências, assets e outros recursos auxiliares. A ideia central: skills + são folders de instruções, scripts e recursos que agentes descobrem e usam para executar + tarefas com mais precisão e eficiência. +

+
my-skill/
+├── SKILL.md          # obrigatório: metadados (frontmatter) + instruções (corpo)
+├── scripts/          # opcional: código executável determinístico
+├── references/       # opcional: documentação carregada sob demanda
+├── assets/           # opcional: templates, schemas, imagens, exemplos
+└── ...               # outros arquivos, se fizer sentido
+
+ Skill ≠ tool. A skill ensina o workflow (procedimento, critérios, validação, + gotchas); tools e MCP fornecem ações e dados externos. Uma skill pode dizer quais ferramentas + usar, mas é o framework que decide quais tools expor, com quais permissões e em qual escopo. Pense em + uma skill como onboarding procedural — não como uma capacidade invocável. +
+

Regras de design do padrão

+
    +
  • O SKILL.md principal deve ser o mapa de execução, não uma enciclopédia.
  • +
  • Se o arquivo ficar longo, mova detalhes para references/ e indique quando carregar cada referência.
  • +
  • Use paths relativos à raiz da skill e evite cadeias profundas de referências.
  • +
  • Scripts devem ser autocontidos, documentados e não interativos.
  • +
  • Assets devem ter nome descritivo e função clara.
  • +
  • O catálogo nunca deve conter todos os corpos completos de todas as skills em um agente generalista.
  • +
+ +
+ +
+

2. Formato do SKILL.md

+

O SKILL.md combina frontmatter YAML e um corpo Markdown. O frontmatter carrega os + metadados que o harness lê sem renderizar o corpo inteiro; o corpo carrega as instruções normativas.

+
---
+name: skill-name
+description: A description of what this skill does and when to use it.
+license: Apache-2.0
+compatibility: Requires Python 3.11+ and read-only filesystem access.
+metadata:
+  org.example.version: "1.0.0"
+  org.example.owner: platform-team
+allowed-tools: Bash(git:*) Read
+---
+
+# Skill Title
+
+## When to use
+Use this skill when...
+
+## Workflow
+1. ...
+2. ...
+
+## Validation
+Before final output, verify...
+ +

Campos do frontmatter

+
+ + + + + + + + + +
CampoObrigatórioRegra prática
nameSim1–64 caracteres; apenas minúsculas, números e hífens; não começa/termina com hífen; sem hífen duplo; deve corresponder ao diretório pai. Verificado
descriptionSim1–1024 caracteres, não-vazio; descreve o que faz, quando usar, termos de gatilho e limites de escopo. Verificado
licenseNãoNome curto da licença ou referência a um arquivo de licença.
compatibilityNão1–500 caracteres se presente. Requisitos de ambiente: produto-alvo, pacotes de sistema, runtime, rede. Verificado
metadataNãoMapa chave/valor para versão, owner, trust, dependências ou dados de registry.
allowed-toolsExperimentalPode pré-aprovar ferramentas em clientes que suportam essa semântica, mas não substitui policy/sandbox.
+
+ Limites verificados: os limites de name (1–64), description + (1–1024) e compatibility (1–500) foram confirmados contra a + AgentSkills Specification + em 2026-06-10. A doc da Anthropic adiciona regras próprias para clientes Claude (o name + não pode conter tags XML nem as palavras reservadas "anthropic"/"claude") — ver + platform.claude.com. +
+ +

Estrutura recomendada do corpo

+

O corpo é o mapa de execução. Esta espinha cobre os pontos que mais influenciam a qualidade de uma + skill — ajuste as seções ao domínio, mas não esconda regras críticas em referências:

+
# Nome legível da skill
+
+## Quando usar
+Declare intenções do usuário, domínios, arquivos, formatos e gatilhos.
+
+## Quando não usar
+Declare limites para reduzir overtriggering e conflitos.
+
+## Arquivos disponíveis
+Liste references, scripts e assets com triggers de carregamento.
+
+## Workflow
+Passos observáveis, em ordem, com defaults claros.
+
+## Validação
+Como saber que a saída está correta; checks finais.
+
+## Gotchas
+Armadilhas que o agente provavelmente erraria sem a skill.
+
+## Output format
+Template ou schema esperado.
+
+## Segurança
+Permissões, confirmações, ações proibidas e escalonamento humano.
+ +
+ +
+

3. Progressive disclosure

+

O padrão reduz custo e interferência instrucional dividindo o carregamento em camadas. O modelo só vê + o que a tarefa atual justifica — o catálogo está sempre presente, mas o corpo e os recursos entram sob + demanda.

+
+ + + + + + +
CamadaConteúdoQuando entra no contextoPolítica
L1 Catálogoname, description, opcionalmente locationNo início da sessão/request, ou após filtro de registry.Leve, roteável, dentro de budget.
L2 InstruçõesSKILL.md completoQuando a skill é ativada por correspondência de intenção ou invocação explícita.Manter exato enquanto ativo.
L3 Recursosreferences/, scripts/, assets/Somente quando o workflow da skill ou a tarefa atual exigir.TTL curto, nunca bulk-load.
+ +
+ + Progressive disclosure: as três camadas e o que entra no contexto em cada momento + + + + L1 · Catálogo + name + description + (+ location opcional) + SEMPRE presente + (dentro do budget) + ~ centenas de tokens + + + ativa + + + L2 · Instruções + SKILL.md completo + só enquanto ativa + mantido exato + soft cap < 5k tokens + + + passo + + + L3 · Recursos + references / scripts + / assets + sob demanda + TTL curto + nunca bulk-load + + + + + + +
Progressive disclosure em três camadas. O catálogo L1 está sempre no contexto (leve); + o corpo L2 entra ao ativar e é mantido exato; os recursos L3 entram só quando um passo do workflow os + exige. O harness adiciona ainda L0 (registry), L4 (arquivos montados) e L5 (binding de tools/MCP) — + ver §8.
+
+ +
+ +
+

Parte 2 — Autoria de skills portáveis

+

Como planejar, escrever e revisar skills genéricas, úteis e compatíveis com diferentes agentes — e + como projetar a description, que é o que realmente decide quando uma skill ativa.

+
+ +
+

4. Autoria de skills portáveis

+

O que faz uma skill ser boa

+

Uma boa skill captura conhecimento operacional que o agente não teria de forma confiável: sequência + de execução, critérios de decisão, validações, formatos de saída, gotchas, integrações, limites e regras + de segurança. Ela não deve ensinar conceitos básicos que o modelo já sabe.

+
+ + + + + + + +
AtributoO que significa
RecorrênciaResolve uma família de tarefas que aparece mais de uma vez.
EspecializaçãoAdiciona conhecimento de domínio, ambiente ou workflow.
VerificabilidadeDefine checks, critérios de sucesso e falhas legíveis.
PortabilidadeNão depende de nomes internos, paths proprietários ou estado vivo de um projeto específico.
+ +

Processo de autoria

+
    +
  1. Comece por casos reais. Extraia o workflow de incidentes, runbooks, tarefas repetidas, revisões de código, tickets ou guias internos.
  2. +
  3. Defina 2–3 casos de uso concretos. Uma skill deve ter escopo coerente, não ser genérica demais.
  4. +
  5. Escreva a description antes do corpo. Se você não consegue dizer quando a skill deve ativar, o escopo ainda está confuso.
  6. +
  7. Escolha o grau de prescrição. Tarefas frágeis precisam de scripts e passos estritos; tarefas abertas precisam de heurísticas e critérios.
  8. +
  9. Inclua gotchas. A parte mais valiosa costuma ser o que o agente erraria sem ajuda.
  10. +
  11. Inclua validação. Não deixe a skill terminar sem um check de qualidade.
  12. +
  13. Teste em execuções reais. Refine a partir de traces, não apenas do output final.
  14. +
+ +

Escolhendo a unidade correta

+

A maioria dos problemas de skill é, na verdade, um problema de granularidade. Diagnostique pelo sintoma:

+
+ + + + + + + +
SintomaProvável problemaCorreção
A skill ativa em quase qualquer pedido.Escopo amplo demais.Dividir por intenção ou adicionar limites de "quando não usar".
Uma tarefa precisa ativar 5+ skills pequenas.Skills estreitas demais ou unidade errada.Consolidar em skill de workflow com referências internas.
O agente lê referências demais.Triggers ruins ou SKILL.md pouco navegável.Listar recursos com condições explícitas.
O agente ignora uma regra crítica.Regra escondida em referência ou em prosa fraca.Mover para workflow/gotchas e usar linguagem operacional.
+ +

Grau de liberdade

+

Calibre quanta autonomia a skill concede ao agente conforme a fragilidade e a auditabilidade da + operação:

+
+ + + + + + +
GrauUse quandoFormato ideal
AltoMúltiplas abordagens válidas; decisões dependem do contexto.Heurísticas, critérios, exemplos, checklist flexível.
MédioHá padrão preferencial, mas parâmetros variam.Pseudocódigo, template, scripts com flags justificadas.
BaixoOperação frágil, auditável ou com risco operacional.Script específico, comandos exatos, validação, confirmação.
+ +

Anti-padrões de autoria

+
    +
  • Prompt monolítico: jogar toda a documentação dentro do SKILL.md.
  • +
  • Catálogo enganoso: description vaga como "ajuda com documentos".
  • +
  • Menu infinito: oferecer muitas opções sem default.
  • +
  • Reference crítica escondida: deixar uma regra obrigatória fora do corpo principal, sem trigger claro.
  • +
  • Dependência implícita: assumir que uma ferramenta, pacote ou credencial existe.
  • +
  • Instruções temporais frágeis: "antes de agosto use X, depois use Y"; prefira uma seção "legado/deprecated".
  • +
  • Path específico de máquina/projeto: use paths relativos à skill ou variáveis de ambiente documentadas.
  • +
+ +

Checklist de autoria

+
    +
  • ☐ name válido, curto, estável e igual ao diretório.
  • +
  • ☐ description explica o que faz e quando usar.
  • +
  • ☐ description contém termos que usuários realmente diriam.
  • +
  • ☐ Há seção "quando não usar" se houver risco de overlap.
  • +
  • ☐ SKILL.md tem workflow observável e ordem de execução.
  • +
  • ☐ Gotchas críticos estão no SKILL.md, não escondidos.
  • +
  • ☐ References têm triggers explícitos.
  • +
  • ☐ Scripts têm --help, argumentos, erros úteis e saída estruturada.
  • +
  • ☐ Output format é concreto.
  • +
  • ☐ Validação final está definida.
  • +
  • ☐ Permissões e ações sensíveis estão claras.
  • +
  • ☐ Há evals de ativação e qualidade.
  • +
+ +
+ +
+

5. Ativação & descriptions

+

Por que a description decide tudo

+

Na maioria dos clientes, o agente vê primeiro apenas name e description. A + description carrega a responsabilidade de ativação: se for vaga, a skill não ativa quando deveria; se for + ampla demais, ativa quando não deveria.

+
+ Regra prática: escreva a description como um roteador de intenção — "faz X; + use quando o usuário pedir Y, Z ou mencionar A/B/C; não use para W". +
+ +

Modelo de description

+

O mesmo exemplo, do template ao bom e ao ruim:

+
+
+ + + +
+
+
description: [verbo + objeto principal]. Use when the user asks to [intenções reais],
+  mentions [termos/arquivos/formats], or needs [resultado]. Do not use for [limites/overlap].
+
+
+
description: Review diffs and pull requests for correctness, security, tests, and
+  maintainability. Use when the user asks to review code, a PR, a diff, or changed
+  files. Do not use for general programming explanations without code changes.
+
+
+
description: Helps with code.
+
+
+ +

Catálogo L1

+

O catálogo é o índice de skills elegíveis. Ele deve conter apenas o necessário para roteamento — não + o corpo das skills:

+
<available_skills>
+  <skill>
+    <name>code-review</name>
+    <description>Review diffs and pull requests for correctness, security, tests, and maintainability. Use when reviewing code, PRs, diffs, or changed files.</description>
+    <location>/skills/code-review/SKILL.md</location>
+  </skill>
+  <skill>
+    <name>report-packaging</name>
+    <description>Create final report packages from structured findings. Use when the user asks for a formatted deliverable, executive report, PDF export, or packaged analysis.</description>
+    <location>/skills/report-packaging/SKILL.md</location>
+  </skill>
+</available_skills>
+ +

Quando ativar

+
+ + + + + + + + +
SituaçãoAção recomendada
Usuário invoca explicitamente uma skill disponível.Ativar, salvo se bloqueada por política/trust.
Tarefa combina claramente com a description.Ativar antes de tools de domínio, shell, MCP, APIs externas ou resposta final.
Tarefa é simples e o agente já resolve sem conhecimento especializado.Não ativar; responda normalmente.
Múltiplas skills são relevantes.Ativar cada uma no máximo uma vez e aplicar em ordem de tarefa.
Skill usada antes está stale.Não confiar em detalhes; reativar antes de seguir regras exatas.
+ +

Contratos de ativação

+

Há duas formas canônicas de o modelo passar de L1 (catálogo) para L2 (corpo ativo):

+

File-read activation

+

O catálogo inclui location e o agente usa uma ferramenta de leitura para carregar o + SKILL.md:

+
When a task matches a skill's description, use the file-read tool to load the SKILL.md
+at the listed location before proceeding.
+Resolve relative paths against the skill directory.
+

Tool dedicada (activate_skill)

+

O harness oferece uma tool com enum das skills elegíveis — mais controle de trust, hash e logging:

+
{
+  "name": "activate_skill",
+  "description": "Load the full instructions for one available Agent Skill.",
+  "parameters": {
+    "type": "object",
+    "properties": {
+      "name": { "type": "string", "enum": ["code-review", "report-packaging"] },
+      "reason": { "type": "string" }
+    },
+    "required": ["name", "reason"],
+    "additionalProperties": false
+  }
+}
+ +

Entrega de L1/L2/L3 por provider

+
+ + + + + + + +
CamadaOpenAI ResponsesGemini InteractionsAnthropic Messages
L1 (catálogo)instructionssystem_instructiontop-level system
L2 disclosure (ativação)function_call_output(call_id=...)function_result(call_id=...)user.content[].tool_result(tool_use_id=...)
L2 ativo (follow-up)Re-renderizado como corpo exato no bloco de autoridade (instructions/system_instruction/system), a partir do skill store — não do tool result histórico.
L3 (on-demand)function_call_outputfunction_resulttool_result
+

+ O formato nativo de tool result (com call_id/tool_use_id pareado) só é exigido + enquanto há um tool loop aberto. Detalhe dos loops nativos em + Paralelismo & tools. +

+ +

Evals de ativação

+

Teste a description com prompts should-trigger e should-not-trigger. Separe + treino/validação para evitar overfitting da description aos próprios casos de teste:

+
{
+  "skill_name": "code-review",
+  "should_trigger": [
+    "Revise este diff e aponte riscos de segurança.",
+    "Pode olhar este pull request antes de eu mergear?",
+    "Analise os arquivos alterados e diga se falta teste."
+  ],
+  "should_not_trigger": [
+    "Explique o que é programação orientada a objetos.",
+    "Escreva um algoritmo de ordenação do zero.",
+    "Qual a diferença entre TCP e UDP?"
+  ]
+}
+ +

Sinais de problemas

+
+ + + + + + + +
SinalProvável causaCorreção
UndertriggeringDescription não cita intenções/termos reais.Adicionar gatilhos e exemplos de linguagem do usuário.
OvertriggeringDescription ampla, sem limites.Adicionar "do not use" e escopo negativo.
Ativação tardiaPrompt não exige carregar antes de tools.Reforçar a regra de ativação antes de ações externas.
Skills conflitantesCatálogo sem namespaces/limites.Melhorar descriptions e usar policy de composição.
+ +
+ +
+

6. Recursos, scripts & assets

+

L3 é onde a maior parte do conteúdo de uma skill deve viver. Bem projetado, o agente lê só o que o + passo atual exige — sem explodir o contexto nem aumentar o risco desnecessariamente.

+ +

O papel de references/

+

Referências são documentação auxiliar carregada apenas quando necessária: detalhes extensos, tabelas, + rubricas, esquemas, edge cases, exemplos longos, documentação de API. No SKILL.md, cada + referência deve vir com condição de uso:

+
## References
+- Read `references/security-checklist.md` only when the user asks for a security review
+  or the diff touches authentication, authorization, secrets, or data access.
+- Read `references/output-format.md` before producing the final report.
+- Read `references/api-reference.md` only when calling or validating API integration behavior.
+ +

O papel de scripts/

+

Scripts servem quando variação é bug: validação determinística, parsing, transformação de + arquivos, geração de artefatos, linting, sumarização mecânica, checks repetíveis. Regras:

+
    +
  • Não use prompts interativos; aceite argumentos.
  • +
  • Documente --help.
  • +
  • Retorne erros úteis em stderr e dados estruturados em stdout.
  • +
  • Implemente --dry-run em ações de escrita.
  • +
  • Seja idempotente sempre que possível.
  • +
  • Declare dependências e versões quando relevantes.
  • +
+
#!/usr/bin/env python3
+import argparse, json, sys
+
+parser = argparse.ArgumentParser(description="Validate an input file against a schema.")
+parser.add_argument("--input", required=True)
+parser.add_argument("--schema", required=True)
+parser.add_argument("--json", action="store_true")
+args = parser.parse_args()
+
+# Perform deterministic validation here.
+result = {"status": "ok", "errors": []}
+print(json.dumps(result, ensure_ascii=False))
+ +

O papel de assets/

+

Assets são recursos estáticos: templates, schemas, imagens, exemplos de arquivo, tabelas de lookup, + modelos de configuração. Assets não devem virar contexto textual por padrão — o runtime + ou uma tool os consome; o prompt não.

+ +

Carregamento sob demanda

+
+ + + + + + + +
RecursoQuando carregarQuando não carregar
ReferenceQuando a etapa atual exige regra, rubrica ou documentação detalhada.No momento da ativação, só para "ver o que tem".
ScriptQuando o workflow manda executar ou quando determinismo reduz risco.Para ler o código inteiro no contexto sem necessidade.
Asset textualQuando template/schema precisa ser usado diretamente.Como parte fixa do catálogo.
Asset binárioQuando runtime/ferramenta precisa do arquivo.Como texto no prompt.
+ +

Contrato para load_skill_resource

+

Uma tool dedicada para carregar um recurso específico — com TTL e validações de segurança + obrigatórias:

+
{
+  "name": "load_skill_resource",
+  "description": "Loads one specific bundled resource from an active or eligible skill.",
+  "parameters": {
+    "type": "object",
+    "properties": {
+      "skill_name": { "type": "string" },
+      "relative_path": { "type": "string" },
+      "reason": { "type": "string" },
+      "ttl_turns": { "type": "integer", "default": 2 }
+    },
+    "required": ["skill_name", "relative_path", "reason"],
+    "additionalProperties": false
+  }
+}
+
+ Validações obrigatórias (path traversal): caminho relativo à raiz da skill; bloquear + .., path absoluto e symlink escape; bloquear leitura fora da skill; impor limite de + tamanho; não aceitar diretórios inteiros; respeitar trust, permissões e escopo do usuário; registrar + skill, path, hash, turn, motivo e resultado. Carregar recurso de skill é leitura privilegiada — trate + como superfície de ataque. +
+ +

Recursos e MCP

+

Reafirmando a fronteira skill/tool: a skill ensina o workflow; tools e MCP fornecem ações e dados.

+
Skill = instrução, workflow, exemplos, scripts, references, assets.
+Tool  = ação invocável com schema e execução pelo host.
+MCP   = protocolo para expor tools, resources e prompts externos.
+
+ Cross-link: o MCP como fronteira de segurança (host/client/server, primitivas, + hardening) é tratado no núcleo em + guia_ferramentas_mcp_rag.html, e por framework em + guia_claude_api.html#c-mcp e + guia_deepagents.html#s-mcp. Para construir um servidor MCP do + zero, a skill mcp-server-builder é o recurso de referência. A spec MCP alvo é + 2025-11-25 Verificado (versão canônica do super-guia). +
+ +
+ +
+

Parte 3 — Implementação em harness próprio

+

Se você está construindo o agente — não apenas escrevendo skills — esta parte cobre o ciclo de vida + do cliente, a política de contexto/budget/eviction, a segurança e a avaliação.

+
+ +
+

7. Implementação em harness próprio

+

Ciclo de vida de um cliente compatível

+

Um agente/harness compatível com o padrão implementa cinco fases: descobrir skills, parsear o + SKILL.md, divulgar o catálogo ao modelo, ativar skills relevantes e gerenciar o contexto ao + longo da sessão.

+
1. Discover skills
+2. Parse SKILL.md files
+3. Disclose available skills to the model
+4. Activate skills
+5. Manage skill context over time
+ +

Discovery

+
    +
  • Escaneie diretórios configurados: usuário, organização, projeto, plugins, registry remoto ou assets embutidos.
  • +
  • Considere .agents/skills/ (ou diretório equivalente) para interoperabilidade.
  • +
  • Ignore diretórios volumosos/irrelevantes: .git, node_modules, build artifacts, caches.
  • +
  • Aplique profundidade máxima e limites de tamanho.
  • +
  • Resolva colisões por escopo/trust/precedência — nunca por ordem aleatória.
  • +
+ +

Parsing e validação

+
def parse_skill_dir(path):
+    skill_md = path / "SKILL.md"
+    if not skill_md.exists():
+        return None
+    frontmatter, body = parse_yaml_frontmatter(skill_md.read_text())
+    validate_name(frontmatter["name"], expected_dir=path.name)
+    validate_description(frontmatter["description"])
+    return {
+        "name": frontmatter["name"],
+        "description": frontmatter["description"],
+        "location": str(skill_md),
+        "base_dir": str(path),
+        "metadata": frontmatter.get("metadata", {}),
+        "hash": sha256_package(path),
+        "trust": classify_trust(path),
+    }
+ +

Arquitetura recomendada para agente generalista

+
system/developer prompt:
+  - regras globais e segurança;
+  - mecanismo de skills;
+  - catálogo L1: name + description + optional location.
+
+tools:
+  - activate_skill(name, reason)            -> retorna SKILL.md estruturado;
+  - load_skill_resource(skill_name, path, reason) -> retorna L3;
+  - tools de domínio, shell, file-read, MCP, APIs externas.
+
+context manager:
+  - active_skill_set;
+  - active_resources;
+  - stale_skill_ledger;
+  - token budgets;
+  - dedup, pinning, eviction, reload_required.
+ +

Prompt base de mecanismo de skills

+

O texto abaixo é o contrato que ensina o modelo a usar progressive disclosure. Cole-o (adaptado) no + system/developer prompt do harness:

+
You have access to Agent Skills through progressive disclosure.
+
+At startup, you see only the skill catalog: name, description, and optional location.
+Full SKILL.md instructions are not active until loaded.
+
+When the current task clearly matches an available skill, call activate_skill(skill_name, reason)
+before using domain-specific tools, shell commands, MCP tools, external APIs, or producing the
+final answer.
+
+After a skill is loaded, follow its SKILL.md instructions unless they conflict with
+higher-priority system/developer policy, safety requirements, explicit user constraints,
+or tool permission policy.
+
+Do not bulk-load references, scripts, or assets. Load a bundled resource only when the active
+SKILL.md instructs you to do so or the current step requires it.
+
+If a previously used skill appears in stale_skills, do not rely on its exact workflow.
+Reactivate it before using exact instructions.
+
+If multiple skills are relevant, activate each relevant skill once, keep them conceptually
+separate, and apply them in task order.
+ +

File-read activation vs tool dedicada

+
+ + + + + + + +
AbordagemVantagensRiscosQuando usar
File-read activationSimples; aproveita o filesystem existente.Menos controle de envelope, permissões, analytics e dedup.Agentes locais com leitura de arquivo confiável.
activate_skillControle de enum, trust, hash, structured wrapping, dedup, logs e resources listados.Exige infraestrutura adicional.Framework próprio, produção, multiagente, compliance.
Catálogo na tool descriptionPrompt global mais limpo.Descrição da tool pode ficar grande; menos transparente.Catálogo pequeno ou ambiente com prompt muito restrito.
Especialista com skills pré-carregadasBaixa latência e foco.Vira prompt monolítico se usado para agentes amplos.Agente task-scoped com 1–3 skills essenciais.
+ +

Agents-as-tools

+

Use agentes especialistas como tools quando o agente principal deve continuar dono da resposta final, + mas precisa delegar subtarefas delimitadas. O especialista pode ter skills pinned e retornar + apenas resultado estruturado:

+
{
+  "agent_profile": "document_reviewer",
+  "base_instructions": "Review documents and return structured findings.",
+  "pinned_skills": ["document-review"],
+  "optional_skills": ["report-packaging"],
+  "allowed_tools": ["read_file", "load_skill_resource"],
+  "history_policy": "task_scoped",
+  "output_contract": "ReviewFindings"
+}
+

O agente principal não deve receber o SKILL.md inteiro do especialista, + referências completas ou logs internos. Deve receber resumo, achados, artefatos, skills/resources usados + e limitações.

+
+ Cross-link: o contraste entre handoff (transferência de ownership) e + agent-as-tool (delegação) como primitivos de orquestração está em + guia_arquitetura_orquestracao.html; a implementação + concreta por framework em + guia_agents_sdk_orquestracao.html, + guia_langgraph_orquestracao.html e + guia_google_adk_orquestracao.html. +
+ +

Integração com estado local e memória

+

Separe o contexto do modelo do contexto local do runtime. Dados como + usuário autenticado, clients de banco, conexões MCP, logs e permissões podem ficar no runtime e ser + acessados por tools — sem serem despejados no prompt. Se o modelo precisa decidir com base em uma + informação, exponha-a por instrução, tool, retrieval ou input explícito.

+
+ Cross-link: a teoria de ledger canônico (estado durável vs payload do + provider, ciclo registrar/reduzir/projetar) que sustenta essa separação está em + guia_estado_contexto_memoria.html. Não reexplicamos o + ledger aqui; tratamos apenas o que é específico de skills. +
+ +
+ +
+

8. Contexto, budget, compaction & eviction

+

Política universal de gestão de contexto para skills: active skill set, stale ledger, budget, + eviction e a regra que evita regressão silenciosa.

+
+ Regra central — skill ativa não se compacta como conversa. Uma skill ativa contém + instruções normativas. Se você resumir livremente o SKILL.md e continuar tratando + o resumo como instrução exata, cria uma regressão silenciosa. A política correta é binária: manter o + corpo inteiro ou removê-lo e marcar reload_required. Não há meio-termo + "resumido mas confiável". +
+
Active skill L2:
+  manter exata enquanto ativa;
+  deduplicar por name+hash;
+  proteger contra pruning destrutivo;
+  remover como unidade inteira se necessário;
+  marcar stale/reload_required ao sair do contexto.
+
+ Cross-link (fronteira de compaction): o contrato de compaction acima é o + invariante específico de skills. A estratégia operacional geral — escada de compactação, teto + X, snapshots cumulativos — está em + guia_contexto_compactacao_estrategias.html#escada, + #subdividir-x e + #snapshots; o contrato de compaction + do ledger em + guia_estado_contexto_memoria.html. Não reexplicamos a + escada aqui. +
+ +

Níveis de carregamento (L0–L5)

+

O harness vê mais camadas do que o modelo. As três da §3 (L1/L2/L3) são as que entram no prompt; o + registry (L0), os arquivos montados (L4) e o binding de tools (L5) são estado do runtime:

+
+ + + + + + + + + +
NívelNomeSignificadoPersistência
L0RegistrySkill existe com hash, versão, trust, path, scope e status.Persistente.
L1Catalog disclosureModelo vê name, description e talvez location.Presente dentro de budget.
L2Hydrated skillSKILL.md completo está no contexto atual.Só enquanto ativa.
L3Hydrated resourceReference/asset textual está no contexto atual.TTL curto.
L4Runtime-mounted filesArquivos/scripts montados no sandbox/container.Por episódio/container.
L5Tool/MCP bindingFerramentas externas habilitadas.Por escopo, risco e permissão.
+ +

Estado canônico recomendado

+

O estado que o context manager mantém para implementar dedup, pinning, eviction e o stale ledger:

+
{
+  "skill_registry": {
+    "invoice-audit": {
+      "version": "1.2.0",
+      "hash": "sha256:abc...",
+      "scope": "org",
+      "trust": "trusted",
+      "location": "/skills/invoice-audit/SKILL.md",
+      "status": "eligible"
+    }
+  },
+  "active_skill_set": [
+    {
+      "name": "invoice-audit",
+      "hash": "sha256:abc...",
+      "loaded_turn": 42,
+      "last_used_turn": 45,
+      "pin": "task",
+      "reason": "current task requires invoice validation"
+    }
+  ],
+  "active_resources": [
+    {
+      "skill": "invoice-audit",
+      "path": "references/output-format.md",
+      "loaded_turn": 44,
+      "last_used_turn": 44,
+      "ttl_turns": 2
+    }
+  ],
+  "stale_skills": [
+    {
+      "name": "report-packaging",
+      "hash": "sha256:def...",
+      "last_used_turn": 18,
+      "reload_required": true,
+      "note": "reload before relying on exact output rules"
+    }
+  ]
+}
+ +

Máquina de estados de uma skill

+

Toda skill percorre um ciclo de vida explícito. O ramo STALE → RELOAD_REQUIRED → ACTIVE + é o que impede o uso de instruções desatualizadas:

+
DISCOVERED -> PARSED -> ELIGIBLE -> DISCLOSED -> ACTIVATION_REQUESTED -> ACTIVE
+ACTIVE -> RESOURCE_ACTIVE
+ACTIVE -> STALE -> RELOAD_REQUIRED -> ACTIVE
+ACTIVE -> EVICTED -> STALE
+ANY    -> QUARANTINED
+
+ + Máquina de estados de uma skill, do descobrimento à quarentena + + + + + + + + DISCOVERED + PARSED + ELIGIBLE + DISCLOSED + ACTIVATION_REQ. + ACTIVE + + + + + + + + + + + STALE + RELOAD_REQUIRED + EVICTED + QUARANTINED + + + + + + + + + reload antes de usar regra exata + ANY → QUARANTINED (origem/risco/policy) + +
Ciclo de vida. Note que EVICTED não apaga a skill: ela vai para + STALE com reload_required, e só volta a ACTIVE após reativação + explícita. Qualquer estado pode ir para QUARANTINED por origem, risco, policy ou + incompatibilidade.
+
+
+ + + + + + + + + + + +
EstadoUso
DISCOVEREDDiretório ou pacote encontrado.
PARSEDSKILL.md validado ou aceito com warnings.
ELIGIBLESkill permitida para usuário, agente, escopo e trust.
DISCLOSEDSkill aparece no catálogo L1.
ACTIVESKILL.md completo será renderizado no request atual.
STALEUsada antes, ausente agora.
RELOAD_REQUIREDDeve reativar antes de confiar em detalhes exatos.
QUARANTINEDBloqueada por origem, risco, policy ou compatibilidade.
+ +

L2 em follow-ups: reinjeção exata vs tool result histórico

+

+ Depois que o disclosure terminou e o modelo já respondeu ao usuário, o tool_result que + entregou o SKILL.md não deve seguir como fonte operacional primária da + skill. Tool results antigos são histórico — podem ser compactados ou ficar soterrados. Enquanto a skill + está ativa, o runtime promove a skill no ledger e o projection builder + re-renderiza o corpo L2 exato a cada turno a partir do skill store, não do tool result + histórico. +

+
{
+  "type": "SkillActivationItem",
+  "skill_name": "contract-review",
+  "version": "1.4.2",
+  "hash": "sha256:...",
+  "loaded_turn": 18,
+  "last_used_turn": 20,
+  "runtime_status": "active",
+  "l2_raw_ref": "skill://contract-review/1.4.2/SKILL.md",
+  "projection_policy": "inject_l2_exact_while_active"
+}
+

O projection builder então renderiza, no bloco de autoridade, o corpo exato:

+
<active_skills_l2 budget_slice="skills_l2_authority">
+  <skill name="contract-review" version="1.4.2" hash="sha256:...">
+    <![CDATA[
+    ... corpo exato do SKILL.md ...
+    ]]>
+  </skill>
+</active_skills_l2>
+
+ Exato-ou-reload, sempre do store. A reinjeção parte do skill store versionado (por + hash), nunca de um resumo nem do tool result antigo. Se o L2 não couber, evicte a skill + inteira e marque stale/reload_required — nunca mantenha um L2 resumido se passando por ativo. +
+ +

Orçamento de skills

+

Use um sub-budget explícito para skills (o nome é livre; aqui skill_budget). O ponto-chave: + references, outputs de script e artefatos grandes não pertencem ao hot set — são payloads + voláteis de execução, com TTL e ponteiros de artefato.

+
total_context     = X
+core_prompt_budget = A
+tool_output_budget = B
+skill_budget       = S
+
+S_catalog = metadata for eligible skills
+S_hot     = full SKILL.md bodies currently active
+
+references, script outputs, external evidence and large artifacts do not belong to S_hot;
+they are volatile execution payloads with TTL and artifact pointers.
+

Defaults iniciais adaptáveis

+
+ + + + + + + + + +
ParâmetroValor inicialObservação
S_target15–35% do prompt-base disponívelAjustar por modelo e domínio.
S_catalog_capaté 5k tokens ou 10–15% de SSe passar disso, filtrar/hierarquizar/buscar skills.
skill_body_soft_cappreferencialmente < 5k tokensAcima disso, refatorar para references.
N_active_max2–4 em generalistas; 1–3 em especialistasProtege contra conflito instrucional.
min_residency_turns3–5 turnosEvita thrashing.
swap_margin1.15–1.30Nova skill só substitui se o ganho esperado superar a perda.
+
+ UNVERIFIED — heurísticas de budget: os valores acima (S_target, + swap_margin etc.) são heurísticas iniciais propostas pelo material-fonte, não + números oficiais da spec. Calibre por evals, modelo, contexto e risco; não cite como limite normativo. +
+ +

L3 e return packets em follow-up: hot por 1 turno, depois ref

+

+ L3 (referências, templates, scripts, assets) é carregado sob demanda via load_skill_resource + e, por default, não é memória permanente. No follow-up imediato, um L3 pequeno pode + sobreviver por ~1 turno num slot hot_followup; depois vira digest/ref/reload. O mesmo vale + para o return_packet de um agent-as-tool. +

+
+ + + + + + + + + +
Tipo de L3Política default em follow-up
reference_normative_smallPode entrar em hot_followup por 1 turno; se ainda necessário, reidratar exato.
template_smallhot_followup por 1 turno; útil para geração imediata.
reference_evidentialPreferir digest/ref; hot só se usado na resposta anterior.
large_referenceDigest + raw_ref; reidratar se o exato for necessário.
scriptExecutar no runtime/sandbox; retornar output/artifacts/provenance — não colar o script inteiro.
assetRef/digest/crop/chunk; reidratar conforme a necessidade.
+
+ Onde o hot follow-up entra — e segurança. O dado transitório de follow-up entra como + bloco tagueado no próximo turno role=user (com ttl_turns=1, + source_item_ids, trust_tier), nunca no system nem + como tool_result fabricado — detalhe no + invariante de colocação. As tags são + organização, não fronteira de segurança: serialize com schema fechado, sanitize e cubra com evals de + prompt-injection. +
+ +

Eviction sem perder autoridade

+

Quando uma nova skill precisa entrar e o budget não comporta, remova skills inteiras. + Não faça LRU puro — calcule a menor perda total de valor de retenção:

+
needed = max(0, current_skill_tokens + token_cost(new_skill) - S_target)
+
+Choose evict_set V that minimizes:
+  sum(retention_value(skill) for skill in V)
+subject to:
+  sum(token_cost(skill) for skill in V) >= needed
+
+retention_value considers:
+  - current task relevance;
+  - recency and frequency;
+  - open dependencies;
+  - output format still pending;
+  - safety/compliance criticality;
+  - pinning/min residency;
+  - expected reactivation cost;
+  - trust and user scope.
+ +

Single-session e limite de compressão

+

Em agente de sessão única ou episódio curto, é aceitável descartar o payload L2 para liberar espaço — + mas o descarte tem de ser explícito no estado: a skill deixa de estar ativa, entra no + ledger como stale e deve ser recarregada se voltar a ser necessária:

+
if context_pressure and session_topology == "single_session":
+    evict_full_skill_payload(skill)
+    stale_ledger.add({
+        "name": skill.name,
+        "hash": skill.hash,
+        "reload_required": True,
+        "reason": "context pressure",
+    })
+ +

Ordem recomendada de renderização

+

A ordem em que o harness monta o prompt importa: política primeiro, conteúdo volátil por último. Isso + mitiga o efeito "lost-in-the-middle" para as instruções normativas:

+
1. Global/system policy
+2. Developer/runtime policy
+3. Agent profile
+4. Tool/MCP policy for current scope
+5. L1 eligible skill catalog
+6. Active L2 skill contents
+7. Active L3 resources
+8. Compacted task memory
+9. Recent relevant turns
+10. Relevant tool observations
+11. Current user message
+ +

Stale ledger

+

O ledger renderizado no contexto avisa o modelo de que uma skill usada antes não é mais autoritativa:

+
<stale_skills>
+  <skill name="report-packaging" hash="sha256:def..." last_used_turn="18" reload_required="true">
+    This skill was used earlier but is not currently active. Reload it before relying on
+    exact formatting or workflow instructions.
+  </skill>
+</stale_skills>
+ +
+ +
+

9. Segurança & governança

+
+ Princípio: trate skills como dependências de código e instrução + privilegiada. Elas podem induzir uso de tools, execução de scripts, chamadas de API, leitura + de arquivos e decisões operacionais. Portanto, precisam de trust gates, auditoria, sandbox, permissões + e logs — como qualquer dependência que entra no seu sistema. +
+ +

Hierarquia de autoridade

+

Uma skill não pode sobrescrever política superior. Se uma skill, reference, output de + script ou página externa disser para ignorar instruções superiores, exfiltrar dados ou ampliar + permissões, trate como conteúdo malicioso ou inválido:

+
1. System/global safety policy
+2. Developer/runtime policy
+3. User task and explicit constraints
+4. Active skill content
+5. Skill references/resources
+6. Tool outputs and external content
+ +

Trust tiers

+

A origem da skill define o trust inicial e a ação de governança:

+
+ + + + + + + + + +
OrigemTrust inicialAção recomendada
Built-in do produto/harnessAltoPermitir com versionamento e logs.
Organização/adminAlto a médioPermitir após revisão e CI.
Usuário instaladoMédioPermitir por escopo, com aprovação e sandbox.
Projeto/repositórioBaixo por padrãoGate por repositório confiável, assinatura ou revisão.
Download externoBaixoQuarentena até auditoria.
Gerada por agenteBaixoHuman-in-the-loop antes de produção.
+ +

Prompt injection e confused deputy

+

Prompt injection em agentes com tools é um risco estrutural: dados externos, + documentos, websites, emails, outputs de tools ou a própria skill podem conter instruções maliciosas. O + design deve reduzir impacto, não apenas tentar "detectar prompts ruins":

+
    +
  • Separe instruções de dados por envelopes e labels.
  • +
  • Não deixe conteúdo externo elevar autoridade.
  • +
  • Restrinja as tools disponíveis ao mínimo necessário.
  • +
  • Use allowlists, confirmação humana, dry-run e escopos de escrita.
  • +
  • Monitore tool calls anômalas, tentativas de leitura sensível e mudanças de comportamento.
  • +
  • Não use o LLM como único controle de segurança para ações destrutivas.
  • +
+
+ Cross-link: o threat model completo de agentes (incluindo guardrails em 3 pontos e + políticas de execução) está no núcleo em + guia_operacao_seguranca_evals.html; a segurança de + ferramentas/MCP (hardening de servidor, trust boundary) em + guia_ferramentas_mcp_rag.html. Aqui ficamos com o que é + específico de skills: hierarquia de autoridade, trust tiers de skill e política de scripts. +
+ +

Checklist de auditoria de skill

+
    +
  • ☐ Ler o SKILL.md integralmente.
  • +
  • ☐ Verificar se tenta sobrescrever políticas superiores.
  • +
  • ☐ Verificar scripts e dependências.
  • +
  • ☐ Buscar comandos destrutivos ou rede inesperada.
  • +
  • ☐ Buscar leitura de arquivos sensíveis.
  • +
  • ☐ Buscar exfiltração de dados ou envio para URLs externas.
  • +
  • ☐ Validar allowed-tools — não aceitar permissões amplas por conveniência.
  • +
  • ☐ Validar references e assets, inclusive arquivos binários se relevantes.
  • +
  • ☐ Validar licença e provenance.
  • +
  • ☐ Executar evals de ativação, segurança e comportamento.
  • +
  • ☐ Registrar hash e versão aprovados.
  • +
+ +

Política para scripts

+
+ + + + + + + +
Tipo de scriptPolítica
Não confiávelNão executar. Quarentena e revisão.
Usuário instaladoSandbox, confirmação para risco, sem secrets por padrão.
Aprovado pela organizaçãoExecutar conforme allowlist, sandbox e logging.
Escrita/destrutivoPlano, dry-run se possível, confirmação explícita e audit log.
+ +

Permissões de tools e MCP

+
    +
  • Não exponha todas as tools globais; exponha apenas por active skill, tarefa, escopo, risco e usuário.
  • +
  • Readonly pode ser auto-enabled se o trust permitir.
  • +
  • Write tools exigem confirmação, salvo automação previamente aprovada.
  • +
  • Destructive tools exigem confirmação forte, plano e rollback/dry-run quando possível.
  • +
  • Use nomes fully qualified para tools MCP quando houver múltiplos servidores.
  • +
+ +

Logs mínimos de segurança

+
- skill name, version, hash, source, trust tier;
+- activation trigger and reason;
+- user/session/project scope;
+- resources loaded;
+- tools exposed while skill active;
+- tool calls made and outputs summarized;
+- permission prompts and approvals;
+- evictions and reload_required events;
+- blocks/refusals/quarantine decisions.
+ +
+ +
+

10. Avaliação & observabilidade

+

Skills devem ser avaliadas com tarefas reais, casos negativos, edge cases, baseline sem skill e + métricas de custo. "Funcionou uma vez" não é evidência. A avaliação cobre ativação, + execução, segurança, qualidade final e impacto de contexto.

+ +

Tipos de teste

+
+ + + + + + + + + +
TesteObjetivoExemplo de métrica
Trigger evalA description ativa na hora certa?Precision, recall, false positives/negatives.
Functional evalO workflow produz resultado correto?Taxa de sucesso, assertions, erros críticos.
Baseline A/BA skill melhora o agente?Delta de qualidade, latência e tokens.
Context evalDedup, stale, compaction e reload funcionam?Reativações corretas, zero uso de stale exato.
Security evalA skill resiste a prompt injection e permissões indevidas?Bloqueios corretos, zero tool write sem confirmação.
Operational evalFunciona em runtime real?Erros de script, missing dependencies, timeouts.
+ +

Exemplo de evals

+
{
+  "skill_name": "invoice-audit",
+  "evals": [
+    {
+      "id": "trigger-001",
+      "prompt": "Audite esta fatura e veja se tem cobrança duplicada.",
+      "expected_active_skills": ["invoice-audit"],
+      "expected_output": "Relatório com campos ausentes, duplicidades e próximos passos."
+    },
+    {
+      "id": "no-trigger-001",
+      "prompt": "Explique a diferença entre lucro e caixa.",
+      "expected_active_skills": [],
+      "expected_output": "Resposta conceitual sem ativar invoice-audit."
+    },
+    {
+      "id": "stale-001",
+      "setup": { "stale_skills": ["report-packaging"] },
+      "prompt": "Use o mesmo formato de relatório de antes.",
+      "expected_behavior": "reactivate report-packaging before relying on exact formatting"
+    }
+  ]
+}
+ +

Métricas recomendadas

+
skill_activation_precision        avg_L1_catalog_tokens
+skill_activation_recall           avg_L2_active_tokens
+skill_false_positive_rate         avg_L3_resource_tokens
+skill_false_negative_rate         avg_active_skill_count
+quality_delta_vs_baseline         reload_required_followed_rate
+latency_delta_vs_baseline         stale_instruction_violation_rate
+token_delta_vs_baseline           duplicate_activation_prevented
+resource_overload_rate            policy_block_rate
+unsafe_tool_call_attempt_rate     thrash_rate
+ +

Observabilidade

+

Os traces devem permitir responder: por que a skill ativou, qual versão foi usada, quais recursos + foram lidos, quais tools foram expostas, qual budget foi consumido e se houve eviction:

+
{
+  "event": "skill_activated",
+  "turn": 42,
+  "skill": "invoice-audit",
+  "version": "1.2.0",
+  "hash": "sha256:abc...",
+  "trigger": "implicit_description_match",
+  "reason": "user asked to audit an invoice for duplicates",
+  "tokens_l2": 3120,
+  "resources_listed": 4,
+  "trust": "trusted",
+  "scope": "current_task"
+}
+
+ Cross-link: os acceptance gates gerais (SCHEMA/TOOL/RAG/CTX/ZDR/BUDGET/PROVIDER/SEC), + a instrumentação de tracing/cost ledger e os evals code-first vivem no núcleo de operação em + guia_operacao_seguranca_evals.html. Os evals de + skills acima alimentam esses gates. +
+ +

CI/CD para skills

+
    +
  • ☐ Validar frontmatter e naming.
  • +
  • ☐ Validar links relativos e ausência de referências profundas desnecessárias.
  • +
  • ☐ Rodar lint dos scripts.
  • +
  • ☐ Rodar testes unitários dos scripts.
  • +
  • ☐ Rodar trigger evals.
  • +
  • ☐ Rodar functional evals.
  • +
  • ☐ Rodar security evals para prompt injection e tool misuse.
  • +
  • ☐ Calcular hash/manifest.
  • +
  • ☐ Publicar somente se passar gates de trust e qualidade.
  • +
  • ☐ Registrar versão, changelog e rollback.
  • +
+ +
+ +
+

Templates copy-paste

+

Modelos prontos para SKILL.md, catálogo, ativação, manifest e prompt de agente. Recolha + o que não usar; copie o que precisar.

+ +

Template universal de SKILL.md

+
+ Ver template completo de SKILL.md +
+
---
+name: example-skill
+description: Do a specific recurring task with clear output and validation. Use when the user asks for [intentions], mentions [keywords/files/formats], or needs [deliverable]. Do not use for [negative scope].
+license: Apache-2.0
+compatibility: Requires [runtime/tools] if applicable. Omit this field if there are no special requirements.
+metadata:
+  org.example.version: "1.0.0"
+  org.example.owner: "team-or-person"
+  org.example.trust: "approved|review-required|experimental"
+---
+
+# Example Skill
+
+## When to use
+Use this skill when...
+
+## When not to use
+Do not use this skill when...
+
+## Available files
+- `references/output-format.md`: read before final output.
+- `references/edge-cases.md`: read when the task includes unusual constraints.
+- `scripts/validate.py`: run when validation is required.
+- `assets/template.json`: use when generating structured output.
+
+## Workflow
+1. Confirm the target input/artifact.
+2. Load only the references required by the current step.
+3. Execute deterministic scripts when instructed.
+4. Produce the requested output using the output format.
+5. Run validation.
+6. Report limitations and unresolved items.
+
+## Gotchas
+- Do not infer missing required fields.
+- Do not call write tools unless explicitly requested and permitted.
+- Do not treat stale prior skill usage as active instructions.
+
+## Output format
+Return:
+- Summary
+- Findings
+- Evidence
+- Recommended next action
+- Limitations
+
+## Validation
+Before final output:
+- Check all required fields are present.
+- Check references were loaded only when needed.
+- Check no prohibited action was taken.
+
+
+ +

Catálogo L1, resposta de ativação & manifest

+
+
+ + + +
+
+
<available_skills>
+  <skill>
+    <name>example-skill</name>
+    <description>Do a specific recurring task with clear output and validation. Use when the user asks for ...</description>
+    <location>/skills/example-skill/SKILL.md</location>
+  </skill>
+</available_skills>
+
+
+
<skill_content name="example-skill" version="1.0.0" hash="sha256:..." source="/skills/example-skill/SKILL.md">
+  <!-- exact SKILL.md body here -->
+  <skill_directory>/skills/example-skill</skill_directory>
+  <skill_resources>
+    <file kind="reference">references/output-format.md</file>
+    <file kind="script">scripts/validate.py</file>
+    <file kind="asset">assets/template.json</file>
+  </skill_resources>
+</skill_content>
+
+
+
{
+  "name": "example-skill",
+  "version": "1.0.0",
+  "hash": "sha256:...",
+  "status": "approved",
+  "files": [
+    { "path": "SKILL.md", "hash": "sha256:..." },
+    { "path": "references/output-format.md", "hash": "sha256:..." },
+    { "path": "scripts/validate.py", "hash": "sha256:..." }
+  ],
+  "permissions": {
+    "filesystem": "read-skill-dir-only",
+    "network": "none",
+    "write_tools": "confirmation-required"
+  }
+}
+
+
+ +

Prompt curto para agente usando skills

+
Use Agent Skills only when they are relevant.
+You initially see only the skill catalog. Full SKILL.md instructions are inactive until loaded.
+If the task clearly matches a skill, activate it before domain tools or final output.
+Do not bulk-load references, scripts, or assets.
+If a skill is stale, reload it before relying on exact instructions.
+Keep multiple active skills separate and apply them in task order.
+ +

Checklists de publicação e de harness

+
+ Checklist de publicação da skill +
+
    +
  • ☐ SKILL.md tem frontmatter válido.
  • +
  • ☐ name corresponde ao diretório.
  • +
  • ☐ description tem gatilhos e limites.
  • +
  • ☐ SKILL.md é enxuto; detalhes longos estão em references.
  • +
  • ☐ Arquivos referenciados existem.
  • +
  • ☐ References estão a um nível a partir do SKILL.md.
  • +
  • ☐ Scripts não são interativos e têm --help.
  • +
  • ☐ Scripts têm testes e mensagens de erro úteis.
  • +
  • ☐ Assets são nomeados por função.
  • +
  • ☐ Segurança/trust/permissions foram revisados.
  • +
  • ☐ Evals cobrem trigger, no-trigger, função e segurança.
  • +
  • ☐ Manifest, hash e changelog foram gerados.
  • +
+
+
+
+ Checklist de implementação do harness +
+
    +
  • ☐ Discovery com escopos e trust tiers.
  • +
  • ☐ Parsing e validação de SKILL.md.
  • +
  • ☐ Catálogo L1 com budget e filtro de permissões.
  • +
  • ☐ activate_skill com enum e structured wrapping.
  • +
  • ☐ load_skill_resource com path traversal bloqueado.
  • +
  • ☐ Dedup por name+hash.
  • +
  • ☐ Active skill set explícito.
  • +
  • ☐ Stale ledger com reload_required.
  • +
  • ☐ Eviction por menor perda, não LRU puro.
  • +
  • ☐ Context compaction separa memória de instrução.
  • +
  • ☐ Logs de ativação, recursos, tools, eviction e segurança.
  • +
  • ☐ Evals de regressão em CI.
  • +
+
+
+
+ +
+

Troubleshooting

+

Sintomas, causas prováveis e correções para ativação, contexto, scripts, stale ledger, segurança e + catálogo.

+
+ + + + + + + + + + + + +
ProblemaCausa provávelCorreção
Skill não ativaDescription vaga, catálogo ausente, skill filtrada por trust, prompt não instrui ativação.Melhorar description, verificar L1, adicionar trigger evals e logs.
Skill ativa demaisDescription ampla, sem escopo negativo, skill genérica demais.Adicionar "do not use", dividir ou restringir escopo.
Agente usa tool antes da skillRegra operacional ausente ou fraca.Instruir: ativar SKILL.md antes de tools de domínio quando houver match claro.
Contexto explodeCarrega SKILL.md/references demais.Progressive disclosure, L3 sob demanda, catálogo filtrado, N_active_max.
Skill resumida perde regraCompaction mistura instrução com memória.Manter exata ou remover com reload_required.
ThrashingEviction agressiva ou sem pinning.Min residency, swap margin, retention score.
Scripts falhamDependências ausentes, prompt interativo, path errado.Documentar compatibility, --help, paths relativos, testes.
Conflito entre skillsScopes sobrepostos, múltiplas skills ativas sem ordem.Descriptions com limites, orquestração explícita, regras de prioridade.
Risco de segurançaSkill não auditada, tools amplas, script não confiável.Quarentena, sandbox, allowlist, confirmação e logs.
+ +

Correção para skill pesada

+
1. Identifique se o SKILL.md contém documentação longa.
+2. Mova detalhes para references/*.md.
+3. No SKILL.md, mantenha só workflow, gotchas críticos e triggers para references.
+4. Divida referências por domínio/feature.
+5. Teste se o agente carrega o arquivo certo no momento certo.
+6. Meça tokens L2 e L3 separadamente.
+ +

Correção para references em cascata

+

Evite referências que apontam para outras referências que apontam para outras — o agente pode ler + parcialmente e perder regras importantes:

+
Bad:
+SKILL.md -> references/advanced.md -> references/details.md -> actual rule
+
+Good:
+SKILL.md -> references/advanced.md
+SKILL.md -> references/details.md
+SKILL.md states when each one is needed.
+ +

Correção para catálogo enorme

+
    +
  • Filtre por escopo do agente, usuário, projeto, idioma, tipo de tarefa e permissões.
  • +
  • Use namespaces e capability tags.
  • +
  • Trunque descriptions menos relevantes, preservando termos front-loaded.
  • +
  • Use skill search/retrieval antes de renderizar o L1 completo.
  • +
  • Mostre warning/diagnóstico quando skills forem omitidas por budget.
  • +
+
+ +
+

Fontes & verificação

+

Todo fato relevante deste guia deve ser conferido contra a documentação oficial. As fontes abaixo + fundamentam as recomendações; o guia privilegia a especificação aberta Agent Skills, documentação oficial + de plataformas e referências reconhecidas de segurança/governança.

+
+ + + + + + + + + + + + + + + + + + + + + + +
FonteURLUso
Agent Skills · Overviewagentskills.io/homeDefinição de skills, estrutura geral e progressive disclosure.
Agent Skills · Specificationagentskills.io/specificationContrato de diretórios, SKILL.md, campos de frontmatter, references/scripts/assets e validação. Versão verificada (spec sem mudanças; último commit 20/05/2026, rechecado em 2026-06-10).
Agent Skills · Adding skills supportagentskills.io/client-implementation/adding-skills-supportDiscovery, parsing, catálogo, ativação, gestão de contexto, dedup, proteção contra compaction.
Agent Skills · Best practicesagentskills.io/skill-creation/best-practicesBoas práticas de autoria, progressive disclosure, instruções úteis e controle de contexto.
Agent Skills · Optimizing descriptionsagentskills.io/skill-creation/optimizing-descriptionsComo escrever e testar descriptions para ativação correta.
Agent Skills · Evaluating skillsagentskills.io/skill-creation/evaluating-skillsEval-driven iteration, casos de teste, assertions, grading, custo/qualidade.
Agent Skills · Using scriptsagentskills.io/skill-creation/using-scriptsScripts, interfaces não interativas, saída estruturada.
OpenAI Codex · Skillsdevelopers.openai.com/codex/skillsSkills no Codex, progressive disclosure, budget da lista inicial, ativação implícita/explícita.
OpenAI API · Skills (tools)developers.openai.com/api/docs/guides/tools-skillsSkills como bundles versionados, compatíveis com o padrão aberto Agent Skills.
Anthropic · Agent Skills Overviewplatform.claude.com · agent-skills/overviewSkills como recursos filesystem-based; carregamento automático quando relevante. Domínio verificado (platform.claude.com é canônico, 2026-05-25).
Anthropic · Skill authoring best practicesplatform.claude.com · agent-skills/best-practicesNaming, descriptions, progressive disclosure, paths, scripts e testes.
Anthropic Engineering · Agent Skillsanthropic.com/engineering · Agent SkillsEngenharia de skills como onboarding procedural para agentes.
Microsoft Learn · Agent Skillslearn.microsoft.com · agent-framework/agents/skillsAgent Skills como pacotes portáveis com progressive disclosure.
Model Context Protocol · Specificationmodelcontextprotocol.io/specification/2025-11-25MCP como protocolo para tools, resources e prompts externos. Versão verificada (2025-11-25 é a revisão atual, rechecada em 2026-06-10). Novo Próxima revisão 2026-07-28 anunciada (ainda em draft; em evolução até a publicação), com breaking changes: protocolo stateless (sem handshake initialize/Mcp-Session-Id) e Tasks movido para a extensão io.modelcontextprotocol/tasks.
MCP · Security best practicesmodelcontextprotocol.io · security best practicesRiscos e boas práticas para integrações MCP.
OWASP · Top 10 for LLM Applicationsowasp.org · Top 10 LLMRiscos de LLMs: prompt injection, output handling, supply chain.
OWASP · LLM01 Prompt Injectiongenai.owasp.org · LLM01Prompt injection e cenários de manipulação de comportamento.
UK NCSC · Prompt injection is not SQL injectionncsc.gov.uk · prompt injectionPrompt injection como confused deputy e risco residual.
NIST · AI Risk Management Frameworknist.gov · AI RMFGovernança e gerenciamento de riscos de sistemas de IA.
+

+ Legenda dos selos: Verificado confirmado na doc oficial · + Novo recurso recente · + UNVERIFIED não confirmado dentro do orçamento — exige checagem · + Removido descontinuado · + N/D não documentado. +

+ +

Notas de verificação & itens UNVERIFIED

+

Os fatos perecíveis deste guia foram confirmados contra a doc oficial em 2026-06-10. Nenhuma versão + foi inventada; o que permanece como heurística está rotulado como tal.

+
    +
  • Verificado Spec MCP 2025-11-25 — confirmada como a revisão atual em modelcontextprotocol.io/specification (schema schema/2025-11-25/schema.ts). É a versão canônica do super-guia. Nota: guia_agents_sdk.html (guia pré-existente) referencia versões anteriores (2024-11-05/2025-03-26); por decisão do time, não reescrevemos o guia existente — a versão canônica aqui é a atual.
  • +
  • Verificado Limites de frontmatter — name 1–64, description 1–1024 e compatibility 1–500 caracteres confirmados na AgentSkills Specification. A doc da Anthropic adiciona, para clientes Claude, a proibição de tags XML e das palavras reservadas "anthropic"/"claude" no name.
  • +
  • Verificado Domínio da doc Anthropic — platform.claude.com/docs/en/... carrega como canônico (não redireciona para docs.anthropic.com). Verificado 2026-05-25.
  • +
  • Heurística Budget de skills (§8: S_target, swap_margin, N_active_max etc.) — valores iniciais propostos, não números oficiais da spec. Mantidos deliberadamente como heurística: calibrar por evals/modelo/risco; não citar como limite normativo.
  • +
  • Resolvido Fronteira autoria vs integração — declarada no topo (§ Sobre este guia); cross-links para guia_claude_api.html#c-skills, guia_deepagents.html#s-skills e guia_agents_sdk.html verificados contra as âncoras reais desses arquivos.
  • +
  • Resolvido Sem IDs de modelo hardcoded — este guia é agnóstico de provedor e não fixa nomes de modelo; fatos de modelo ficam no portal e na folha de fatos SOTA.
  • +
  • Novo Integração da proposta v0.6 (2026-05-26) — reinjeção de L2 em follow-up a partir do skill store (não do tool result histórico, §8), política de L3/return packets em hot_followup (§8) e mapeamento de entrega de L1/L2/L3 por provider (§5).
  • +
  • Verificado Varredura 2026-06-10 — re-checagem contra as fontes oficiais: spec MCP 2025-11-25 segue atual, com próxima revisão 2026-07-28 anunciada (ainda em draft; em evolução até a publicação; protocolo stateless sem handshake initialize/Mcp-Session-Id, novo server/discover, Tasks movido para a extensão io.modelcontextprotocol/tasks, Roots/Sampling/Logging deprecados); spec AgentSkills sem mudanças (último commit 20/05/2026) — limites de frontmatter inalterados.
  • +
+
+ +
+
+ +
+
+
+
Guia de Agent Skills Autoria, ativação & harness — agnóstico
+

+ Referência técnica construída a partir da documentação oficial pública do padrão Agent Skills em + 2026-06-10. Cobre autoria/padrão; a integração por framework está nos guias + cross-linkados. Para informação sempre atualizada, consulte as + fontes oficiais. +

+
+
+
Crédito de produção
+
Gerado por subagentes Claude Opus 4.7 (xhigh)
+
revisão e montagem pelo orquestrador · 2026-05-26
+
+ Spec Agent Skills + PT-BR +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + diff --git a/references/agents_tools_best_guides/guia_token_counting.html b/references/agents_tools_best_guides/guia_token_counting.html new file mode 100644 index 0000000..f8755b5 --- /dev/null +++ b/references/agents_tools_best_guides/guia_token_counting.html @@ -0,0 +1,7305 @@ + + + + + +Guia de Contagem de Tokens — OpenAI, Gemini e Anthropic (texto, imagens, PDFs, arquivos, reasoning/thinking, cache) + + + + + + + + +
+
+
Guia de Contagem de Tokens OpenAI · Gemini · Anthropic
+
+ Verificado em 2026-06-11 + OpenAI + Gemini + Claude + +
+
+
+ +
+ + +
+ +
+

Como OpenAI, Gemini e Claude contam tokens — texto, imagens, PDFs, arquivos, reasoning e cache

+

Referência técnica comparativa, exaustiva e verificada de como os três providers quantificam tokens antes e depois da chamada: que endpoints existem, que campos a resposta devolve (input_tokens, usage_metadata, cached_tokens, thoughts_token_count, reasoning_tokens), como imagens lidas, imagens geradas, PDFs, arquivos persistentes, tools, vídeo, áudio, cache e reasoning/thinking são contados, com fórmulas, exemplos rodáveis em Python e TypeScript e armadilhas práticas. Construído a partir das docs oficiais públicas dos três providers (developers.openai.com, ai.google.dev, docs.claude.com) em 2026-06-10.

+
+ Endpoints oficiais + Responses · google-genai · Messages + Itens marcados UNVERIFIED precisam re-verificação antes de citar publicamente +
+
+ +
+

Por que contar tokens antes — e depois — da chamada

+

Token counting tem três usos práticos distintos que valem ser tratados como cenários separados:

+
+
+

1. Pré-flight (antes da chamada)

+

Estimar custo, decidir entre modelo barato vs caro, garantir que o prompt cabe no context window, e — em conversações longas — decidir quando truncar o histórico.

+
    +
  • OpenAI: POST /v1/responses/input_tokens
  • +
  • Gemini: client.models.count_tokens(...)
  • +
  • Anthropic: POST /v1/messages/count_tokens
  • +
+
+
+

2. Pós-chamada (auditoria)

+

Saber exatamente o que foi cobrado, isolar cache hits, reasoning, output e ajustar o pipeline.

+
    +
  • OpenAI: response.usage (com input_tokens_details.cached_tokens e output_tokens_details.reasoning_tokens)
  • +
  • Gemini: response.usage_metadata (com thoughts_token_count e cached_content_token_count)
  • +
  • Anthropic: response.usage (input/output, cache_read, cache_creation)
  • +
+
+
+

3. Tokenização local

+

Útil apenas para texto puro e dev offline; insuficiente para imagens, PDFs, tools, reasoning ou cache.

+
    +
  • OpenAI: tiktoken
  • +
  • Gemini: sem tokenizer oficial offline — use count_tokens remoto
  • +
  • Anthropic: sem tokenizer offline — use o endpoint remoto
  • +
+
+
+
+ Regra de bolso. Para qualquer payload com mídia (imagem, PDF, áudio, vídeo, arquivo) ou tools, nunca estime localmente — o erro típico passa de 50%. Use o endpoint do provider; ele é gratuito nos três. +
+
+ +
+

Três modelos mentais que você precisa carregar

+
    +
  1. Input ≠ output ≠ reasoning ≠ cache. Cada um tem fórmula, preço e campo de telemetria próprios. Um modelo de raciocínio que "pensa muito" pode produzir 200 tokens de texto visível e 6.000 tokens de reasoning faturados.
  2. +
  3. Mídia é discretizada antes de virar texto. Imagens viram patches (OpenAI gpt-5.x), entram pela tabela media_resolution (Gemini 3) ou viram um número derivado da área (Anthropic (W·H)/750). Áudio e vídeo viram tokens por unidade de tempo. No Gemini 3, vídeo é tokenizado por frame (70 tk/frame default, 280 em HIGH) mais 32 tk/s do áudio embutido — somando ≈102 tk/s no default. O valor genérico de 258 tk/frame ≈ 300 tk/s é o baseline do count_tokens, não o que se fatura em produção. PDFs são página-renderizada-como-imagem mais texto extraído.
  4. +
  5. O endpoint de contagem é uma estimativa fidedigna do input, não do total. Ele não roda o modelo. Reasoning, output e tokens system-added (Anthropic) só aparecem no usage da chamada real.
  6. +
+
+ +
+

Decisão rápida — qual ferramenta usar quando

+
+ + + + + + + + + + + + + + +
CenárioOpenAIGeminiAnthropic
Estimar custo antes de mandar um prompt longoresponses.input_tokens.count(...)models.count_tokens(...)messages.count_tokens(...)
Saber se uma imagem cabe no orçamentoresponses.input_tokens.count com input_imagecount_tokens com inlineData/fileDatamessages.count_tokens com image
Auditar gasto real após a chamadaresponse.usage (incluindo cached_tokens e reasoning_tokens)response.usage_metadataresponse.usage (incl. cache_read_input_tokens)
Roteamento: prompt > X tokens → modelo maiorPré-flight no input_tokensPré-flight no count_tokensPré-flight no count_tokens
Estimar tokens só de texto offline (dev)tiktoken (limitado)Sem tokenizer offlineSem tokenizer offline
Saber tokens de "raciocínio" (reasoning/thinking)output_tokens_details.reasoning_tokens (pós)thoughts_token_count (pós)usage da chamada com extended thinking
Saber quanto foi servido do cacheinput_tokens_details.cached_tokenscached_content_token_countcache_read_input_tokens
Contar tokens de tools/function schemasSim, em input_tokens.countSim, em count_tokensSim, em messages.count_tokens
Imagens geradas (saída)Imagem & vídeo cobrados por API/duração, não via input_tokensImagem cobrada por imagem em Nano Banana; não via count_tokensNão gera imagens
Vídeo / áudio de entradaÁudio via Chat (gpt-audio-1.5); vídeo só via framesNativo · Gemini 3: vídeo 70 tk/frame (HIGH 280) + áudio 32 tk/s ≈ 102 tk/s default (258 tk/frame ≈ 300 tk/s = baseline do count_tokens)Não suporta
+
+
+ +
+

Quadro comparativo — equivalências e diferenças

+

As tabelas abaixo são a parte mais densa do guia. Cada uma cobre uma faceta de token counting nos 3 providers. Use-as como referência de bolso; os deep-dives a seguir expandem cada célula.

+ +

5.1 Endpoints e SDKs

+
+ + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Endpoint de contagemPOST /v1/responses/input_tokensPOST /v1beta/models/{m}:countTokensPOST /v1/messages/count_tokens
Método Pythonclient.responses.input_tokens.count(...)client.models.count_tokens(...)client.messages.count_tokens(...)
Método TSclient.responses.inputTokens.count(...)ai.models.countTokens({...})client.messages.countTokens({...})
Aceita o mesmo payload da criação?Sim — mesma shape do responses.createSim — aceita contents ou generateContentRequestSim — mesma shape do messages.create
Tokenizer offline oficialtiktoken (só texto)Não publicadoNão publicado
Cobrado?GrátisGrátisGrátis (com RPM por tier)
Eligible para Zero Data RetentionN/DN/DSim (ZDR)
+
+ +

5.2 Campos no response (o que aparece onde)

+
+ + + + + + + + + + + + +
MétricaOpenAIGoogle GeminiAnthropic
Total de input (pré-flight)input_tokens (no /input_tokens)totalTokens (no countTokens)input_tokens (no count_tokens)
Input pós-chamadausage.input_tokensDois formatos coexistem: usage_metadata.prompt_token_count (em generateContent / Vertex AI) ou usage.total_input_tokens (na Interactions API, schema novo a partir de 20/05/2026)usage.input_tokens
Output pós-chamadausage.output_tokensusage_metadata.candidates_token_countusage.output_tokens
Total pós-chamadausage.total_tokensusage_metadata.total_token_countSum manual
Tokens servidos do cacheusage.input_tokens_details.cached_tokensusage_metadata.cached_content_token_countusage.cache_read_input_tokens
Tokens de raciocíniousage.output_tokens_details.reasoning_tokensusage_metadata.thoughts_token_countEmbutido em output_tokens quando thinking.enabled
Quebra por modalidadeSó agregadopromptTokensDetails[] com ModalityTokenCountSó agregado
Tokens system-added (não cobrados)——Podem estar somados; explicitado nas docs
+
+ +

5.3 Texto puro

+
+ + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Heurística aproximada1 token ≈ 4 chars EN; varia por idioma1 token ≈ 4 chars; 100 tk ≈ 60–80 palavras EN1 token ≈ 3,5–4 chars; varia por idioma
System prompt entra na conta?Sim via instructions ou primeira msgSim via systemInstructionSim via campo system
Histórico multi-turn?Sim, inclui previous_response_id ou input[]Sim, passe chat.get_history()Sim, passe messages[] completo
Tokenizer offlinetiktoken (cl100k_base, o200k_base, etc.)NãoNão
+
+ +

5.4 Imagens lidas (vision)

+

Esta é a maior fonte de divergência entre os providers — cada um tem uma fórmula diferente. O tiktoken não conta imagem, então use o endpoint remoto.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Fórmula +
Patch (gpt-5.x) — método atual +

Patch (gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano):

+
patches = ceil(W/32) · ceil(H/32)
+billed  = min(patches, budget) · multiplier
+budget  : 10000 (original) | 2500 (high) | 1536 (mini/nano)
+mult.   : 1.0 (gpt-5.5) | 1.62 (mini) | 2.46 (nano)
+

O método tile (512×512 + base) é exclusivamente legado e não se aplica aos modelos atuais.

+
+
+
media_resolution (Gemini 3) — método atual +

Gemini 3 usa a tabela media_resolution (não tiles): default/HIGH=1120, MEDIUM=560, LOW=280, ULTRA_HIGH=2240 tk per-part.

+
# baseline do count_tokens (NÃO é o valor de produção):
+se W ≤ 384 e H ≤ 384:
+  tokens = 258 (1 tile)
+senão:
+  crop = floor(min(W,H)/1.5)
+  tiles = (W/crop) · (H/crop)
+  tokens = tiles · 258
+

O 258/tile é o baseline genérico do count_tokens; os tokens faturados em Gemini 3 vêm da tabela media_resolution acima.

+
+
+ tokens ≈ (W · H) / 750 +

Sweet spot ~1,19 MP → ~1568 tk (std). Opus 4.8 até 4784 tk @ 2576 px long edge.

+
Parâmetro de resoluçãoinput_image.detail: low | high | original | automedia_resolution global ou per-part: LOW/MEDIUM/HIGH/ULTRA_HIGHSem parâmetro. Opus 4.8 hi-res automático; demais usam std.
Exemplo de custogpt-5.5 · 1024×768 · high → ceil(1024/32)·ceil(768/32) = 32·24 = 768 patches (cabe no budget de 2500)1024×768 · default Gemini 3 → 1120 tokens (media_resolution default/HIGH)1024×768 · Sonnet 4.6 → (1024·768)/750 ≈ 1048 tokens
Endpoint conta exato?SimSimEstimativa — pode variar ±poucos tk
+
+ +

5.5 PDFs

+
+ + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Tipo de blocoinput_file (file_id, file_url ou file_data)fileData (Files API) ou inlineData base64document (base64, url ou file_id)
Como contaTexto OCR + página-imagem (mesma fórmula de patch)Texto nativo + página-imagem (Gemini 3: media_resolution, 560 tk/pág default)Texto + página-imagem ((W·H)/750)
Cap por request50 MB combinados50 MB inline / 1000 pgs32 MB / 600 pgs (1M ctx) · 100 pgs (Haiku 200k)
Endpoint conta?SimSimSim (com limitações iguais à Messages API)
Exemplo oficial—countTokens com sample_pdfClaude-3 Model Card → 2188 tk
+
+ +

5.6 Arquivos persistentes (Files API)

+
+ + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Endpoint FilesPOST /v1/files (com purpose)client.files.upload(...) (resumable)POST /v1/files (beta files-api-2025-04-14)
Como referenciar no countfile_id em input_image / input_filefileData.fileUri em Partsource.type="file" + file_id
Tokens contam igual?Sim — mesma fórmula da imagem/PDF inlineSimSim
Quotas512 MB/arquivo, 2,5 TB/projeto2 GB/arquivo, 20 GB/projeto, retenção 48 h500 MB/arquivo, 500 GB/org
+
+ +

5.7 Tools / function schemas

+
+ + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Tools entram no count?Sim — passe tools=[...]Sim — em generateContentRequestSim — passe tools=[...]
Schema JSON pesaCada chave/description contaFunctionDeclaration conta integralinput_schema conta integral
MCP / hosted toolsDefinição do servidor contan/a no countTokensServer tools: só primeira sampling call
Exemplo oficial——get_weather simples → 403 tk
+
+ +

5.8 Reasoning / thinking

+
+ + + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Como ativareasoning.effort: none|low|medium|high|xhighthinking_level: minimal|low|medium|high (Gemini 3; direto em generation_config na Interactions API, aninhado em thinking_config no generateContent; thinking_budget é legado)thinking: {type:"enabled", budget_tokens: N} (Sonnet 4.6)
Aparece no count pré-flight?Não — só inputNão — só inputParcial — current turn thinking conta; turnos anteriores não
Aparece no usage pós-call?output_tokens_details.reasoning_tokensthoughts_token_countSomado em output_tokens
É cobrado?Sim — preço de outputSim — preço de outputSim — preço de output
Persistência entre turnosReasoning items voltam via previous_response_idCumulative em chats; budgetedThinking blocks anteriores IGNORADOS no count, mas devolvidos com signature na mensagem
+
+
+ Surpresa #1. Tokens de reasoning podem dominar a fatura em modelos com xhigh: um output visível de 200 tokens pode esconder 5–8 mil tokens de raciocínio. Sempre logue reasoning_tokens / thoughts_token_count em produção. +
+ +

5.9 Cache de prompt

+
+ + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic Claude
Estratégia (escopo do projeto)Automático na Responses API + prompt_cache_key opcionalApenas implícito (Developer Flash/Lite ≥1.024 · Pro ≥4.096 tk; Vertex unificado 4.096 tk). Explicit cachedContents fora de escopoExplícito via cache_control: {type:"ephemeral", ttl:"5m"|"1h"}
Aparece no count pré-flight?NãoNãoNão — endpoint ignora cache_control
Aparece no usage pós-call?input_tokens_details.cached_tokenscached_content_token_countcache_read_input_tokens + cache_creation_input_tokens
Custo do hit~25–50% do input normalImplícito: ~10% do input normal; sem fee de write nem de storageRead = 0,1× input; write 5m = 1,25×; write 1h = 2×
+
+ +

5.10 Imagens / vídeos GERADOS (saída)

+

Aqui muda a régua: nenhum dos três providers conta imagem ou vídeo gerado no endpoint de token counting. A cobrança vai por número de imagens, duração ou pixels, dependendo do produto.

+
+ + + + + + + +
TipoOpenAIGoogleAnthropic
Imagem geradagpt-image-2 via Images API ou tool em Responses — cobra por imagem (tier low/medium/high) e adiciona tokens de prompt no usagegemini-3.1-flash-image (Nano Banana 2) — por imagem; tokens de prompt em usage_metadataNão suporta
Vídeo geradoSora 2 / Sora 2-Pro — preço por segundo (4/8/12s), resolução afeta; sem input_tokens contadoVeo 3 (API separada) — preço por segundoNão suporta
Áudio gerado (TTS)gpt-realtime-2, gpt-audio-1.5, TTS dedicada — cobrado por token de áudio ou minutoGemini Live API — $0,018/min outputNão suporta
+
+
+ Como auditar geração. Para imagem/vídeo/áudio gerados, use os campos específicos de billing do produto (não o token counting). Em OpenAI, o usage da chamada que dispara a tool já mostra os tokens de prompt; o preço da imagem vem do dashboard. Em Gemini, o usage_metadata tem o breakdown por modalidade quando aplicável. +
+ +

5.11 Áudio e vídeo de ENTRADA

+
+ + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic
Áudio de entradaChat input_audio (gpt-audio-1.5); STT por arquivo via gpt-4o-transcribeNativo em generateContent · 32 tokens/segundoNão suporta — use STT externo
Vídeo de entradaSem nativo — extrair frames manualmenteNativo · Gemini 3: 70 tk/frame + 32 tk/s áudio ≈ 102 tk/s default (HIGH = 280 tk/frame). O 258 tk/frame ≈ 300 tk/s é o baseline genérico do count_tokens, não o valor de produção. 1 FPS default; muda com media_resolution.Não suporta
Endpoint conta?Audio in Chat → não passa pelo /input_tokens da ResponsesSim — passe fileData/inlineData no count_tokens—
+
+ +

5.12 Pricing & rate limits do endpoint de contagem

+
+ + + + + + + + +
AspectoOpenAIGoogle GeminiAnthropic
Custo do endpointGrátisGrátisGrátis
Rate limit do endpointCompartilhado com Responses (TPM)Quota do projetoIndependente: 100/2000/4000/8000 RPM por tier 1–4
Conta contra limite de criação?——Não — count_tokens tem RPM próprio
ZDRN/DN/DSim
+
+
+ +
+ OpenAI +

OpenAI deep-dive — token counting

+

+ Referência: 2026-06-10. Endpoint canônico de pré-contagem: + POST /v1/responses/input_tokens (espelha o body do POST /v1/responses). + Modelo padrão dos exemplos: gpt-5.5; variações sob demanda: gpt-5.4-mini, + gpt-5.4-nano. Para texto puro offline ainda há + tiktoken, mas ele não conta + imagens, PDFs, schemas de tools, MCP, instruções nem itens de reasoning. +

+ +

5.1 Visão geral e quando usar

+

+ Token counting na OpenAI cobre dois momentos distintos do ciclo de vida da requisição: +

+
    +
  1. Pré-flight — antes de chamar responses.create, você envia + o mesmo payload para POST /v1/responses/input_tokens e recebe + o número exato de input tokens. Use isso para validar limites de contexto, estimar custo + e rotear (prompt pequeno → gpt-5.4-mini; prompt grande → gpt-5.5).
  2. +
  3. Pós-resposta — toda chamada à Responses API retorna um campo + usage com input_tokens, output_tokens, + total_tokens, input_tokens_details.cached_tokens e + output_tokens_details.reasoning_tokens. Esses contadores são a fonte + autoritativa de billing.
  4. +
+
+ Quando preferir o endpoint vs. tiktoken: use + /v1/responses/input_tokens sempre que houver + imagens, files, tools, MCP servers ou instructions estruturadas. Use + tiktoken apenas para estimar prompts text-only em pipelines offline ou + hot-paths que não toleram o RTT do endpoint. +
+ +
+ + + + + + + + + + + + + +
Endpoint POST /v1/responses/input_tokens — campos aceitos
CampoTipoDescrição
modelstringMesmo identificador usado em responses.create. Define a fórmula de tokenização (patch vs. tile) e o vocab.
inputstring | array de itemsString simples ou lista de Items (message, input_text, input_image, input_file, reasoning, function_call, etc.).
instructionsstringSystem-level guidance. Conta como input tokens.
toolsarrayFunction schemas, web_search, file_search, code_interpreter, image_generation, computer_use, MCP servers. Todos pesam no input.
tool_choice / parallel_tool_calls—Aceitos para refletir o mesmo header de tools que será enviado em produção.
conversation / previous_response_idstringQuando passado, o endpoint resolve o histórico e devolve a contagem cumulativa.
+
+ +

Resposta:

+
{
+  "object": "response.input_tokens",
+  "input_tokens": 1432
+}
+ +

5.2 Texto puro — instructions e multi-turn

+

+ Para texto puro o endpoint coincide com o tokenizer local (cl100k_base / + o200k_base dependendo do modelo). A diferença começa quando há + instructions, mensagens estruturadas ou histórico via + previous_response_id — nesses casos só o endpoint sabe os tokens + de framing/role/separadores que o servidor adiciona. +

+ +
+
+ + +
+
from openai import OpenAI
+
+client = OpenAI()
+
+# 1) Contagem do prompt antes de enviar
+pre = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    instructions="Você é um analista financeiro sênior. Responda em PT-BR.",
+    input=[
+        {"role": "user", "content": "Resuma os riscos do Q3 em 5 bullets."}
+    ],
+)
+print("pré-flight input_tokens:", pre.input_tokens)
+
+# 2) Chamada real e leitura do usage
+resp = client.responses.create(
+    model="gpt-5.5",
+    instructions="Você é um analista financeiro sênior. Responda em PT-BR.",
+    input=[
+        {"role": "user", "content": "Resuma os riscos do Q3 em 5 bullets."}
+    ],
+    reasoning={"effort": "medium"},
+)
+u = resp.usage
+print("input_tokens:", u.input_tokens)
+print("output_tokens:", u.output_tokens)
+print("reasoning_tokens:", u.output_tokens_details.reasoning_tokens)
+print("cached_tokens:", u.input_tokens_details.cached_tokens)
+
import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const pre = await client.responses.inputTokens.count({
+  model: "gpt-5.5",
+  instructions: "Você é um analista financeiro sênior. Responda em PT-BR.",
+  input: [
+    { role: "user", content: "Resuma os riscos do Q3 em 5 bullets." },
+  ],
+});
+console.log("pré-flight input_tokens:", pre.input_tokens);
+
+const resp = await client.responses.create({
+  model: "gpt-5.5",
+  instructions: "Você é um analista financeiro sênior. Responda em PT-BR.",
+  input: [
+    { role: "user", content: "Resuma os riscos do Q3 em 5 bullets." },
+  ],
+  reasoning: { effort: "medium" },
+});
+const u = resp.usage!;
+console.log("input_tokens:", u.input_tokens);
+console.log("output_tokens:", u.output_tokens);
+console.log("reasoning_tokens:", u.output_tokens_details?.reasoning_tokens);
+console.log("cached_tokens:", u.input_tokens_details?.cached_tokens);
+
+ +
+ tiktoken: quando ainda vale. Para validação local em loops apertados, + use tiktoken.encoding_for_model("gpt-5.5") e some os tokens das strings. + Sempre que o payload tiver image_url, input_file, + tools, mcp, file_search, code_interpreter + ou image_generation, a contagem local diverge — o endpoint é a verdade. +
+ +

5.3 Contagem com imagens — método patch

+

+ Os modelos SOTA da OpenAI (gpt-5.5, gpt-5.4-mini, gpt-5.4-nano) + tokenizam imagem pelo método patch (32×32 px). O método tile das + gerações anteriores é legado (ver abaixo): +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Regras de tokenização de imagem por família de modelo (verificado 🔒 2026-06-10, docs oficiais images-vision)
FamíliaFórmulaDetail levelsBudget & multiplier
gpt-5.5Patch 32×32low, high, original, autohigh: 2.500 patches ou 2048 px; original/auto: 10.000 patches ou 6000 px. Multiplier não publicado na tabela oficial — para gpt-5.5 os tokens billed correspondem ao resized_patch_count direto (multiplier efetivo = 1.0) 🔒. A tabela com multipliers >1 cobre apenas as variantes mini/nano.
gpt-5.4-miniPatch 32×32low, high, auto1.536 patches ou 2048 px. Multiplier 1.62.
gpt-5.4-nanoPatch 32×32low, high, auto1.536 patches ou 2048 px. Multiplier 2.46.
+
+ +

Fórmula patch (gpt-5.x e variantes)

+

O cálculo é determinístico e replicável local:

+
# A) Patches necessários para cobrir a imagem original
+original_patch_count = ceil(width/32) * ceil(height/32)
+
+# B) Se exceder o budget, reduz preservando aspect ratio
+shrink_factor = sqrt((32**2 * patch_budget) / (width * height))
+adjusted = shrink_factor * min(
+    floor(width  * shrink_factor / 32) / (width  * shrink_factor / 32),
+    floor(height * shrink_factor / 32) / (height * shrink_factor / 32),
+)
+
+# C) Reconta após resize
+resized_w, resized_h = int(width*adjusted), int(height*adjusted)
+resized_patch_count = ceil(resized_w/32) * ceil(resized_h/32)
+
+# D) Aplica multiplier do modelo (1.0 para gpt-5.5; 1.62 mini; 2.46 nano)
+billed_tokens = resized_patch_count * multiplier
+ +

Exemplos numéricos de imagem (calculados pelas fórmulas oficiais)

+
+ + + + + + + + + + + + + + +
Tokens billed por imagem (aplicando patch oficial + multiplier)
Imagem / Detailgpt-5.5 (×1.0)gpt-5.4-mini (×1.62)gpt-5.4-nano (×2.46)
640×480 high300486738
1024×768 high7681.2441.889
1024×1024 high1.0241.6592.519
1800×2400 high4.275resize → 2.3523.572
2048×2048 high4.096resize → 2.4893.779
3000×4000 original~9.7502.489 (cap)3.779
qualquer low~85~138~209
+
+ +

Fórmula tile — legado (gerações pré-gpt-5.x)

+
+ Método legado. A fórmula tile (512×512 + base) é a tokenização das gerações anteriores ao patch-based. Nenhum modelo SOTA atual (gpt-5.5, gpt-5.4-mini, gpt-5.4-nano) a usa — todos seguem o método patch acima. Mantida apenas como referência de migração. +
+
    +
  1. Imagens com detail: "low" custam um base fixo, sem tiles.
  2. +
  3. Para detail: "high": scale para caber em 2048×2048, depois scale para que o menor lado seja 768 px, depois conte quantos quadrados de 512 px cobrem a imagem.
  4. +
  5. Total = base + (tiles × tile_tokens).
  6. +
+ +
+ Detail levels mudam custo. + low sempre é base-fixo / 512×512 downsample. + high habilita patches/tiles cheios. + original (só gpt-5.x) sobe o budget para 10.000 patches / + 6000 px — ideal para OCR e UI densa, mas pode multiplicar o custo por 4×. + auto em gpt-5.5 é equivalente a original; + em gpt-5.4-mini/gpt-5.4-nano é equivalente a high. 🔒 +
+ +

Comparação multi-detail na mesma imagem (gpt-5.5, 1800×2400)

+
+ + + + + + + + +
Mesma imagem, três detail levels — diferença real de billing
DetailBudget aplicadoPatches finaisTokens billed$ em gpt-5.5 (input $5/1M)
lowfixed 512 px downsample~13·17 = 221~221$0.0011
high2.500 / 2048 pxresize 1536×2048 → 48·64 = 3072 → cap 25002500$0.0125
original10.000 / 6000 px57·75 = 4275 (cabe)4275$0.0214
+
+

Lição: para OCR denso (NFE, prontuário, screenshot de UI), original compensa; para descrição genérica, low é 19× mais barato sem perda perceptível.

+ +

Exemplo: medir as três opções no endpoint (mesma imagem, três níveis)

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+URL = "https://exemplo.com/nfe-001.png"
+
+for detail in ("low", "high", "original"):
+    c = client.responses.input_tokens.count(
+        model="gpt-5.5",
+        input=[{
+            "role": "user",
+            "content": [
+                {"type": "input_text", "text": "Liste os itens."},
+                {"type": "input_image", "image_url": URL, "detail": detail},
+            ],
+        }],
+    )
+    print(f"detail={detail:>8s}  tokens={c.input_tokens}")
+# detail=     low  tokens=~230
+# detail=    high  tokens=~2510
+# detail=original  tokens=~4290
+
const URL = "https://exemplo.com/nfe-001.png";
+
+for (const detail of ["low", "high", "original"] as const) {
+  const c = await client.responses.inputTokens.count({
+    model: "gpt-5.5",
+    input: [{
+      role: "user",
+      content: [
+        { type: "input_text", text: "Liste os itens." },
+        { type: "input_image", image_url: URL, detail },
+      ],
+    }],
+  });
+  console.log(`detail=${detail.padStart(8)}  tokens=${c.input_tokens}`);
+}
+
+ +

5.4 Contagem com PDFs e input_file

+

+ PDFs entram via input_file, aceitando file_id (Files API), + file_url (HTTPS público) ou file_data + (Base64 data:application/pdf;base64,...). O servidor extrai texto + e imagens de cada página em modelos com visão (família gpt-5.x); + a contagem reflete os dois. Para outros tipos (.docx, .pptx, + .txt, código), só o texto é extraído. +

+ +
+ + + + + + + + + + + + + +
Limites de input_file e purpose recomendados
ItemLimite / Recomendação
Tamanho por arquivo50 MB
Soma de arquivos por request50 MB
Modelos com vision (texto + imagens das páginas)família gpt-5.x (gpt-5.5, gpt-5.4-mini, gpt-5.4-nano)
purpose=user_dataAnexar como contexto direto em input_file (PDF, DOCX, planilha) 🔒
purpose=assistantsLegado da Assistants API; ainda aceito mas desencorajado em novos fluxos Responses 🔒
purpose=visionImagens reais (PNG/JPG/WEBP/GIF) para input_image.file_id
purpose=batchJSONL para Batch API (≤ 200 MB)
purpose=fine-tuneReservado para fine-tuning
+
+ +

Diferença prática de count entre user_data e assistants: + o contador de tokens é o mesmo (servidor extrai texto e renderiza páginas idem), + mas em assistants o arquivo é tratado como "anexável a thread" e exige tools + como file_search para ser lido — gerando overhead extra de tool schema. Para um + PDF analítico de turn único, user_data + input_file direto é + ~150–400 tokens mais barato por request (sem o schema do file_search).

+ +
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+# Sobe o PDF com purpose=user_data
+file = client.files.create(
+    file=open("relatorio_q3.pdf", "rb"),
+    purpose="user_data",
+)
+
+count = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    input=[{
+        "role": "user",
+        "content": [
+            {"type": "input_text", "text": "Liste os 10 KPIs principais deste PDF."},
+            {"type": "input_file", "file_id": file.id},
+        ],
+    }],
+)
+print("Tokens do PDF + prompt:", count.input_tokens)
+
import fs from "node:fs";
+import OpenAI from "openai";
+
+const client = new OpenAI();
+
+const file = await client.files.create({
+  file: fs.createReadStream("relatorio_q3.pdf"),
+  purpose: "user_data",
+});
+
+const count = await client.responses.inputTokens.count({
+  model: "gpt-5.5",
+  input: [{
+    role: "user",
+    content: [
+      { type: "input_text", text: "Liste os 10 KPIs principais deste PDF." },
+      { type: "input_file", file_id: file.id },
+    ],
+  }],
+});
+console.log("Tokens do PDF + prompt:", count.input_tokens);
+
+ +
+ Heurística para estimar PDF antes do upload: + cada página renderizada como imagem entra na fórmula patch (família gpt-5.x) + como uma imagem independente. Pré-conte multiplicando páginas × tokens-por-página + no modelo alvo, ou — recomendado — chame o endpoint com file_data Base64 + em uma página de amostra para calibrar. +
+ +

5.5 Contagem com tools, MCP servers e File Search

+

+ Schemas de function tools, definições de MCP servers e a habilitação de + hosted tools (web_search, file_search, + code_interpreter, image_generation, + computer_use) consomem tokens de input. O endpoint inclui esse + overhead automaticamente — não tente estimar a partir do JSON cru. +

+ +
+
+ + +
+
tools = [
+    {
+        "type": "function",
+        "name": "get_pricing",
+        "description": "Retorna pricing por SKU.",
+        "parameters": {
+            "type": "object",
+            "properties": {
+                "sku": {"type": "string"},
+                "currency": {"type": "string", "enum": ["BRL", "USD", "EUR"]},
+            },
+            "required": ["sku"],
+        },
+        "strict": True,
+    },
+    {"type": "web_search"},
+    {"type": "file_search", "vector_store_ids": ["vs_abc123"]},
+]
+
+count = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    instructions="Use as tools quando precisar de dados externos.",
+    input="Qual o preço atual do SKU 9981 em BRL e fontes recentes?",
+    tools=tools,
+    tool_choice="auto",
+)
+print(count.input_tokens)
+
const tools = [
+  {
+    type: "function" as const,
+    name: "get_pricing",
+    description: "Retorna pricing por SKU.",
+    parameters: {
+      type: "object",
+      properties: {
+        sku: { type: "string" },
+        currency: { type: "string", enum: ["BRL", "USD", "EUR"] },
+      },
+      required: ["sku"],
+    },
+    strict: true,
+  },
+  { type: "web_search" as const },
+  { type: "file_search" as const, vector_store_ids: ["vs_abc123"] },
+];
+
+const count = await client.responses.inputTokens.count({
+  model: "gpt-5.5",
+  instructions: "Use as tools quando precisar de dados externos.",
+  input: "Qual o preço atual do SKU 9981 em BRL e fontes recentes?",
+  tools,
+  tool_choice: "auto",
+});
+console.log(count.input_tokens);
+
+ +

Overhead típico de tools (medido pelo endpoint, mesmo prompt-base)

+
+ + + + + + + + + + + + +
Δ input_tokens ao adicionar cada tool (gpt-5.5, prompt-base = 412 tokens)
Tool adicionadaTokens adicionaisNotas
web_search+ ~40–60Schema fixo, hospedado pela OpenAI
file_search (1 vector store)+ ~80–120Inclui hint do schema + ref ao vs_*
code_interpreter+ ~30–50Container hospedado, schema mínimo
image_generation+ ~50–90Cresce com quality/size/action
function (1 schema, ~10 props strict)+ ~120–250Cresce linear com props + descrições
mcp remote (5 tools listadas)+ ~600–1.500Inclui handshake + mcp_list_tools 🔒
mcp remote (30 tools, sem allowed_tools)+ ~3.000–6.000Filtre via allowed_tools 🔒
+
+ +

Exemplo: MCP remoto com contagem antes/depois

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+prompt_base = "Refunde o último charge do customer cus_98 e me retorne o ID."
+
+# 1) Sem MCP — só o function tool básico
+base = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    input=prompt_base,
+)
+print("baseline:", base.input_tokens)
+
+# 2) Com MCP Stripe inteiro (~30 tools)
+full = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    input=prompt_base,
+    tools=[{
+        "type": "mcp",
+        "server_label": "stripe",
+        "server_url": "https://mcp.stripe.com",
+        "headers": {"Authorization": "Bearer $STRIPE_API_KEY"},
+    }],
+)
+print("com MCP completo:", full.input_tokens)
+
+# 3) Filtrado: apenas as tools que importam
+filtered = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    input=prompt_base,
+    tools=[{
+        "type": "mcp",
+        "server_label": "stripe",
+        "server_url": "https://mcp.stripe.com",
+        "headers": {"Authorization": "Bearer $STRIPE_API_KEY"},
+        "allowed_tools": ["create_refund", "list_charges"],
+    }],
+)
+print("com MCP filtrado:", filtered.input_tokens)
+# Típico: 1500-4000 tokens economizados no segundo caso.
+
const prompt = "Refunde o último charge do customer cus_98.";
+
+const mcpFull = {
+  type: "mcp" as const,
+  server_label: "stripe",
+  server_url: "https://mcp.stripe.com",
+  headers: { Authorization: "Bearer $STRIPE_API_KEY" },
+};
+const mcpFiltered = { ...mcpFull,
+  allowed_tools: ["create_refund", "list_charges"] };
+
+const [base, full, filtered] = await Promise.all([
+  client.responses.inputTokens.count({ model: "gpt-5.5", input: prompt }),
+  client.responses.inputTokens.count({ model: "gpt-5.5", input: prompt, tools: [mcpFull] }),
+  client.responses.inputTokens.count({ model: "gpt-5.5", input: prompt, tools: [mcpFiltered] }),
+]);
+console.log({ baseline: base.input_tokens, fullMcp: full.input_tokens, filtered: filtered.input_tokens });
+
+ +

File Search: contagem com vector store ativa

+

+ A tool file_search custa $2.50 / 1k chamadas + $0.10/GB-dia + de storage no vector store. O schema da tool em si já é contado no input, mas + o conteúdo retornado pela busca aparece em output_tokens da response como + citations + trechos. Use o endpoint para medir o impacto do schema antes de ativar. +

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+# Custo de schema: chama o endpoint com e sem file_search
+without_fs = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    input="Quem é o CFO atual segundo o último 10-K?",
+).input_tokens
+
+with_fs = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    input="Quem é o CFO atual segundo o último 10-K?",
+    tools=[{
+        "type": "file_search",
+        "vector_store_ids": ["vs_corp_10k_2025"],
+        "max_num_results": 5,  # menos resultados = menos output tokens
+    }],
+).input_tokens
+
+print(f"overhead do file_search: {with_fs - without_fs} tokens")
+
+# Chamada real, lendo input + output (com search results inline via include)
+resp = client.responses.create(
+    model="gpt-5.5",
+    input="Quem é o CFO atual segundo o último 10-K?",
+    tools=[{
+        "type": "file_search",
+        "vector_store_ids": ["vs_corp_10k_2025"],
+        "max_num_results": 5,
+    }],
+    include=["file_search_call.results"],
+)
+print("input:", resp.usage.input_tokens, "output:", resp.usage.output_tokens)
+
const q = "Quem é o CFO atual segundo o último 10-K?";
+const [without, withFs] = await Promise.all([
+  client.responses.inputTokens.count({ model: "gpt-5.5", input: q }),
+  client.responses.inputTokens.count({
+    model: "gpt-5.5", input: q,
+    tools: [{ type: "file_search", vector_store_ids: ["vs_corp_10k_2025"], max_num_results: 5 }],
+  }),
+]);
+console.log("overhead file_search:", withFs.input_tokens - without.input_tokens);
+
+ +
+ MCP remoto e tool catalogs grandes. Catálogos de 30+ tools podem + custar centenas a milhares de tokens só de schema 🔒. Em + gpt-5.5, use allowed_tools para filtrar o subset relevante + por turn — o endpoint mostra o impacto exato no input. Para servers que mudam pouco, + o handshake + mcp_list_tools é cacheável (entra no prefixo) se você mantiver + o tool config no início do payload. +
+ +

5.6 Reasoning tokens (output)

+

+ Modelos reasoning (gpt-5.5, gpt-5.4-mini, + gpt-5.4-nano) geram reasoning tokens internos antes do + output final. Eles são output tokens e não aparecem no + endpoint /v1/responses/input_tokens (que é só pré-flight de input). + São visíveis apenas no usage da resposta real. +

+ +
+ + + + + + + +
Onde ler reasoning tokens (verificado 🔒)
APICampo
Responses APIusage.output_tokens_details.reasoning_tokens
Chat Completionsusage.completion_tokens_details.reasoning_tokens
+
+ +

+ O custo de reasoning escala com reasoning.effort ∈ {none, low, medium, high, xhigh} 🔒. + Em produção sob orçamento apertado, monitore esse campo e ajuste o effort por + rota — em gpt-5.5 o default é none, e xhigh + é o nível de raciocínio máximo. +

+ +
+ Em conversations stateful (com previous_response_id) os reasoning items + podem ser preservados de turn para turn — quando passados de volta como input, eles + contam como input tokens no próximo turn. O endpoint /v1/responses/input_tokens + inclui esse overhead se você enviar o conversation/previous_response_id. +
+ +

Exemplo: contagem cumulativa em conversa stateful

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+# Turn 1
+r1 = client.responses.create(
+    model="gpt-5.5",
+    input="Você é tutor de matemática. Resolva: integral de x*sin(x) dx.",
+    reasoning={"effort": "high"},
+    store=True,  # permite previous_response_id
+)
+print("T1 input:", r1.usage.input_tokens,
+      "reasoning:", r1.usage.output_tokens_details.reasoning_tokens,
+      "output:", r1.usage.output_tokens)
+
+# Turn 2 — pré-flight com previous_response_id (mede o overhead acumulado)
+pre = client.responses.input_tokens.count(
+    model="gpt-5.5",
+    previous_response_id=r1.id,
+    input="Agora derive o resultado para conferir.",
+)
+print("T2 pré-flight cumulativo:", pre.input_tokens)
+# Inclui: instructions originais + Q1 + reasoning preservado + answer Q1 + Q2
+
+r2 = client.responses.create(
+    model="gpt-5.5",
+    previous_response_id=r1.id,
+    input="Agora derive o resultado para conferir.",
+    reasoning={"effort": "low"},  # reduz o custo no turn 2
+)
+print("T2 input:", r2.usage.input_tokens,
+      "cached:", r2.usage.input_tokens_details.cached_tokens,
+      "reasoning:", r2.usage.output_tokens_details.reasoning_tokens)
+
const r1 = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Você é tutor. Resolva: integral de x*sin(x) dx.",
+  reasoning: { effort: "high" }, store: true,
+});
+
+const pre = await client.responses.inputTokens.count({
+  model: "gpt-5.5", previous_response_id: r1.id,
+  input: "Agora derive o resultado.",
+});
+console.log("T2 cumulativo:", pre.input_tokens);
+
+const r2 = await client.responses.create({
+  model: "gpt-5.5", previous_response_id: r1.id,
+  input: "Agora derive o resultado.",
+  reasoning: { effort: "low" },
+});
+console.log(r2.usage.input_tokens, r2.usage.input_tokens_details?.cached_tokens);
+
+ +

5.7 Cached input tokens (prompt caching automático)

+

+ A Responses API faz prompt caching automático em prompts ≥1024 tokens + (família gpt-5.x). Cache hits aparecem como + usage.input_tokens_details.cached_tokens e custam frações do preço + do input padrão (até –90% e –80% de latência) 🔒. +

+ +
+ + + + + + + + + + + + +
Prompt caching — fatos operacionais (verificado 🔒)
AspectoComportamento
Mínimo para hitPrefixo ≥ 1024 tokens, exato (mensagens, imagens, tools, schemas).
Retenção in_memory5–10 min de inatividade, até 1 h. Não suportado em gpt-5.5 e modelos futuros 🔒.
Retenção 24h (Extended Prompt Caching)Desde 2026-05-29, prompt_cache_retention: "24h" é o default para organizações sem ZDR em v1/responses, v1/chat/completions e v1/batch — inclusive em gpt-5.4-mini e gpt-5.4-nano. Em gpt-5.5 e modelos futuros é obrigatório 🔒.
Configuraçãoprompt_cache_retention: "24h" ou "in_memory". Em gpt-5.5 só 24h é aceito.
RoteamentoHash dos primeiros ~256 tokens. prompt_cache_key consistente aumenta hit rate; cap de ~15 RPM por chave antes de overflow.
CustoSem fee adicional. Cache hits pagam a tabela de "cached input".
ZDRExtended caching NÃO bloqueia ZDR; key/value tensors são retidos até 24 h em GPU-local storage 🔒.
+
+ +

Shape oficial do usage em Responses (extraído da doc 🔒):

+
{
+  "usage": {
+    "input_tokens": 2006,
+    "output_tokens": 312,
+    "total_tokens": 2318,
+    "input_tokens_details":  { "cached_tokens": 1920 },
+    "output_tokens_details": {
+      "reasoning_tokens": 88,
+      "accepted_prediction_tokens": 0,
+      "rejected_prediction_tokens": 0
+    }
+  }
+}
+ +
+ Padrão de design. Coloque instructions, schemas de tools, + contexto fixo e exemplos no início do prompt; mantenha a parte + variável do usuário no final. Isso maximiza o prefixo cacheável. +
+ +

5.8 Streaming + usage no último chunk

+

+ Em chamadas com stream=True (Responses API) ou + stream=true + stream_options.include_usage=true (Chat Completions), + o campo usage só chega no último evento da stream. + Se a conexão for interrompida ou cancelada, você não recebe o usage final 🔒 + — o billing acontece no servidor de qualquer forma, mas o cliente perde a visibilidade. +

+ +
+ + + + + + + + + + + + + + + + + + + + +
Onde o usage aparece em cada API streaming
APIComo pedirOnde ler
Responses APIstream=True (default já inclui usage)Evento response.completed → response.usage
Chat Completionsstream=True, stream_options={"include_usage": True}Último chunk (com choices=[]) → chunk.usage
Realtime APIDefault em response.doneevent.response.usage
+
+ +

Exemplo: capturando o usage da stream

+
+
+ + +
+
from openai import OpenAI
+client = OpenAI()
+
+usage = None
+text_parts = []
+
+with client.responses.stream(
+    model="gpt-5.5",
+    input="Explique entropia em 3 parágrafos.",
+    reasoning={"effort": "low"},
+) as stream:
+    for event in stream:
+        if event.type == "response.output_text.delta":
+            text_parts.append(event.delta)
+        elif event.type == "response.completed":
+            # usage chega aqui — último evento
+            usage = event.response.usage
+
+print("".join(text_parts))
+print("input:", usage.input_tokens,
+      "output:", usage.output_tokens,
+      "reasoning:", usage.output_tokens_details.reasoning_tokens,
+      "cached:", usage.input_tokens_details.cached_tokens)
+
+# --- Chat Completions equivalente ---
+chunks = client.chat.completions.create(
+    model="gpt-5.4-mini",
+    messages=[{"role": "user", "content": "Diga oi"}],
+    stream=True,
+    stream_options={"include_usage": True},  # <-- crucial
+)
+last_usage = None
+for c in chunks:
+    if c.usage is not None:           # vem só no último chunk
+        last_usage = c.usage
+print(last_usage)
+
let usage: any = null;
+const stream = await client.responses.stream({
+  model: "gpt-5.5",
+  input: "Explique entropia em 3 parágrafos.",
+  reasoning: { effort: "low" },
+});
+for await (const event of stream) {
+  if (event.type === "response.completed") usage = event.response.usage;
+}
+console.log(usage.input_tokens, usage.output_tokens);
+
+// Chat Completions equivalente:
+const cc = await client.chat.completions.create({
+  model: "gpt-5.4-mini",
+  messages: [{ role: "user", content: "Diga oi" }],
+  stream: true,
+  stream_options: { include_usage: true },  // <-- crucial
+});
+let lastUsage = null;
+for await (const chunk of cc) if (chunk.usage) lastUsage = chunk.usage;
+console.log(lastUsage);
+
+ +
+ Stream interrompida = sem usage no cliente. Implemente um + fallback: ao detectar disconnect/cancelamento, faça um GET /v1/responses/{id} + (com store=True) para puxar o usage autoritativo do servidor. +
+ +

5.9 Imagens geradas (gpt-image-2) e vídeos (Sora 2)

+

+ O endpoint /v1/responses/input_tokens conta apenas inputs. + Outputs gerados — imagens via image_generation tool ou + POST /v1/images/generations com gpt-image-2, e vídeos via + POST /v1/videos com sora-2 / sora-2-pro — são + cobrados pela tabela de pricing do produto (por imagem/segundo + image output tokens), + não no shape padrão de text input/output tokens da Responses. +

+ +
+ + + + + + + + + + + + + +
Como cada saída gerada é cobrada (verificado 🔒)
SaídaUnidade de cobrançaAparece em usage?
Texto (qualquer modelo)input/output tokensSim
Reasoning internooutput_tokens (subset)Sim — output_tokens_details.reasoning_tokens
Imagem gerada (gpt-image-2 via tool em Responses)Image output tokens por quality+sizeSim — tokens entram em output_tokens e aparecem no item image_generation_call do output; preço por imagem UNVERIFIED → ver pricing oficial
Imagem via Images API (POST /v1/images/generations)Tabela de $/imagem (Low/Med/High × size)Não no usage da Responses — billing por job
Partial images em streaming+100 image output tokens por partial 🔒Incluído em output_tokens
Vídeo gerado (sora-2, sora-2-pro)Por segundo de vídeo + resoluçãoNão — billing é por job assíncrono
TTS (/v1/audio/speech)Por caractere de inputNão no usage da Responses
STT (/v1/audio/transcriptions)Por minuto ou por token, depende do modeloNão no usage da Responses
+
+ +

Exemplo end-to-end: image_generation tool e onde aparece no usage

+
+
+ + +
+
from openai import OpenAI
+import base64
+client = OpenAI()
+
+resp = client.responses.create(
+    model="gpt-5.5",
+    input="Gere uma capa minimalista para um livro sobre entropia.",
+    tools=[{
+        "type": "image_generation",
+        "quality": "high",
+        "size": "1024x1536",
+    }],
+)
+
+# Salva a imagem
+for item in resp.output:
+    if item.type == "image_generation_call":
+        with open("capa.png", "wb") as f:
+            f.write(base64.b64decode(item.result))
+        print("revised_prompt:", item.revised_prompt)
+
+# Usage: text input + text output (descrição do call) + image output tokens
+u = resp.usage
+print("input:", u.input_tokens)
+print("output:", u.output_tokens, " (inclui ~6240 image output tokens para 1024x1536/high)")
+# Cross-check pela tabela: 1024x1536 high → 6240 image tokens + small text overhead
+
import fs from "node:fs";
+
+const resp = await client.responses.create({
+  model: "gpt-5.5",
+  input: "Gere uma capa minimalista para um livro sobre entropia.",
+  tools: [{ type: "image_generation", quality: "high", size: "1024x1536" }],
+});
+for (const item of resp.output) {
+  if (item.type === "image_generation_call")
+    fs.writeFileSync("capa.png", Buffer.from(item.result, "base64"));
+}
+console.log(resp.usage.input_tokens, resp.usage.output_tokens);
+
+ +
+ + + + + + + + +
Image output tokens por qualidade/resolução (gpt-image-2) — referência para estimar o subset de output_tokens que veio da geração. UNVERIFIED: confirme os valores atuais na pricing page oficial (renderiza via JS).
Quality1024×10241024×15361536×1024
Low272408400
Medium105615841568
High416062406208
+
+ +

5.10 Files API e resolução de file_id

+

+ Qualquer arquivo previamente subido em POST /v1/files + (purpose user_data, vision, assistants, batch, fine-tune) + pode ser referenciado por file_id em input_file ou + input_image. O endpoint de count resolve o file_id, + extrai o conteúdo no servidor e aplica a fórmula de tokenização adequada + (patch/tile para imagens, texto+páginas-imagem para PDFs, texto para outros tipos). +

+ +
+ + + + + + + + + +
Como file_id vira tokens
TipoResoluçãoCobrança
Imagem (.png, .jpg, .webp, .gif)Mesma fórmula patch/tile da imagem embutida.Input tokens.
PDF (texto + páginas como imagem)Extrai texto e renderiza cada página como imagem.Input tokens (soma das duas modalidades).
.docx, .pptx, .txt, códigoSó extração de texto; sem imagens embutidas.Input tokens (texto).
Spreadsheet (.xlsx, .csv, .tsv, .iif)Augmentation específica (linhas + headers).Input tokens.
+
+ +
+ Atalho perigoso: evite estimar PDF via + caracteres / 4 ou + páginas × 600. Páginas densas (charts, tabelas) costumam ultrapassar + 1.500–2.500 tokens cada em gpt-5.5 com detail: "original". + Sempre rode o endpoint na primeira execução de cada pipeline novo de PDF. +
+ +

5.11 Batch API + counting (50% off, JSONL ≤200 MB, 24 h)

+

+ A Batch API oferece 50% de desconto em todos os modelos + suportados, com janela de conclusão de 24 h e pool separado de rate-limits 🔒. + Cada batch aceita até 50.000 requests e o arquivo JSONL pode ter no máximo + 200 MB. Endpoints suportados: /v1/responses, + /v1/chat/completions, /v1/embeddings, /v1/completions, + /v1/moderations, /v1/images/generations, + /v1/images/edits, /v1/videos 🔒. +

+ +
+ + + + + + + + + + + + + +
Limites operacionais Batch (verificado 🔒)
LimiteValor
Requests por batch≤ 50.000
Tamanho do JSONL≤ 200 MB
Janela de execuçãocompletion_window: "24h" (único valor aceito hoje)
Criação de batches≤ 2.000/hora
Desconto50% sobre input/cached/output do modelo
Embeddings≤ 50.000 inputs por batch
Output retention30 dias (depois deletado automaticamente)
Vídeos via batchApenas JSON (sem multipart); assets via file_id/image_url
+
+ +

Pré-flight de 10k requests antes de submeter um batch

+

+ O endpoint /v1/responses/input_tokens é o caminho certo para validar + cada linha de um JSONL antes de subir. Use-o em um loop com checkpoint para evitar + surpresas (linha 7.842 estourar o context window pega o batch inteiro). +

+ +
+
+ + +
+
import json
+from openai import OpenAI
+client = OpenAI()
+
+CONTEXT_LIMIT = 272_000        # gpt-5.5
+TARGET_BUDGET = int(0.85 * CONTEXT_LIMIT)
+
+total = 0
+problems = []
+with open("batch_input.jsonl", "r", encoding="utf-8") as f:
+    for i, line in enumerate(f):
+        req = json.loads(line)
+        body = req["body"]
+        c = client.responses.input_tokens.count(
+            model=body["model"],
+            input=body["input"],
+            instructions=body.get("instructions"),
+            tools=body.get("tools"),
+        )
+        total += c.input_tokens
+        if c.input_tokens > TARGET_BUDGET:
+            problems.append((req["custom_id"], c.input_tokens))
+
+print(f"total estimado de input tokens: {total:,}")
+print(f"requests problemáticas: {len(problems)}")
+for cid, n in problems[:10]:
+    print(f"  - {cid}: {n} tokens")
+
+# Se tudo OK, subir e criar o batch
+if not problems:
+    f = client.files.create(file=open("batch_input.jsonl","rb"),
+                            purpose="batch")
+    batch = client.batches.create(
+        input_file_id=f.id,
+        endpoint="/v1/responses",
+        completion_window="24h",
+        metadata={"description": "nightly extraction"},
+    )
+    print(batch.id, batch.status)
+
import fs from "node:fs";
+import readline from "node:readline";
+
+const TARGET = Math.floor(0.85 * 272_000);   // gpt-5.5
+const rl = readline.createInterface({ input: fs.createReadStream("batch_input.jsonl") });
+
+let total = 0;
+const problems: { id: string; n: number }[] = [];
+for await (const line of rl) {
+  const req = JSON.parse(line);
+  const c = await client.responses.inputTokens.count({
+    model: req.body.model, input: req.body.input,
+    instructions: req.body.instructions, tools: req.body.tools,
+  });
+  total += c.input_tokens;
+  if (c.input_tokens > TARGET) problems.push({ id: req.custom_id, n: c.input_tokens });
+}
+console.log(`total: ${total.toLocaleString()}, problemas: ${problems.length}`);
+
+if (problems.length === 0) {
+  const file = await client.files.create({
+    file: fs.createReadStream("batch_input.jsonl"), purpose: "batch",
+  });
+  const batch = await client.batches.create({
+    input_file_id: file.id, endpoint: "/v1/responses", completion_window: "24h",
+  });
+  console.log(batch.id, batch.status);
+}
+
+ +
+ Custo de pré-flight do batch. O endpoint input_tokens.count + é grátis. Para 10.000 requests, são 10k roundtrips — paralelize em ~32 workers para + completar em poucos minutos. Cache o resultado por custom_id para + re-runs (mesma input → mesmo count). +
+ +

5.12 Pricing por 1M tokens — referência rápida

+

+ Tabela oficial Standard tier (developers.openai.com/api/docs/pricing, verificado 🔒 2026-06-10). + Multiplique pela quantidade lida em usage.input_tokens / + cached_tokens / output_tokens para obter o $ exato. +

+ +
+ + + + + + + + + + +
Pricing standard por 1M tokens (USD, <272K context). Batch tier = 50% off em todos.
ModeloInputCachedOutput
gpt-5.5$5.00$0.50$30.00
gpt-5.4-mini$0.75$0.075$4.50
gpt-5.4-nano$0.20$0.02$1.25
+
+ +

+ Regional processing uplift: +10% sobre gpt-5.5, + gpt-5.4-mini e gpt-5.4-nano + quando usadas em endpoints de data residency 🔒. + Tools com pricing separado: file_search $2.50/1k calls + $0.10/GB-dia; + web_search $10–25/1k calls (varia por modelo); code_interpreter (containers): + desde 2026-06-02 a cobrança é por minuto, com mínimo de + 5 minutos por sessão — as taxas por 20 min seguem como base de preço + (1GB $0.03 · 4GB $0.12 · 16GB $0.48 · 64GB $1.92), mas não se cobra mais o bloco de 20 min inteiro. +

+ +

Custo computado a partir do usage

+
+
+ + +
+
PRICING = {
+    "gpt-5.5":       {"in": 5.00, "cache": 0.50, "out": 30.00},
+    "gpt-5.4-mini":  {"in": 0.75, "cache": 0.075,"out":  4.50},
+    "gpt-5.4-nano":  {"in": 0.20, "cache": 0.02, "out":  1.25},
+}
+
+def cost(usage, model, batch=False):
+    p = PRICING[model]
+    factor = 0.5 if batch else 1.0
+    cached = usage.input_tokens_details.cached_tokens
+    fresh = usage.input_tokens - cached
+    return (
+        fresh   * p["in"]    / 1_000_000 * factor +
+        cached  * p["cache"] / 1_000_000 * factor +
+        usage.output_tokens * p["out"]   / 1_000_000 * factor
+    )
+
+print(f"${cost(resp.usage, 'gpt-5.5'):.4f}")
+
const PRICING = {
+  "gpt-5.5":      { in: 5.00, cache: 0.50,  out: 30.00 },
+  "gpt-5.4-mini": { in: 0.75, cache: 0.075, out:  4.50 },
+  "gpt-5.4-nano": { in: 0.20, cache: 0.02,  out:  1.25 },
+} as const;
+
+function cost(u: any, model: keyof typeof PRICING, batch = false) {
+  const p = PRICING[model], factor = batch ? 0.5 : 1;
+  const cached = u.input_tokens_details?.cached_tokens ?? 0;
+  const fresh = u.input_tokens - cached;
+  return (fresh*p.in + cached*p.cache + u.output_tokens*p.out) / 1e6 * factor;
+}
+console.log("$", cost(resp.usage, "gpt-5.5").toFixed(4));
+
+ +

5.13 Limites, custos e checklist

+ +
+ + + + + + + + + + + + + +
Limites operacionais relevantes (2026-06-10)
ItemLimite
Payload do /v1/responses/input_tokensIdêntico ao /v1/responses — não há limite documentado próprio; o servidor recusa o que excederia o context window do modelo alvo 🔒
Arquivos por request (input_file)50 MB total combinado
Imagens por request≤ 1.500 inputs; payload total ≤ 512 MB 🔒
Imagem image_url via Chat Completions8 MB (acima disso é silenciosamente descartado) 🔒
Mínimo de tokens para cache hit1024 🔒
Granularidade do cache prefix-hash~256 tokens iniciais 🔒
Vazão por prompt_cache_key≈15 RPM antes de overflow 🔒
Janela de contexto gpt-5.5272K tokens (preço <272K nesta tabela)
+
+ +
+ Checklist de pré-flight em produção. +
    +
  1. Sempre que houver imagens, PDFs, tools ou MCP no payload, chame + /v1/responses/input_tokens antes do request real.
  2. +
  3. Compare pre.input_tokens com o limite do modelo; rejeite ou + degrade para gpt-5.4-mini antes de 90% da janela.
  4. +
  5. Pós-resposta, loggue usage.input_tokens, + output_tokens, cached_tokens e + reasoning_tokens em métrica/observability — esses 4 contadores + explicam 100% do custo.
  6. +
  7. Estabilize prefixo (instructions + tools + few-shot) para maximizar cached + tokens; use prompt_cache_key por tenant/rota.
  8. +
  9. Em streaming, capture o usage no evento response.completed / + último chunk; em disconnect, faça GET /v1/responses/{id}.
  10. +
  11. Para gpt-5.5, o default já é prompt_cache_retention: "24h" + — confirme se cabe na sua política de Data Residency / ZDR (cabe, ZDR não bloqueia 🔒).
  12. +
  13. Antes de batch grandes, rode o loop de input_tokens.count + sobre o JSONL para pegar outliers e ganhar 50% de desconto sem surpresas.
  14. +
+
+ +
+ Referências oficiais consultadas (2026-06-10, todas verificadas via MCP openaiDeveloperDocs): + +
+
+ + +
+
Gemini
+

Gemini deep-dive — token counting

+

No Gemini, contar tokens é uma capability de primeira classe e tem dois caminhos complementares: (1) pré-flight com client.models.count_tokens(...) — só conta o input e é grátis; (2) pós-call via response.usage_metadata — devolve input, output, thinking e cache. As duas chamadas aceitam o mesmo modelo de contents que generateContent, então qualquer combinação de text, inlineData, fileData, system instruction, tools e cachedContent pode ser estimada antes do request. Verificado em 2026-06-10 contra ai.google.dev/gemini-api/docs/tokens, media-resolution, video-understanding, files, caching, batch-api, pricing e gemini-3 (via MCP geminiApiDocs); itens não confirmados estão marcados UNVERIFIED 2026-06-10.

+ +
+ SDKs atuais. Use google-genai (Python) e @google/genai (JS/TS). Os pacotes legados google-generativeai / @google/generative-ai estão deprecated e não recebem novos campos do usage_metadata (ex.: thoughts_token_count). Modelos default neste guia: gemini-3.1-pro-preview (frontier) e gemini-3.5-flash (cost/latency). +
+ + + + +

Overview — o que é um token, dois caminhos de contagem

+

Para modelos Gemini, um token equivale a ~4 caracteres e 100 tokens ≈ 60–80 palavras em inglês (PT-BR e ES tendem a usar mais tokens por palavra). A tokenização cobre todas as modalidades — texto, imagem, áudio, vídeo, PDF — e cada modalidade tem regras próprias de conversão para tokens (ver abaixo).

+ +
+ + + + + + + +
Caminhos de contagem suportados pelo Gemini API
CaminhoRPC / SDKO que contaQuando usar
Pré-flightmodels.countTokens · client.models.count_tokens(...) · ai.models.countTokens(...)Apenas o input (totalTokens). Inclui system instruction, tools e cachedContent quando passados via generateContentRequest.Validar tamanho antes de gastar; cabe na janela? cabe no budget?
Pós-callresponse.usage_metadataInput + output + thinking + cache (campos detalhados por modalidade).Billing real, telemetria, dashboards de custo.
+
+ +

Ambos os caminhos são grátis — o countTokens não é cobrado e o usage_metadata vem embutido na resposta de generateContent. Custo real só ocorre quando o modelo de fato processa o request.

+ +

Campos do usage_metadata (Python snake_case / JS camelCase)

+
+ + + + + + + + + + + + +
Campos retornados em response.usage_metadata (após generateContent)
CampoSignificadoQuando aparece
prompt_token_count / promptTokenCountTokens efetivamente cobrados como input (system + history + user turn + tools + cached prefix re-contados).Sempre.
candidates_token_count / candidatesTokenCountTokens gerados como output visível ao usuário.Sempre que houve geração textual/JSON.
total_token_count / totalTokenCountInput + output + (thinking, quando exposto). Soma billable do request.Sempre.
thoughts_token_count / thoughtsTokenCountTokens consumidos no processo de thinking (chain-of-thought interno).Apenas em modelos com thinking ativo (família gemini-3.x).
cached_content_token_count / cachedContentTokenCountTokens lidos do cache (cobrados com desconto — ver §Cache).Quando há hit no cache implícito (Gemini 3 — único modo usado neste projeto).
prompt_tokens_details[] / promptTokensDetails[]Quebra do input por modalidade ({modality, tokenCount}): TEXT, IMAGE, AUDIO, VIDEO, DOCUMENT.Quando o input é multimodal.
cache_tokens_details[] / cacheTokensDetails[]Mesma quebra para o conteúdo cacheado.Quando há cache hit.
+
+ +
+ Math do total_token_count. Em modelos com thinking, total_token_count == prompt_token_count + candidates_token_count + thoughts_token_count. Se você só somar prompt+candidates vai dar diferente do que aparece no console de billing — confira sempre thoughts_token_count em gemini-3.x. Importante: o preço de output em Gemini 3 já inclui os thinking tokens (ver §Pricing). +
+ + + + +

Texto puro — basic + chat multi-turn

+

O caso mais simples: passa uma string (ou lista de Content) e recebe o totalTokens. Para chat multi-turn, o ponto crítico é anexar o próximo turno ao histórico antes de recontar — caso contrário você está medindo o passado, não o que vai ser cobrado.

+ +

Basic — Python & TypeScript

+
+
+ + +
+
+
from google import genai
+
+client = genai.Client()
+prompt = "The quick brown fox jumps over the lazy dog."
+
+# 1) Pré-flight — só input, grátis
+pre = client.models.count_tokens(model="gemini-3.5-flash", contents=prompt)
+print("pre-flight totalTokens:", pre.total_tokens)
+
+# 2) Pós-call — input + output + thinking
+resp = client.models.generate_content(model="gemini-3.5-flash", contents=prompt)
+print(resp.usage_metadata)
+# prompt_token_count=11, candidates_token_count=73, total_token_count=84
+
+
+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const prompt = "The quick brown fox jumps over the lazy dog.";
+
+const pre = await ai.models.countTokens({ model: "gemini-3.5-flash", contents: prompt });
+console.log("pre-flight totalTokens:", pre.totalTokens);
+
+const resp = await ai.models.generateContent({ model: "gemini-3.5-flash", contents: prompt });
+console.log(resp.usageMetadata);
+
+
+ +

Chat multi-turn — sempre anexe o próximo turno antes de recontar

+
+
+ + +
+
+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+chat = client.chats.create(
+    model="gemini-3.5-flash",
+    history=[
+        types.Content(role="user",  parts=[types.Part(text="Hi my name is Bob")]),
+        types.Content(role="model", parts=[types.Part(text="Hi Bob!")]),
+    ],
+)
+
+# Tamanho do histórico atual
+print(client.models.count_tokens(model="gemini-3.5-flash", contents=chat.get_history()))
+
+resp = chat.send_message(message="In one sentence, explain how a computer works to a young child.")
+print(resp.usage_metadata)
+
+# Para estimar o PRÓXIMO turno antes de enviar, anexe-o ao histórico
+next_turn = types.UserContent(parts=[types.Part(text="What is the meaning of life?")])
+history_plus = [*chat.get_history(), next_turn]
+print(client.models.count_tokens(model="gemini-3.5-flash", contents=history_plus))
+
+
+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const chat = ai.chats.create({
+  model: "gemini-3.5-flash",
+  history: [
+    { role: "user",  parts: [{ text: "Hi my name is Bob" }] },
+    { role: "model", parts: [{ text: "Hi Bob!" }] },
+  ],
+});
+
+const sizeNow = await ai.models.countTokens({ model: "gemini-3.5-flash", contents: chat.getHistory() });
+console.log(sizeNow.totalTokens);
+
+const r = await chat.sendMessage({ message: "In one sentence, explain how a computer works to a young child." });
+console.log(r.usageMetadata);
+
+const nextTurn = { role: "user", parts: [{ text: "What is the meaning of life?" }] };
+const combined = [...chat.getHistory(), nextTurn];
+const sizeNext = await ai.models.countTokens({ model: "gemini-3.5-flash", contents: combined });
+console.log("next-turn estimate:", sizeNext.totalTokens);
+
+
+ +

Streaming — usage_metadata só chega no chunk final

+

Com generate_content_stream, cada chunk é um GenerateContentResponse parcial. O usage_metadata normalmente só aparece preenchido no último chunk (quando finish_reason está setado). Capture e agregue dessa forma:

+ +
+
+ + +
+
+
from google import genai
+
+client = genai.Client()
+final_usage = None
+
+for chunk in client.models.generate_content_stream(
+    model="gemini-3.5-flash",
+    contents="Conte uma história curta sobre um dragão.",
+):
+    # Tokens em geração (pode aparecer só no fim)
+    if chunk.usage_metadata and chunk.usage_metadata.total_token_count:
+        final_usage = chunk.usage_metadata
+    if chunk.text:
+        print(chunk.text, end="", flush=True)
+
+print("
+
+Usage final:", final_usage)
+# Em streaming, total_token_count, candidates_token_count e thoughts_token_count
+# só ficam estáveis no chunk com finish_reason setado.
+
+
+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+let finalUsage: any = null;
+
+const stream = await ai.models.generateContentStream({
+  model: "gemini-3.5-flash",
+  contents: "Conte uma história curta sobre um dragão.",
+});
+
+for await (const chunk of stream) {
+  if (chunk.usageMetadata?.totalTokenCount) finalUsage = chunk.usageMetadata;
+  if (chunk.text) process.stdout.write(chunk.text);
+}
+console.log("
+
+Usage final:", finalUsage);
+
+
+ + + + +

Imagens — tabela media_resolution (Gemini 3) vs baseline 258 do count_tokens

+

Em Gemini 3, os tokens faturados por imagem vêm da tabela media_resolution, não de tiles de 258:

+
    +
  • Default / HIGH ⇒ 1120 tokens/imagem.
  • +
  • MEDIUM ⇒ 560 · LOW ⇒ 280 · ULTRA_HIGH (per-part) ⇒ 2240.
  • +
+ +
+ Cuidado com o 258. A regra tokens ≈ ceil(W/768) · ceil(H/768) · 258 (piso 258 para imagens ≤ 384×384) é o baseline genérico do count_tokens — uma estimativa, não o valor que Gemini 3 fatura. Em produção, o que conta é a tabela media_resolution (default 1120 tk/imagem). Como o countTokens aceita exatamente o mesmo contents de generateContent, é mais confiável chamar a API e ler o usage real do que estimar pelo 258. +
+ +

Baseline do count_tokens (estimativa de tiles 768×768 · 258 tk)

+
+ + + + + + + + + + + + +
Estimativa-baseline do count_tokens — não é o valor de produção do Gemini 3 (ver tabela media_resolution abaixo)
ResoluçãoTilesTokens (baseline)Observação
384×3841258piso (≤ 384×384)
768×7681258cabe em 1 tile
1024×7682516ceil(1024/768)·ceil(768/768) = 2·1
1536×102441 032ceil(1536/768)·ceil(1024/768) = 2·2
1920×108061 5483·2 tiles (HD landscape)
3072×2048123 0964·3 tiles
4096×4096369 2886·6 tiles — limite prático
+
+ +

Inline (PIL) e via Files API — Python & TypeScript

+
+
+ + +
+
+
from google import genai
+import PIL.Image
+
+client = genai.Client()
+prompt = "Tell me about this image"
+
+# --- Caminho A: inline via PIL ---
+img = PIL.Image.open("media/organ.jpg")
+pre_inline = client.models.count_tokens(
+    model="gemini-3.5-flash", contents=[prompt, img]
+)
+print("inline:", pre_inline.total_tokens)  # ~263 para uma imagem pequena
+
+# --- Caminho B: via Files API (recomendado > 20 MB ou reuso) ---
+up = client.files.upload(file="media/organ.jpg")
+pre_file = client.models.count_tokens(
+    model="gemini-3.5-flash", contents=[prompt, up]
+)
+print("files-api:", pre_file.total_tokens)
+
+resp = client.models.generate_content(
+    model="gemini-3.5-flash", contents=[prompt, up]
+)
+print(resp.usage_metadata)
+# prompt_token_count=1126, candidates_token_count=80, total_token_count=1206
+# prompt_tokens_details=[{modality: TEXT, tokenCount: 6}, {modality: IMAGE, tokenCount: 1120}]
+# (Gemini 3 default = 1120 tk/imagem; ~258 tk para 1 tile é só o baseline do count_tokens)
+
+
+
import { GoogleGenAI, createUserContent, createPartFromUri, createPartFromBase64 } from "@google/genai";
+import * as fs from "node:fs";
+
+const ai = new GoogleGenAI({});
+const prompt = "Tell me about this image";
+
+// Inline (base64)
+const b64 = fs.readFileSync("media/organ.jpg").toString("base64");
+const inline = createUserContent([prompt, createPartFromBase64(b64, "image/jpeg")]);
+const preInline = await ai.models.countTokens({ model: "gemini-3.5-flash", contents: inline });
+
+// Files API
+const up = await ai.files.upload({ file: "media/organ.jpg", config: { mimeType: "image/jpeg" } });
+const contents = createUserContent([prompt, createPartFromUri(up.uri, up.mimeType)]);
+const preFile = await ai.models.countTokens({ model: "gemini-3.5-flash", contents });
+const resp = await ai.models.generateContent({ model: "gemini-3.5-flash", contents });
+console.log(preInline.totalTokens, preFile.totalTokens, resp.usageMetadata);
+
+
+ + + + +

media_resolution — controle fino de tokens por imagem/frame/página (Gemini 3)

+

Modelos Gemini 3 introduzem o parâmetro media_resolution que define o número máximo de tokens alocados por imagem, frame de vídeo ou página de PDF. Pode ser setado globalmente no GenerationConfig (todos os modelos multimodais) ou per-part (Gemini 3 apenas, via API v1alpha). Per-part permite mistura — high para um diagrama complexo e low para uma imagem contextual — no mesmo request.

+ +
+ + + + + + + + + + +
Token counts por media_resolution em modelos Gemini 3 (oficial — ai.google.dev/gemini-api/docs/media-resolution#token-counts)
media_resolutionImagemVídeo (por frame)PDF (por página)
MEDIA_RESOLUTION_UNSPECIFIED (default Gemini 3)112070560
MEDIA_RESOLUTION_LOW28070280 + native text
MEDIA_RESOLUTION_MEDIUM56070560 + native text
MEDIA_RESOLUTION_HIGH11202801120 + native text
MEDIA_RESOLUTION_ULTRA_HIGH (per-part, v1alpha)2240N/AN/A
+
+ +
+ Pegadinha do vídeo em Gemini 3. LOW e MEDIUM custam o mesmo em vídeo (70 tk/frame) — comprimidos agressivamente para preservar contexto. Para diferenciar custo de vídeo é UNSPECIFIED/LOW/MEDIUM (70) vs HIGH (280) — não há ganho de upar de LOW para MEDIUM em vídeo. ULTRA_HIGH é exclusivo per-part e usado tipicamente em computer-use. +
+ +

Aplicando media_resolution global — Python & TypeScript

+
+
+ + +
+
+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+config = types.GenerateContentConfig(
+    media_resolution=types.MediaResolution.MEDIA_RESOLUTION_LOW,  # 280 tk/img — barato para thumbnails
+)
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=["Describe", my_img_part],
+    config=config,
+)
+print(resp.usage_metadata.prompt_tokens_details)
+# [{modality: TEXT, tokenCount: ...}, {modality: IMAGE, tokenCount: 280}]
+
+
+
import { GoogleGenAI, MediaResolution } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const resp = await ai.models.generateContent({
+  model: "gemini-3.1-pro-preview",
+  contents: ["Describe", myImgPart],
+  config: { mediaResolution: MediaResolution.MEDIA_RESOLUTION_LOW },
+});
+console.log(resp.usageMetadata?.promptTokensDetails);
+
+
+ +

Per-part (Gemini 3 + v1alpha) — misturar resoluções no mesmo request

+
+
+ + +
+
+
from google import genai
+from google.genai import types
+
+# Per-part só funciona em v1alpha
+client = genai.Client(http_options={"api_version": "v1alpha"})
+
+img_hi  = open("diagrama_denso.png", "rb").read()
+img_low = open("contexto_simples.jpg", "rb").read()
+
+part_hi  = types.Part.from_bytes(data=img_hi,  mime_type="image/png",
+                                 media_resolution=types.MediaResolution.MEDIA_RESOLUTION_HIGH)
+part_low = types.Part.from_bytes(data=img_low, mime_type="image/jpeg",
+                                 media_resolution=types.MediaResolution.MEDIA_RESOLUTION_LOW)
+
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=["Compare diagrama (denso) com a foto contextual.", part_hi, part_low],
+)
+print(resp.usage_metadata.prompt_tokens_details)
+# IMAGE total = 1120 (HIGH) + 280 (LOW) = 1400 tk
+
+
+
import { GoogleGenAI, MediaResolution } from "@google/genai";
+import * as fs from "node:fs";
+
+const ai = new GoogleGenAI({ httpOptions: { apiVersion: "v1alpha" } });
+const b64Hi  = fs.readFileSync("diagrama_denso.png").toString("base64");
+const b64Low = fs.readFileSync("contexto_simples.jpg").toString("base64");
+
+const partHi  = { inlineData: { mimeType: "image/png",  data: b64Hi  }, mediaResolution: { level: "MEDIA_RESOLUTION_HIGH" } };
+const partLow = { inlineData: { mimeType: "image/jpeg", data: b64Low }, mediaResolution: { level: "MEDIA_RESOLUTION_LOW" } };
+
+const resp = await ai.models.generateContent({
+  model: "gemini-3.1-pro-preview",
+  contents: [{ parts: [{ text: "Compare..." }, partHi, partLow] }],
+});
+console.log(resp.usageMetadata?.promptTokensDetails);
+
+
+ + + + +

Vídeo — Gemini 3: 70 tk/frame (HIGH 280) + 32 tk/s áudio ≈ 102 tk/s default

+

Por padrão, o Files API amostra vídeo a 1 FPS. Em Gemini 3, a tokenização de vídeo vem da tabela media_resolution (ai.google.dev/gemini-api/docs/media-resolution#token-counts):

+
    +
  • Cada frame (1 FPS): 70 tokens em UNSPECIFIED/LOW/MEDIUM; 280 tokens em HIGH.
  • +
  • Áudio: 32 tokens/segundo (single-channel, 1 kbps).
  • +
  • Metadados: incluídos.
  • +
  • Total Gemini 3: ~102 tk/s default · ~312 tk/s em HIGH.
  • +
+ +
+ 258 tk/frame é o baseline do count_tokens. O valor genérico de "258 tk/frame ≈ 300 tk/s" descrito no guia de video understanding é a estimativa-baseline do count_tokens — não o que Gemini 3 fatura em produção. O billing real segue a tabela media_resolution (70/280 tk/frame). Para 1M de janela, Gemini 3 aceita até 1 h de vídeo no default ou 3 h em LOW. Confirme sempre com o usage real. +
+ +
+ + + + + + + + + +
Custo de vídeo por duração — Gemini 3 (billing real) vs baseline do count_tokens
DuraçãoGemini 3 default (70 tk/frame + 32 tk/s áudio = ~102 tk/s)Gemini 3 HIGH (280 tk/frame + 32 tk/s = ~312 tk/s)Baseline count_tokens (~300 tk/s)
10 s~1 020~3 120~3 000
60 s~6 120~18 720~18 000
10 min~61 200~187 200~180 000
1 h~367 200~1 123 200~1 080 000
+
+ +

Upload via Files API — Python & TypeScript

+
+
+ + +
+
+
from google import genai
+import time
+
+client = genai.Client()
+f = client.files.upload(file="media/Big_Buck_Bunny.mp4")
+while not f.state or f.state.name != "ACTIVE":
+    time.sleep(5); f = client.files.get(name=f.name)
+
+pre = client.models.count_tokens(model="gemini-3.5-flash", contents=["Tell me about this video", f])
+print("video totalTokens (pre):", pre.total_tokens)
+
+resp = client.models.generate_content(model="gemini-3.5-flash", contents=["Tell me about this video", f])
+print(resp.usage_metadata)
+
+
+
import { GoogleGenAI, createUserContent, createPartFromUri } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+let v = await ai.files.upload({ file: "media/Big_Buck_Bunny.mp4", config: { mimeType: "video/mp4" } });
+while (!v.state || v.state.toString() !== "ACTIVE") {
+  await new Promise(r => setTimeout(r, 5000));
+  v = await ai.files.get({ name: v.name! });
+}
+const contents = createUserContent(["Tell me about this video", createPartFromUri(v.uri!, v.mimeType!)]);
+const pre = await ai.models.countTokens({ model: "gemini-3.5-flash", contents });
+const resp = await ai.models.generateContent({ model: "gemini-3.5-flash", contents });
+console.log(pre.totalTokens, resp.usageMetadata);
+
+
+ +

YouTube URL direto — fileData sem upload

+

Você pode passar URLs públicas do YouTube diretamente como Part sem subir nada via Files API. O countTokens aceita o mesmo payload. Em preview, atualmente sem cobrança extra; limites: 8 h/dia em tier free (sem limite no paid), até 10 vídeos/request na família Gemini 3, apenas vídeos públicos (não private/unlisted).

+ +
+
+ + +
+
+
from google import genai
+from google.genai import types
+
+client = genai.Client()
+
+# YouTube como Part — sem upload
+yt = types.Part(file_data=types.FileData(file_uri="https://www.youtube.com/watch?v=9hE5-98ZeCg"))
+
+# countTokens aceita YouTube URL diretamente
+pre = client.models.count_tokens(
+    model="gemini-3.5-flash",
+    contents=types.Content(parts=[yt, types.Part(text="Resuma em 3 frases.")]),
+)
+print("YouTube pre-flight:", pre.total_tokens)
+# Para vídeo de ~10 min: ~61k (Gemini 3 default); ~180k é o baseline do count_tokens
+
+# Cortar trecho — videoMetadata.start_offset / end_offset
+yt_clip = types.Part(
+    file_data=types.FileData(file_uri="https://www.youtube.com/watch?v=XEzRZ35urlk"),
+    video_metadata=types.VideoMetadata(start_offset="1250s", end_offset="1570s"),
+)
+resp = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=types.Content(parts=[yt_clip, types.Part(text="Resuma o trecho.")]),
+)
+print(resp.usage_metadata)
+
+
+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+
+const contents = [{
+  role: "user",
+  parts: [
+    { fileData: { fileUri: "https://www.youtube.com/watch?v=9hE5-98ZeCg", mimeType: "video/*" } },
+    { text: "Resuma em 3 frases." },
+  ],
+}];
+
+const pre = await ai.models.countTokens({ model: "gemini-3.5-flash", contents });
+console.log("YouTube pre-flight:", pre.totalTokens);
+
+// Com clipping
+const clipped = [{
+  role: "user",
+  parts: [
+    { fileData: { fileUri: "https://www.youtube.com/watch?v=XEzRZ35urlk", mimeType: "video/*" },
+      videoMetadata: { startOffset: "1250s", endOffset: "1570s" } },
+    { text: "Resuma o trecho." },
+  ],
+}];
+const resp = await ai.models.generateContent({ model: "gemini-3.5-flash", contents: clipped });
+console.log(resp.usageMetadata);
+
+
+ +
+ Live API tem billing próprio. A Live API (sessões bidirecionais de áudio/vídeo em tempo real) não é cobrada via usage_metadata com o mesmo preço de generateContent — usa cobrança por minuto de sessão, e os campos de usage podem aparecer parciais. Para reconciliar custo, combine: (a) telemetria interna do servidor Live API, (b) usage_metadata nos turn-level responses quando expostos, (c) tabela de pricing dedicada da Live API. Se você não usa Live API, ignore — o generateContent normal cobra como descrito aqui. Live API faz billing por minuto (input ~$0,005/min, output ~$0,018/min em gemini-3.1-flash-live-preview) com sua própria contabilidade — o shape de usage_metadata entre turns dentro da sessão segue o da Gemini API normal. Consulte ai.google.dev/gemini-api/docs/live para a billing reference autoritativa. +
+ + + + +

Áudio — 32 tokens/segundo

+

Áudio é tokenizado a 32 tokens por segundo de duração, independentemente da modalidade ou formato (MP3/WAV/FLAC/AAC/OGG/AIFF). Equivalências práticas:

+
    +
  • 1 minuto ≈ 1 920 tokens.
  • +
  • 10 minutos ≈ 19 200 tokens.
  • +
  • 1 hora ≈ 115 200 tokens — cabe folgado em modelos com janela ≥ 128k.
  • +
  • 9,5 horas ≈ 1 094 400 tokens — limite prático em modelos de 1M de janela.
  • +
+ +
up = client.files.upload(file="meeting.mp3")
+pre = client.models.count_tokens(
+    model="gemini-3.5-flash",
+    contents=["Transcreva e resuma.", up],
+)
+print(pre.total_tokens)  # ≈ 32 * duração_em_segundos + texto
+ + + + +

PDF / documentos — page-as-image + texto nativo

+

Gemini processa cada página de PDF como uma imagem + o texto OCR/nativo extraído. Em Gemini 3 o default é 560 tokens/página (com texto nativo incluso grátis); media_resolution ajusta o componente de imagem (280 / 560 / 1120). Limites duros do Files API para PDF: 50 MB por arquivo e 1 000 páginas. O recomendado oficial para PDF é MEDIA_RESOLUTION_MEDIUM — qualidade já satura nesse nível para documentos comuns.

+ +
pdf = client.files.upload(file="contrato.pdf")
+pre = client.models.count_tokens(
+    model="gemini-3.5-flash",
+    contents=["Resuma este documento.", pdf],
+)
+print(pre.total_tokens)
+
+resp = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=["Resuma este documento.", pdf],
+)
+print(resp.usage_metadata.prompt_tokens_details)
+# [{modality: DOCUMENT, tokenCount: N}, {modality: TEXT, tokenCount: ...}]
+ + + + +

Multimodal real — promptTokensDetails por modalidade

+

Quando o request combina TEXT + IMAGE + VIDEO + AUDIO + DOCUMENT, o response.usage_metadata.prompt_tokens_details volta como um array com a quebra exata por modalidade. Útil para alocar custo a cada componente e para auditoria de billing.

+ +
+
+ + +
+
+
from google import genai
+from google.genai import types
+import time
+
+client = genai.Client()
+img   = client.files.upload(file="diagrama.png")
+audio = client.files.upload(file="meeting.mp3")
+pdf   = client.files.upload(file="contrato.pdf")
+video = client.files.upload(file="call.mp4")
+for f in (img, audio, pdf, video):
+    while not f.state or f.state.name != "ACTIVE":
+        time.sleep(3); f = client.files.get(name=f.name)
+
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=["Analise tudo:", img, audio, pdf, video],
+)
+um = resp.usage_metadata
+print("total:", um.total_token_count)
+for d in um.prompt_tokens_details:
+    print(f"  {d.modality}: {d.token_count}")
+# Exemplo de saída:
+#   TEXT:      14
+#   IMAGE:     1120     (Gemini 3 default)
+#   AUDIO:     5760     (180s · 32)
+#   DOCUMENT:  5600     (10 páginas · 560)
+#   VIDEO:     6120     (60s · ~102 tk/s default Gemini 3)
+
+
+
import { GoogleGenAI, createUserContent, createPartFromUri } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const upload = async (file: string, mt: string) => {
+  let f = await ai.files.upload({ file, config: { mimeType: mt } });
+  while (!f.state || f.state.toString() !== "ACTIVE") {
+    await new Promise(r => setTimeout(r, 3000));
+    f = await ai.files.get({ name: f.name! });
+  }
+  return f;
+};
+
+const img   = await upload("diagrama.png", "image/png");
+const audio = await upload("meeting.mp3", "audio/mpeg");
+const pdf   = await upload("contrato.pdf", "application/pdf");
+const video = await upload("call.mp4", "video/mp4");
+
+const contents = createUserContent([
+  "Analise tudo:",
+  createPartFromUri(img.uri!,   img.mimeType!),
+  createPartFromUri(audio.uri!, audio.mimeType!),
+  createPartFromUri(pdf.uri!,   pdf.mimeType!),
+  createPartFromUri(video.uri!, video.mimeType!),
+]);
+
+const resp = await ai.models.generateContent({ model: "gemini-3.1-pro-preview", contents });
+console.log(resp.usageMetadata?.promptTokensDetails);
+
+
+ + + + +

System instruction — entra no count (e pode ser multimodal)

+

System instruction é cobrada como input e contada quando você passa um generateContentRequest completo ao countTokens (não funciona se você só passa contents=[...] e a config separada — em Python/TS use sempre o parâmetro config em ambas as chamadas). Padrão atual:

+ +
from google import genai
+from google.genai import types
+
+client = genai.Client()
+config = types.GenerateContentConfig(
+    system_instruction="Você é um gato chamado Neko. Responda como um gato.",
+)
+
+# Para incluir system + tools no count, passe a request completa via generate_content_config
+pre = client.models.count_tokens(
+    model="gemini-3.5-flash",
+    contents=["Good morning! How are you?"],
+    config=config,
+)
+print(pre.total_tokens)
+
+resp = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents=["Good morning! How are you?"],
+    config=config,
+)
+print(resp.usage_metadata)
+ +

System instruction multimodal (não recomendado, mas suportado)

+

Tecnicamente system_instruction aceita um Content com múltiplas Part, incluindo imagens. Isso eleva o custo da system instruction porque ela é re-cobrada a cada request. Use apenas se a imagem é genuinamente parte da persona/regra do sistema (ex.: logo de marca para style transfer). Caso contrário passe imagem como user content.

+ +
from google import genai
+from google.genai import types
+
+client = genai.Client()
+logo = client.files.upload(file="brand_logo.png")
+
+config = types.GenerateContentConfig(
+    system_instruction=types.Content(parts=[
+        types.Part(text="Use sempre este estilo visual de referência:"),
+        types.Part(file_data=types.FileData(file_uri=logo.uri, mime_type=logo.mime_type)),
+    ]),
+)
+pre = client.models.count_tokens(
+    model="gemini-3.1-pro-preview",
+    contents="Crie um título de capa.",
+    config=config,
+)
+print(pre.total_tokens)  # inclui IMAGE da system_instruction (1120 tk em Gemini 3 default)
+ + + + +

Tools — function declarations contam

+

Schemas de tools (function declarations) são serializados e adicionados ao prompt — portanto contam como input tokens. Vale para tools nativas do Gemini também (googleSearch, urlContext, codeExecution), embora a sobrecarga delas seja pequena. Passe os tools via config e o countTokens medirá com eles incluídos.

+ +
from google.genai import types
+
+multiply = types.FunctionDeclaration(
+    name="multiply",
+    description="Returns a * b.",
+    parameters={
+        "type": "object",
+        "properties": {"a": {"type": "number"}, "b": {"type": "number"}},
+        "required": ["a", "b"],
+    },
+)
+
+config = types.GenerateContentConfig(tools=[types.Tool(function_declarations=[multiply])])
+pre = client.models.count_tokens(
+    model="gemini-3.5-flash",
+    contents=["What is 13 * 17?"],
+    config=config,
+)
+print("com tools:", pre.total_tokens)
+ + + + +

Thinking — thinking_level e thoughts_token_count

+

Os modelos da família Gemini 3 usam thinking dinâmico. O parâmetro oficial é thinking_level (substitui o legado thinking_budget — usar ambos no mesmo request retorna 400). Os níveis (oficial — ai.google.dev/gemini-api/docs/gemini-3):

+ +
+ + + + + + + + + +
Suporte de thinking_level por modelo Gemini 3 (oficial)
Level3.1 Pro3.1 Flash-Lite3 Flash / 3.5 FlashDescrição
minimal—✓ (default)✓"No thinking" para a maioria das queries; pode ainda pensar minimamente em código complexo. Minimiza latência.
low✓✓✓Minimiza latência e custo. Bom para instrução simples, chat, alta vazão.
medium✓✓✓Balanceado.
high✓ (default, dinâmico)✓ (dinâmico)✓ (default, dinâmico)Profundidade máxima — tempo de primeira resposta sobe, qualidade idem.
+
+ +
+ Estes níveis são limites máximos, não garantias. Gemini 3 trata thinking_level como relative allowance — o modelo pode usar muito menos thinking se a query for simples. Não há tabela oficial de "fator empírico" por nível porque o consumo real depende do prompt; meça em runs de calibração e use thoughts_token_count como verdade absoluta. A doc oficial não publica fator determinístico (do tipo "medium = 2x low") porque o consumo real depende do prompt — sempre meça em runs de calibração no seu workload específico. +
+ +
from google import genai
+from google.genai import types
+
+client = genai.Client()
+config = types.GenerateContentConfig(
+    thinking_config=types.ThinkingConfig(thinking_level="high"),  # minimal|low|medium|high
+)
+resp = client.models.generate_content(
+    model="gemini-3.5-flash",
+    contents="Prove que sqrt(2) é irracional.",
+    config=config,
+)
+um = resp.usage_metadata
+print("input:",     um.prompt_token_count)
+print("thinking:", um.thoughts_token_count)   # > 0 quando thinking ativo
+print("output:",    um.candidates_token_count)
+print("total:",     um.total_token_count)
+assert um.total_token_count == um.prompt_token_count + um.thoughts_token_count + um.candidates_token_count
+ +
+ Pre-flight não enxerga thinking. count_tokens sempre conta apenas input. Para orçar thinking, multiplique candidates_token_count esperado por um fator empírico (medido em runs de calibração) ou aceite a regra do pricing: em Gemini 3 o preço de output já inclui thinking — então o custo de output que você fatura é (candidates + thoughts) · preço_output (com tabela na §Pricing). +
+ + + + +

Context caching — implícito automático (escopo do projeto)

+ +
+ Escopo do projeto: apenas implicit caching. Explicit cachedContents existe na API (client.caches.create / Vertex Context Cache REST) mas está fora de escopo deste guia — não criar, não nomear, não referenciar. Toda a otimização vem do reuso de prefixo estável dentro da janela RAM do serviço (§10.3 e §10.5). +
+ +

Cache implícito é automático para prefixos repetidos na família Gemini 3 (Developer API e Vertex). O response.usage_metadata traz cached_content_token_count indicando quantos tokens vieram do cache (cobrados com desconto vs. tokens novos). Nada a configurar, nomear ou deletar.

+ +
+ + + + + + + + +
Limites de cache implícito (Gemini 3 — oficial)
ModeloMin token limit p/ implicit hit — Developer APIMin token limit p/ implicit hit — Vertex
gemini-3.5-flash / gemini-3-flash-preview1 0244 096
gemini-3.1-pro-preview4 0964 096
gemini-3.1-flash-lite1 0244 096
+
+ +

Cache implícito — observação automática (sem código de setup)

+

Na família Gemini 3, prefixos comuns repetidos em curto intervalo geram cache hit automaticamente. A única forma de observar é olhar cached_content_token_count na segunda chamada idêntica. Em sequência:

+ +
from google import genai
+
+client = genai.Client()
+big = "... 5 000 tokens de instrução repetida ..."
+
+# Primeira chamada: cache miss (cached_content_token_count == 0)
+r1 = client.models.generate_content(model="gemini-3.5-flash", contents=[big, "P1"])
+print("r1 cached:", r1.usage_metadata.cached_content_token_count)  # 0
+
+# Segunda chamada idêntica em segundos: cache hit implícito
+r2 = client.models.generate_content(model="gemini-3.5-flash", contents=[big, "P2"])
+print("r2 cached:", r2.usage_metadata.cached_content_token_count)  # > 0
+# Cache implícito é in-memory (RAM-only, opaca, project+region-isolada) e não viola ZDR.
+ +
+ Billing do cache implícito. prompt_token_count inclui o conteúdo cacheado (o modelo ainda o lê); cached_content_token_count diz quanto desse total caiu na faixa de desconto. Custo efetivo do input = (prompt_token_count − cached_content_token_count) · preço_input + cached_content_token_count · preço_cache_read. Não há SKU de storage para implicit (RAM-only). Para detalhamento operacional cross-provider, ver §10.3 (Developer API) e §10.5 (Vertex). +
+ + + + +

Pricing — preço por 1M tokens (Standard tier, paid)

+

Preços oficiais de ai.google.dev/gemini-api/docs/pricing (verificado 2026-06-10). Tier Standard / Paid; valores per 1M tokens USD. Storage de cache é cobrado à parte, geralmente em $/(1M tokens · hora).

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
Gemini 3 — preços Standard / paid (Batch = 50% off, Flex ≈ 50% off, Priority = +80%: $2.70 in / $16.20 out em gemini-3.5-flash). Coluna "Cache storage/h" omitida — implicit caching não cobra storage (RAM-only).
ModeloInputOutput (inclui thinking)Cache read (implicit)
gemini-3.1-pro-preview$2.00 (≤200k)
$4.00 (>200k)
$12.00 (≤200k)
$18.00 (>200k)
$0.20 (≤200k)
$0.40 (>200k)
gemini-3.5-flash$1.50$9.00$0.15
gemini-3.1-flash-lite$0.25 (text/image/video)
$0.50 (audio)
$1.50$0.025 (text/image/video)
$0.05 (audio)
+
+ +
+ + + + + + + + + +
Service tiers — multiplicadores aplicados sobre o Standard (verificado para gemini-3.5-flash)
TierInputOutputCache readSLO / nota
Standard$1.50$9.00$0.15baseline
Batch (50% off)$0.75$4.50$0.07524h SLO, JSONL ou inline (até 20MB)
Flex$0.75$4.50$0.08same price as Batch, real-time
Priority (+80%)$2.70$16.20$0.27latência baixa, alta prioridade
+
+ +

Multiplicador Batch = 50% de Standard vale também para gemini-3.1-pro-preview e gemini-3.1-flash-lite — confirmado em pricing oficial. Service tiers Flex/Priority são opt-in com tabela própria — não inclusos acima. Consulte ai.google.dev/gemini-api/docs/pricing para os multiplicadores correntes antes de subir produção.

+ + + + +

Batch API — pré-contar JSONL e 50% off

+

A Batch API (client.batches.create(...)) processa volumes grandes de forma assíncrona a 50% do preço Standard, com SLO de 24 h (na prática muito mais rápido). Aceita dois formatos: inline (lista de GenerateContentRequest com tamanho total < 20 MB) ou JSONL (recomendado para volume; arquivo até 2 GB via Files API). Para auditoria de custo, faça pré-flight de cada request antes de submeter — depois agregue.

+ +

Pré-contar um job JSONL antes de submeter

+
+
+ + +
+
+
import json
+from google import genai
+from google.genai import types
+
+client = genai.Client()
+MODEL = "gemini-3.5-flash"
+
+# 1) Construir requests + pré-flight de cada uma
+requests = [
+    {"key": "r1", "request": {"contents": [{"parts": [{"text": "Resuma a fotossíntese."}]}]}},
+    {"key": "r2", "request": {"contents": [{"parts": [{"text": "Ingredientes da pizza margherita?"}]}]}},
+]
+total_input = 0
+for r in requests:
+    pre = client.models.count_tokens(model=MODEL, contents=r["request"]["contents"])
+    total_input += pre.total_tokens
+print(f"input pré-flight do batch: {total_input} tk")
+# Custo estimado: total_input * $1.50/1M * 0.5 (batch discount) + output estimado * $9.00/1M * 0.5
+
+# 2) Gravar JSONL e subir
+with open("batch.jsonl", "w", encoding="utf-8") as f:
+    for r in requests:
+        f.write(json.dumps(r) + "
+")
+
+up = client.files.upload(
+    file="batch.jsonl",
+    config=types.UploadFileConfig(display_name="my-batch", mime_type="jsonl"),
+)
+
+# 3) Criar batch job
+job = client.batches.create(
+    model=MODEL,
+    src=up.name,
+    config={"display_name": "summarize-job"},
+)
+print("batch:", job.name)
+
+# 4) Quando completar, somar usage_metadata de cada resposta no JSONL de saída
+# for line in download(result_file).splitlines():
+#     resp = json.loads(line)
+#     um = resp["response"]["usageMetadata"]
+#     ...
+
+
+
import { GoogleGenAI } from "@google/genai";
+import * as fs from "node:fs";
+
+const ai = new GoogleGenAI({});
+const MODEL = "gemini-3.5-flash";
+
+const requests = [
+  { key: "r1", request: { contents: [{ parts: [{ text: "Resuma a fotossíntese." }] }] } },
+  { key: "r2", request: { contents: [{ parts: [{ text: "Ingredientes da pizza margherita?" }] }] } },
+];
+
+let totalInput = 0;
+for (const r of requests) {
+  const pre = await ai.models.countTokens({ model: MODEL, contents: r.request.contents });
+  totalInput += pre.totalTokens!;
+}
+console.log("input pré-flight:", totalInput);
+
+fs.writeFileSync("batch.jsonl", requests.map(r => JSON.stringify(r)).join("
+") + "
+");
+const up = await ai.files.upload({ file: "batch.jsonl", config: { mimeType: "jsonl" } });
+
+const job = await ai.batches.create({
+  model: MODEL,
+  src: up.name!,
+  config: { displayName: "summarize-job" },
+});
+console.log("batch:", job.name);
+
+
+ +
+ Caching em Batch. Context caching está habilitado em batch requests; cache hits são cobrados ao mesmo preço de cache-read do Standard (não ao preço Standard input). Combinar batch (50% off) + cache (≈10% do input) é o jeito mais barato de processar grandes volumes com prompt repetido. Batch é não-idempotente — não envie a mesma creation request duas vezes ou criará dois jobs distintos. +
+ + + + +

Vertex AI backend — counting é igual?

+

A partir do google-genai SDK, o mesmo client roda contra Gemini Developer API (default) ou contra Vertex AI / Gemini Enterprise Agent Platform apenas trocando flags. O contrato de count_tokens e usage_metadata é o mesmo, mas auth, regions, pricing e algumas features divergem.

+ +
+
+ + +
+
+
from google import genai
+
+# Gemini Developer API (default)
+dev = genai.Client()  # usa GEMINI_API_KEY
+
+# Vertex AI / Gemini Enterprise Agent Platform
+vx = genai.Client(
+    vertexai=True,
+    project="meu-projeto",
+    location="us-central1",
+)
+
+prompt = "The quick brown fox jumps over the lazy dog."
+
+print(dev.models.count_tokens(model="gemini-3.5-flash", contents=prompt).total_tokens)
+print(vx.models.count_tokens (model="gemini-3.5-flash", contents=prompt).total_tokens)
+# Mesmo resultado: a tokenização é determinística pelo modelo, não pelo backend.
+
+
+
import { GoogleGenAI } from "@google/genai";
+
+const dev = new GoogleGenAI({});  // GEMINI_API_KEY
+const vx  = new GoogleGenAI({ vertexai: true, project: "meu-projeto", location: "us-central1" });
+
+const prompt = "The quick brown fox jumps over the lazy dog.";
+console.log((await dev.models.countTokens({ model: "gemini-3.5-flash", contents: prompt })).totalTokens);
+console.log((await vx.models.countTokens ({ model: "gemini-3.5-flash", contents: prompt })).totalTokens);
+
+
+ +
+ Diferenças relevantes Vertex vs Developer API. +
    +
  • Auth. Vertex usa service accounts (ADC) — não API key.
  • +
  • Pricing. Vertex tem tabela própria, geralmente alinhada com a Gemini Developer API mas com diferenças em provisioned throughput e cobrança em moeda local; trate a §Pricing acima como referência da Gemini Developer API e consulte cloud.google.com/vertex-ai/generative-ai/pricing para Vertex.
  • +
  • Regions. Vertex permite escolha de região (compliance/latência); Developer API é multi-region gerenciada.
  • +
  • Tokenização. Igual — mesmo modelo, mesmo tokenizer, mesma contagem.
  • +
  • Features. YouTube URL, Files API e Batch existem em ambos com payloads idênticos no SDK google-genai.
  • +
+
+ + + + +

Context window — descobrir limite via models.get + Files API limits

+

Em vez de hardcodar limites por modelo (que mudam), consulte client.models.get(...) e use input_token_limit / output_token_limit. Esse é o jeito canônico de validar se o request cabe.

+ +
+ + + + + + + + + + + + + + + + +
Janelas e limites de Files API (oficial — verificado 2026-06-10)
RecursoLimiteFonte
Gemini 3.1 Pro / 3.5 Flash / 3.1 Flash-Lite — context1 M input / 64 k outputai.google.dev/gemini-api/docs/gemini-3
Files API — máx por arquivo2 GBai.google.dev/gemini-api/docs/files
Files API — storage por projeto20 GBidem
Files API — retenção48 hidem (auto-delete; download não disponível)
Threshold para upload obrigatório100 MB total requestidem (50 MB para PDFs)
PDF — máx páginas1 000via Files API
Batch — JSONL máx2 GBai.google.dev/gemini-api/docs/batch-api
Batch — inline máx20 MBidem
Batch — SLO turnaround24 hidem (job expira em 48 h)
YouTube — máx vídeos/request (Gemini 3)10ai.google.dev/gemini-api/docs/video-understanding
YouTube — free tier8 h/diaidem
+
+ +
+
+ + +
+
+
from google import genai
+
+client = genai.Client()
+info = client.models.get(model="gemini-3.5-flash")
+print("input_token_limit:",  info.input_token_limit)
+print("output_token_limit:", info.output_token_limit)
+
+# Padrão defensivo: estimar e validar antes
+pre = client.models.count_tokens(model="gemini-3.5-flash", contents=meu_prompt)
+if pre.total_tokens > info.input_token_limit - 2000:  # headroom p/ output
+    raise ValueError("prompt grande demais — comprima ou use chunking")
+
+
+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const info = await ai.models.get({ model: "gemini-3.5-flash" });
+console.log(info.inputTokenLimit, info.outputTokenLimit);
+
+const pre = await ai.models.countTokens({ model: "gemini-3.5-flash", contents: meuPrompt });
+if (pre.totalTokens! > info.inputTokenLimit! - 2000) {
+  throw new Error("prompt grande demais");
+}
+
+
+ +

Resposta REST de countTokens (JSON)

+

Endpoint: POST https://generativelanguage.googleapis.com/v1beta/models/{model}:countTokens. O corpo pode ser {"contents": [...]} (mais simples) ou {"generateContentRequest": {...}} (para incluir systemInstruction, tools e cachedContent). Os dois são mutuamente exclusivos. Resposta:

+ +
{
+  "totalTokens": 1284,
+  "cachedContentTokenCount": 980,
+  "promptTokensDetails": [
+    { "modality": "TEXT",  "tokenCount": 304 },
+    { "modality": "IMAGE", "tokenCount": 1120 }
+  ],
+  "cacheTokensDetails": [
+    { "modality": "DOCUMENT", "tokenCount": 980 }
+  ]
+}
+ +
+ Custo. Tanto countTokens quanto usage_metadata são gratuitos — você só paga quando generateContent processa o request. Use o pré-flight liberalmente em pipelines de RAG, batch jobs e UIs que mostram custo estimado. Preços por modalidade/modelo: ai.google.dev/gemini-api/docs/pricing. +
+ +

Checklist final

+
    +
  • Pré-flight com count_tokens antes de submeter requests grandes (multimodais, batches, RAG).
  • +
  • Pós-call: leia usage_metadata e some thoughts_token_count em modelos com thinking (Gemini 3 fatura output incluindo thinking).
  • +
  • Para system instruction / tools / cached content entrarem na contagem pré-flight, passe-os via config (Python) / config (TS) / generateContentRequest (REST).
  • +
  • Imagens: em Gemini 3, media_resolution (default 1120 tk/img). A regra de 258 tk/tile é só o baseline do count_tokens.
  • +
  • Vídeo: Gemini 3 usa 70 tk/frame (HIGH 280) + 32 tk/s áudio ≈ 102 tk/s default; o 258 tk/frame ≈ 300 tk/s é o baseline do count_tokens.
  • +
  • YouTube: passe a URL direta em file_data — sem upload, sem custo extra em preview (8 h/dia free, até 10 vídeos/request na família Gemini 3).
  • +
  • Áudio: 32 tk/s — multiplique pela duração.
  • +
  • PDF: page-as-image (560 tk/pág default) + native text (grátis em Gemini 3); cap: 50 MB / 1 000 páginas.
  • +
  • Cache: implícito automático na família Gemini 3 (min 1024 Flash/Lite, 4096 Pro na Developer API; 4096 unificado na Vertex). Sem fee de write, sem storage — RAM-only. Explicit cachedContents fora do escopo deste guia (ver §10.3).
  • +
  • Batch API: 50% off, JSONL até 2 GB, SLO 24 h, suporta cache.
  • +
  • Vertex AI: vertexai=True mantém mesmo contrato de tokens e usage_metadata.
  • +
  • Streaming: usage_metadata só estável no chunk final.
  • +
  • Live API: billing por minuto separado — não confunda com generateContent.
  • +
  • Janela do modelo: client.models.get(...).input_token_limit — nunca hardcode.
  • +
+
+ + + +
+
Gemini · Interactions
+

Gemini Interactions API — token counting deep-dive

+

+ A Interactions API (lançada em Dez/2025, atualmente em v1beta no Gemini Developer API) é o novo padrão recomendado pelo Google para fluxos agênticos e conversas multimodais multiturno. Ela substitui — para projetos novos — o velho fluxo generateContent, mantém o estado da conversa no servidor (via previous_interaction_id) e devolve uma timeline tipada de steps[]. Como consequência, todo o esquema de contagem de tokens muda: o objeto usage_metadata (com sufixo _count) vira usage (com prefixo total_*_tokens), o breakdown por modalidade passa a usar nomes em snake_case alinhados ao vocabulário da Responses API da OpenAI, e novos campos aparecem para grounding e tools server-side. +

+

+ Esta seção é o espelho exaustivo da seção Gemini existente (deep-dive de generateContent) aplicada à Interactions API. Todos os preços por modalidade, os limites por arquivo e o pricing por modelo são idênticos aos de generateContent — o que muda é exclusivamente o shape do response (e o cronograma de breaking changes de Maio–Junho 2026, já consumado — ver §G·migration). +

+
+ Beta — não usar em produção crítica. A documentação oficial recomenda explicitamente: "Para cargas de trabalho de produção, continue usando a API padrão generateContent." Use Interactions API para projetos novos, fluxos agênticos, Deep Research / Deep Think, multimodal multiturno com cache implícito automático, e quando precisar de cancelamento server-side ou tarefas em background. O schema legado foi removido em 2026-06-08 — steps[] é hoje o único schema aceito, e a página oficial de migração já chama a Interactions API de "the standard interface for building with Gemini", recomendando-a para todo desenvolvimento novo. +
+ + + + +

G·overview Endpoint, SDK e quando usar

+

A Interactions API tem 4 operações REST canônicas (verificado em ai.google.dev/api/interactions-api, 2026-06-10):

+
+ + + + + + + + + +
Endpoints REST da Interactions API (base: https://generativelanguage.googleapis.com)
OperaçãoMétodoPathCounting relevante
Criar interaçãoPOST/v1beta/interactionsDevolve usage no response final.
RecuperarGET/v1beta/interactions/{id}Inclui usage persistido; aceita stream=true + last_event_id.
ExcluirDELETE/v1beta/interactions/{id}Apaga estado server-side (perde futuro hit de cache implícito).
CancelarPOST/v1beta/interactions/{id}/cancelAplica-se a background=true (Deep Research / Deep Think).
+
+

O path canônico é v1beta/interactions: a referência oficial (ai.google.dev/api/interactions-api), o guia e a página de streaming usam essa forma. Apenas o guia de migração mostra v1beta2/interactions, o que é uma discrepância documental confirmada em 2026-06-10 — adote v1beta.

+ +

SDKs e versões mínimas

+
+ + + + + + + +
LinguagemPacoteVersão mínima (legado)Versão obrigatória desde 2026-06-08
Pythongoogle-genai>= 1.55.0 (Interactions; confirmado em ai.google.dev/gemini-api/docs/interactions) · versão mínima específica p/ Deep Research UNVERIFIED (não documentada oficialmente até 2026-06-10)>= 2.0.0
JavaScript / TypeScript@google/genai1.33.0>= 2.0.0
REST puro—header Api-Revision: 2026-05-20 (opt-in)header ignorado; schema novo é o único disponível
+
+ +

Quando usar Interactions vs. generateContent (do ponto de vista de token counting)

+
+ + + + + + + + + + + + + +
CenárioAPI recomendadaPor quê (counting)
Novo projeto / fluxo agênticoInteractionsusage traz breakdown unificado por modalidade + grounding count.
Produção estável existentegenerateContentSchema usage_metadata não muda; dashboards atuais continuam funcionando.
Batch API (50% de desconto)generateContentBatch não suportado em Interactions.
Cache implícito (prefixo estável + Gemini 3)generateContentImplicit hit automático quando o prefixo atinge o min do modelo. Interactions sob store=false (padrão do projeto) tem total_cached_tokens ≈ 0 — ver §10.4.
Conversas multiturno com cache implícito visívelgenerateContentHit em cached_content_token_count sem código adicional; Interactions só ativaria via previous_interaction_id, bloqueado por store=false.
Deep Research / Deep ThinkInteractionsbackground=true só existe aqui; tokens de loops agentic entram em total_*_tokens normais.
Auto function calling em PythongenerateContentEm Interactions o round-trip é manual (cliente recebe function_call e devolve function_result).
Vídeo com FPS / offsets customizadosgenerateContentInteractions não aceita video_metadata customizado.
Vertex AIgenerateContentInteractions UNVERIFIED (não documentada oficialmente em Vertex até 2026-06-10); anunciada como "coming soon".
+
+ + + + +

G·mapping Mapping usage_metadata → usage

+

O mapping abaixo é a peça mais útil desta seção para times migrando dashboards de billing. Cada coluna mostra o nome legado (no generateContent, vigente desde sempre) e o nome novo (no interaction.usage da Interactions API). Os valores calculados pelas duas APIs são idênticos para o mesmo input — só o nome do campo muda.

+
+ + + + + + + + + + + + + + + + +
Tabela canônica de equivalências (verificado 2026-06-10, fonte: ai.google.dev/api/interactions-api + migrate-to-interactions)
SignificadogenerateContent · response.usage_metadataInteractions API · interaction.usage
Tokens do input (todas as modalidades agregadas)prompt_token_count · promptTokenCounttotal_input_tokens
Tokens gerados como output visívelcandidates_token_count · candidatesTokenCounttotal_output_tokens
Tokens lidos do cache (com desconto)cached_content_token_count · cachedContentTokenCounttotal_cached_tokens
Tokens de thinking (chain-of-thought interno)thoughts_token_count · thoughtsTokenCounttotal_thought_tokens
Tokens de tools server-sidetool_use_prompt_token_count · toolUsePromptTokenCounttotal_tool_use_tokens
Soma billable agregadatotal_token_count · totalTokenCounttotal_tokens
Breakdown do input por modalidadeprompt_tokens_details[] · promptTokensDetails[]input_tokens_by_modality[]
Breakdown do output por modalidadecandidates_tokens_details[] · candidatesTokensDetails[]output_tokens_by_modality[]
Breakdown do cache por modalidadecache_tokens_details[] · cacheTokensDetails[]cached_tokens_by_modality[]
Breakdown dos tokens de tools (novo)—tool_use_tokens_by_modality[]
Quantidade de chamadas de grounding(via grounding_metadata separado)grounding_tool_count
+
+

Observe que o campo de detalhes por modalidade também muda de nome interno: o objeto era ModalityTokenCount {modality, tokenCount} em generateContent e agora é ModalityTokens {modality, tokens} em Interactions (campo tokens no JSON REST, conforme ai.google.dev/api/interactions-api). No SDK Python o tipo ModalityTokenCount expõe o contador como atributo .token_count (ver a referência do google-genai), enquanto o JSON REST devolve tokens — valide o atributo no objeto retornado pelo seu SDK. O conjunto de modalidades aceitas é o mesmo, mas o enum no JSON REST é minúsculo: text, image, audio, video, document.

+ +
+ Por que esses nomes mudaram? A Google sinalizou no changelog (entradas de Dez/2025 a Jun/2026) que a Interactions API foi desenhada para se aproximar do vocabulário da Responses API da OpenAI (input_tokens / output_tokens / cached_tokens), facilitando bibliotecas unified-counting entre providers. Os valores em si seguem o tokenizador do Gemini — mas os nomes ficam mais portáveis. +
+ + + + +

G·usage Objeto usage — todos os campos

+

Tabela exaustiva de tudo que pode aparecer dentro de interaction.usage (Python) / interaction.usage (REST/JSON):

+
+ + + + + + + + + + + + + + + +
CampoTipoQuando apareceBucket de billing
total_input_tokensintegerSempre.Input.
total_output_tokensintegerSempre que houve model_output.Output.
total_cached_tokensintegerQuando há hit no cache implícito (via previous_interaction_id).Input com desconto (taxa de cache).
total_thought_tokensintegerModelos com thinking ativo (Gemini 3.x, 2.5 Pro, 2.5 Flash).Output (Gemini 3 já inclui thinking no preço de output).
total_tool_use_tokensintegerQuando alguma tool server-side foi executada.Conforme tabela de tools; ver §G·tools.
total_tokensintegerSempre; soma billable agregada.—
input_tokens_by_modality[]ModalityTokens[]Quando input é multimodal.—
output_tokens_by_modality[]ModalityTokens[]Quando output é multimodal (ex.: imagem gerada + texto).—
cached_tokens_by_modality[]ModalityTokens[]Quando cache hit é multimodal.—
tool_use_tokens_by_modality[]ModalityTokens[]Quando tools server-side retornam dados multimodais (ex.: code_execution gera imagem).—
grounding_tool_count[]GroundingToolCount[]Quando houve grounding (Search, Maps, Vertex Search).Array de {count, type}; type ∈ {google_search, google_maps, retrieval}.
+
+ +

Sub-objeto ModalityTokens

+

Na referência oficial (ai.google.dev/api/interactions-api) o campo do contador chama-se tokens (não token_count) e o enum modality é minúsculo (text, image, audio, video, document) — confirmado nos exemplos JSON oficiais ({"modality":"text","tokens":7}). No JSON REST canônico use sempre tokens. No SDK Python google-genai, porém, o tipo ModalityTokenCount expõe o contador como atributo .token_count (ver a referência do google-genai); valide qual atributo o objeto retornado pelo seu SDK realmente tem antes de depender dele.

+
{
+  "modality": "image" | "text" | "audio" | "video" | "document",
+  "tokens": 1120
+}
+ +

Sub-objeto grounding_tool_count (array de GroundingToolCount)

+

Conforme a referência oficial (ai.google.dev/api/interactions-api, verificado 2026-06-10): grounding_tool_count é um array de objetos GroundingToolCount, cada um com dois campos — count (integer) e type (enum ∈ {google_search, google_maps, retrieval}). Não existem chaves como google_search_count; cada tool de grounding vira um item do array.

+
[
+  { "type": "google_search", "count": 3 },
+  { "type": "google_maps",   "count": 0 },
+  { "type": "retrieval",    "count": 1 }
+]
+

O enum type tem exatamente 3 valores na referência: google_search, google_maps e retrieval (Vertex AI Search). O ponto importante é que ele conta quantas vezes uma tool server-side de grounding foi invocada (impacta billing de Search Grounding em chamadas com grounding pago) — não tokens.

+ +
+ Sanity check do total_tokens. Em modelos com thinking e tools server-side, vale: total_tokens ≈ total_input_tokens + total_output_tokens + total_thought_tokens + total_tool_use_tokens − total_cached_tokens*desconto. Não some manualmente assumindo equivalência exata — o serviço pode arredondar ou aplicar políticas internas (ex.: Search Grounding exclui tokens recuperados do count). Sempre log o total_tokens bruto. +
+ + + + +

G·text Texto puro — basic + multiturn server-side

+

A regra heurística é a mesma de generateContent: 1 token ≈ 4 caracteres EN (ou ~0,75 palavra). O system_instruction entra em total_input_tokens no mesmo bucket de texto. Diferentemente de generateContent, você não mantém o histórico em contents[]: cada turn passa previous_interaction_id e o servidor concatena o estado.

+ +

Chamada simples — Python & TypeScript

+
+
+ + +
+
+
from google import genai
+
+client = genai.Client()  # GEMINI_API_KEY do ambiente
+
+interaction = client.interactions.create(
+    model="gemini-3.5-flash",
+    system_instruction="You are concise.",
+    input="Explique a IA em uma frase.",
+)
+
+print(interaction.output_text)
+print(interaction.usage.total_input_tokens,   # ex.: 17
+      interaction.usage.total_output_tokens,  # ex.: 28
+      interaction.usage.total_tokens)         # ex.: 45
+
+
+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+
+const interaction = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  systemInstruction: "You are concise.",
+  input: "Explique a IA em uma frase.",
+});
+
+console.log(interaction.outputText);
+console.log(interaction.usage.totalInputTokens,
+            interaction.usage.totalOutputTokens,
+            interaction.usage.totalTokens);
+
+
+ +

Multiturn server-side — total_input_tokens inclui o histórico inteiro

+
+ Correção importante (verificado 2026-06-10). A doc oficial de count-tokens é explícita: ao passar previous_interaction_id, "Usage includes tokens from both turns" — ou seja, total_input_tokens do turn novo já contém o histórico server-side acumulado, não apenas o input daquele turn. O cache implícito (ver §G·cache-implicit) reporta em total_cached_tokens a parte desse input que foi reaproveitada do prefixo (cobrada com desconto) — total_cached_tokens é um subconjunto de total_input_tokens, não um bucket à parte. Para o custo de input "fresco": total_input_tokens − total_cached_tokens. +
+
+
+ + +
+
+
i1 = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Tenho 2 cachorros.",
+)
+i2 = client.interactions.create(
+    model="gemini-3.5-flash",
+    previous_interaction_id=i1.id,
+    input="Quantas patas há na minha casa?",
+)
+print(i2.usage.total_input_tokens)    # inclui o histórico (turn 1 + turn 2)
+print(i2.usage.total_cached_tokens)   # subconjunto reaproveitado do prefixo (com desconto)
+
+
+
const i1 = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  input: "Tenho 2 cachorros.",
+});
+const i2 = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  previousInteractionId: i1.id,
+  input: "Quantas patas há na minha casa?",
+});
+console.log(i2.usage.totalInputTokens, i2.usage.totalCachedTokens);
+
+
+ + + + +

G·images Imagens — media_resolution (1120 tk default em Gemini 3)

+

A fórmula é idêntica à de generateContent (ver §gemini-tc-images): em Gemini 3 os tokens vêm da tabela media_resolution (default 1120 tk/imagem); o 258/bloco é apenas o baseline genérico do count_tokens. O resultado aparece em input_tokens_by_modality[] com modality = "image" (enum minúsculo no JSON REST).

+
+ + + + + + + + +
CasoTokens (Gemini 3, billing real)Onde
Imagem (default / HIGH)1120 tokensinput_tokens_by_modality[] (modality:"image")
Imagem MEDIUM / LOW560 / 280 tokensidem
Baseline do count_tokens (estimativa)258 × ⌈W/768⌉ × ⌈H/768⌉só o pré-flight; não é o billing
Imagem gerada por gemini-3-pro-imagePreço por imagem (não por token) + tokens de prompt em total_input_tokensoutput_tokens_by_modality[] (modality:"image", informativo)
+
+ +

Exemplo — Python lendo input_tokens_by_modality (modality "image")

+
+
+ + +
+
+
import base64
+from google import genai
+
+client = genai.Client()
+with open("foto.jpg", "rb") as f:
+    img_b64 = base64.b64encode(f.read()).decode()
+
+i = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text",  "text": "Descreva esta imagem."},
+        {"type": "image", "data": img_b64, "mime_type": "image/jpeg"},
+    ],
+)
+
+for mt in i.usage.input_tokens_by_modality:
+    print(mt.modality, mt.tokens)   # JSON REST: campo "tokens"; SDK pode expor alias .token_count
+# text 6
+# image 258  (para foto <= 384 px)
+
+
+
import { readFileSync } from "node:fs";
+import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const img = readFileSync("foto.jpg").toString("base64");
+
+const i = await ai.interactions.create({
+  model: "gemini-3.5-flash",
+  input: [
+    { type: "text", text: "Descreva esta imagem." },
+    { type: "image", data: img, mimeType: "image/jpeg" },
+  ],
+});
+for (const mt of i.usage.inputTokensByModality ?? []) {
+  console.log(mt.modality, mt.tokenCount);
+}
+
+
+ + + + +

G·modality media_resolution — controle fino do custo

+

Em Gemini 3.x, o input multimodal aceita media_resolution ∈ {low, medium, high, ultra_high} — equivalente direto ao §gemini-tc-modality do generateContent. Pode ser definido globalmente em generation_config.media_resolution ou por-part dentro de cada item do input[] (o controle por-item é exclusivo de Gemini 3). O valor default quando não especificado é tratado como unspecified.

+
+ + + + + + + + + + +
Tokens por media_resolution e tipo de mídia — tabela oficial "Token counts" da página ai.google.dev/gemini-api/docs/media-resolution (Gemini 3, verificado 2026-06-10)
media_resolutionImagemVídeo (por frame)PDF (por página)Quando usar
unspecified (default)1 12070560Padrão balanceado para a maioria dos casos.
low28070280 + texto nativoThumbnails, OCR rápido, screenshots de UI; vídeo longo (até 3 h).
medium56070560 + texto nativoImagem ilustrativa, diagrama simples; setting recomendado para PDF.
high1 1202801 120 + texto nativoFoto, diagrama complexo, vídeo com texto denso (OCR).
ultra_high2 240N/AN/ASó por-item; computer use ou quando supera high em testes.
+
+
+ Atenção aos números de vídeo. Em Gemini 3, o billing real segue a tabela media_resolution: low e medium são idênticos para vídeo (70 tk/frame), high = 280 tk/frame; ultra_high não se aplica a vídeo nem a PDF. O guia de video understanding cita 258 tk/frame (≈300 tk/s) — esse é o baseline genérico do count_tokens, não o que se fatura. Para orçamento, use os valores media_resolution (70/280) e confirme com o usage real. +
+

Esses valores aparecem no input_tokens_by_modality[] sem distinção entre níveis — você só sabe a resolução escolhida olhando o parâmetro passado, não o response. Para auditoria, log media_resolution junto com o usage.

+ + + + +

G·video Vídeo — frame + áudio combinados

+

Em Interactions, o vídeo é processado com defaults: 1 FPS implícito + faixa de áudio mono ~1 kbps (32 tk/s). Em Gemini 3, o billing segue a tabela media_resolution: frames a 70 tk/frame (default/low/medium) ou 280 tk/frame (high) + 32 tk/s de áudio → ≈ 102 tk/segundo no default e ≈ 312 tk/segundo em high. (O guia de video understanding cita 258 tk/frame ≈ 300 tk/s — é o baseline genérico do count_tokens, ver §G·modality; o que se fatura são os inteiros 70/280.)

+
+ + + + + + + + +
CenárioTokens/segundo (Gemini 3)Limite de duraçãoAparece em
Vídeo default (media_resolution default/low/medium)~102 tk/s (70/frame + 32/s áudio)1 h (em contexto de 1 M)input_tokens_by_modality[] (modality:"video")
Vídeo com media_resolution: "high"~312 tk/s (280/frame + 32/s áudio)1 hidem
Baseline do count_tokens (estimativa)~300 tk/s (258/frame + 32/s áudio)—só o pré-flight; não é o billing
Vídeo via Files API (cap diferente)Mesmas regrasaté 20 GB pago / 2 GB freeidem
+
+
+ Sem video_metadata customizado. A Interactions API não aceita video_metadata com start_offset, end_offset ou fps. Se precisar de FPS diferente do default ou recortar intervalo, use generateContent. Isso impacta diretamente o counting: sem controle de FPS, vídeos longos podem estourar o budget esperado. +
+ +

Exemplo — pré-calcular custo de vídeo antes de subir

+
def video_tokens_estimate(seconds, media_resolution="default"):
+    # Billing real Gemini 3 (tabela media_resolution): high = 280 tk/frame;
+    # default/low/medium = 70 tk/frame (a 1 FPS) + 32 tk/s de áudio.
+    frame_cost = 280 if media_resolution == "high" else 70
+    audio_cost = 32  # tk/s
+    return seconds * (frame_cost + audio_cost)
+
+# Vídeo de 5 minutos, resolução default
+print(video_tokens_estimate(300))   # 300 * (70+32) = 30 600 tokens
+ + + + +

G·audio Áudio — 32 tokens/segundo

+

Áudio em Interactions é cobrado a 32 tokens por segundo, independente do MIME type ou da taxa de bits do arquivo original. Internamente, o servidor faz downsample para mono 16 kbps. O limite por comando é 9,5 horas de áudio (≈ 1 094 400 tokens) e tamanho inline < 20 MB.

+ +
+ + + + + + + + +
MIME types aceitos no input[].audio
FamíliaMIMEs aceitos
PCM & losslessaudio/wav, audio/flac, audio/aiff
Comprimidosaudio/mp3, audio/mpeg, audio/aac, audio/m4a, audio/ogg, audio/opus
Telefoniaaudio/alaw, audio/mulaw
+
+ +
def audio_tokens(seconds): return seconds * 32
+
+# 1 minuto = 1 920 tk; 1 hora = 115 200 tk
+ + + + +

G·pdf PDF — 560 tk/página (default Gemini 3) + texto nativo grátis

+

PDF é processado como página-imagem mais o texto nativo extraído. Em Gemini 3, a página-imagem é faturada pela tabela media_resolution: 560 tk/página no default (MEDIUM), 280 em LOW, 1120 em HIGH. A novidade em Gemini 3 é que o texto nativo é gratuito — você só paga pela página-imagem. Limites: até 50 MB inline e 1 000 páginas por documento; resolução suportada 768 × 768 a 3072 × 3072.

+
+ + + + + + + + + +
ItemTokens (Gemini 3)Cobrado?
Página renderizada (default / MEDIUM)560 tk/páginaSim
Página renderizada (LOW / HIGH)280 / 1120 tk/páginaSim
Texto nativo extraído (Gemini 3)—Não — grátis
Baseline do count_tokens (estimativa)~258 tk/páginasó o pré-flight; não é o billing
PDF entregue via Files APIMesmas regras—
+
+ +

Exemplo — Python via Files API

+
from google import genai
+client = genai.Client()
+
+pdf = client.files.upload(file="relatorio.pdf")
+i = client.interactions.create(
+    model="gemini-3.5-flash",
+    input=[
+        {"type": "text", "text": "Resuma em 5 bullets."},
+        {"type": "document", "uri": pdf.uri, "mime_type": pdf.mime_type},
+    ],
+)
+
+# Para um PDF de 12 páginas em Gemini 3: ~ 258 * 12 = 3 096 tokens DOCUMENT
+# Texto nativo é gratuito — não soma em total_input_tokens
+for mt in i.usage.input_tokens_by_modality:
+    print(mt.modality, mt.token_count)
+ + + + +

G·multimodal-breakdown Breakdown completo por modalidade

+

Quando o input mistura várias modalidades, input_tokens_by_modality[] é a única fonte confiável de quanto cada parte custou. Útil para dashboards de custo "por tipo de arquivo".

+
+
+ + +
+
+
def summarize_usage(usage):
+    return {
+        "input_total":  usage.total_input_tokens,
+        "output_total": usage.total_output_tokens,
+        "cached":       usage.total_cached_tokens,
+        "thought":      usage.total_thought_tokens,
+        "tool_use":     usage.total_tool_use_tokens,
+        "by_modality": {
+            mt.modality: mt.token_count
+            for mt in (usage.input_tokens_by_modality or [])
+        },
+    }
+
+# Saída típica para input: texto + 2 imagens + 1 PDF de 10 pgs
+# {
+#   "input_total": 4 130,
+#   "by_modality": {"text": 14, "image": 516, "document": 2 580, "audio": 1 020}
+# }
+
+
+
function summarizeUsage(usage: any) {
+  return {
+    inputTotal:  usage.totalInputTokens,
+    outputTotal: usage.totalOutputTokens,
+    cached:      usage.totalCachedTokens,
+    thought:     usage.totalThoughtTokens,
+    toolUse:     usage.totalToolUseTokens,
+    byModality:  Object.fromEntries(
+      (usage.inputTokensByModality ?? []).map((m: any) => [m.modality, m.tokenCount])
+    ),
+  };
+}
+
+
+ + + + +

G·system system_instruction entra no input

+

Igual a generateContent: o conteúdo de system_instruction é cobrado como TEXT dentro de total_input_tokens (sem campo separado). Atenção: em Interactions, system_instruction é interaction-scoped — você precisa re-declará-lo a cada turn (não é herdado de previous_interaction_id).

+

Isso tem implicação direta no counting: se você passa o mesmo system_instruction em todos os turns de uma conversa longa, ele entra em total_input_tokens de cada chamada — mas o cache implícito normalmente cobre o prefixo idêntico, então o custo efetivo cai (aparece em total_cached_tokens).

+ +
i = client.interactions.create(
+    model="gemini-3.5-flash",
+    system_instruction="Responda apenas com JSON.",
+    input="Liste 3 frutas tropicais.",
+)
+# system_instruction ~ 12 tokens já estão em total_input_tokens.TEXT
+ + + + +

G·tools Tools — client-side vs server-side

+

A distinção entre tools client-side (funções declaradas que o cliente executa) e server-side (tools que rodam no servidor da Google) define em qual campo do usage os tokens entram.

+
+ + + + + + + + + + + + + +
tools[].typeQuem executaJSON Schema cobra emResultado cobra em
functionClientetotal_input_tokensfunction_result que o cliente devolve cobra como input no próximo turn.
google_searchServidortotal_input_tokens (declaração)total_tool_use_tokens (snippets) — Search Grounding exclui tokens recuperados.
code_executionServidor (sandbox Python)total_input_tokenstotal_tool_use_tokens (stdout + código gerado); imagens geradas podem entrar em tool_use_tokens_by_modality[] (modality:"image").
url_contextServidortotal_input_tokenstotal_tool_use_tokens (HTML/Markdown das URLs).
mcp_serverServidor remoto MCPtotal_input_tokenstotal_tool_use_tokens.
file_searchServidor (RAG)total_input_tokenstotal_tool_use_tokens (chunks recuperados).
google_mapsServidortotal_input_tokenstotal_tool_use_tokens.
retrieval (Vertex AI Search)Servidortotal_input_tokenstotal_tool_use_tokens (somente em Vertex; ver §G·vertex).
computer_useServidor (UI agent)total_input_tokenstotal_tool_use_tokens + capturas em tool_use_tokens_by_modality[] (modality:"image").
+
+

Tools são interaction-scoped: precisam ser re-declaradas a cada turn (não é herdada de previous_interaction_id). Isso significa que o JSON Schema delas pesa em total_input_tokens a cada chamada.

+ + + + +

G·thinking Thinking — bucket separado, cobrado como output

+

Configurável via generation_config.thinking_level ∈ {minimal, low, medium, high} e thinking_summaries ∈ {auto, none}. Os tokens consumidos pelo raciocínio interno aparecem em total_thought_tokens — exatamente como thoughts_token_count em generateContent. Em Gemini 3, o preço de output já inclui o thinking, ou seja: total_thought_tokens é cobrado à tabela de output.

+ +
+ Thinking sumiu do response mas continua na fatura. Se thinking_summaries: "none", você não vê nada do raciocínio nos steps[] — mas total_thought_tokens continua aparecendo. Sempre faça log dele em produção: um output visível de 200 tokens pode esconder 5–8 mil tokens de thinking em thinking_level: "high". +
+ +
i = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Resolva: integral de sin(x²) dx",
+    generation_config={"thinking_level": "high", "thinking_summaries": "auto"},
+)
+print(i.usage.total_thought_tokens)   # ex.: 6 200
+print(i.usage.total_output_tokens)    # ex.: 180 (resposta final)
+print(i.usage.total_tokens)           # soma billable agregada
+ + + + +

G·cache-implicit Cache implícito — automático via previous_interaction_id

+

A Interactions API tem apenas cache implícito: ele se ativa automaticamente quando você passa previous_interaction_id. Os tokens reutilizados do histórico server-side aparecem em total_cached_tokens + cached_tokens_by_modality[] e são cobrados ao preço de cache do modelo (mesmo desconto que cached_content_token_count em generateContent).

+ +
+ Bloqueado neste projeto: a constraint store=false default impede o uso de previous_interaction_id, que é o gate para o cache implícito Interactions-specific. Resultado empírico: total_cached_tokens ≈ 0 em chamadas Interactions sob store=false. Detalhe operacional + recipe em §10.4. +
+ +
+ + + + + + + + + + +
CaracterísticaCache implícito Interactions (gated por previous_interaction_id)Cache implícito generateContent (Gemini 3.x — modo usado no projeto)
Como ativarPassar previous_interaction_id (requer store=true — bloqueado neste projeto)Automático: prefixo byte-idêntico ≥ min do modelo no mesmo (project, region, model)
TTL configurávelNão — segue retenção do interaction.id (55 d / 1 d)Não — RAM-only opaca, ~minutos best-effort
Storage costNão cobradoNão cobrado (RAM)
Aparece emtotal_cached_tokens (=0 sob store=false)cached_content_token_count (> 0 em hit)
Min tokens para ativarSem mínimo documentado (irrelevante sob store=false)Flash/Lite ≥ 1 024 (Developer) / Pro ≥ 4 096 (Developer e Vertex; Vertex unifica todos em 4 096)
Compatível com a constraint do projetoNão — gated por store=trueSim — modo recomendado
+
+ +

Estratégias para maximizar implicit hit (caminho generateContent)

+
    +
  • Mantenha system_instruction + tools byte-idênticos entre turns; uma vírgula a mais invalida o prefixo.
  • +
  • Mesmo model ID em toda a sessão (Pro/Flash/Lite são caches diferentes).
  • +
  • Mesma região (cross-region = miss; sessão precisa rotear consistente).
  • +
  • Mesmo project (cross-project = miss; útil como tenant-isolation natural).
  • +
  • Prefixo ≥ min do modelo antes do primeiro turno dinâmico; abaixo disso, nunca há hit.
  • +
  • Monitore cached_content_token_count / prompt_token_count — em conversas saudáveis cresce a partir do 2º turno.
  • +
+ + + + +

G·count-tokens Pré-contagem com client.models.count_tokens

+
+ Confirmado: NÃO existe client.interactions.count_tokens. Verificado em ai.google.dev/gemini-api/docs/interactions/tokens e em github.com/googleapis/python-genai (2026-06-10). O recurso interactions tem apenas as operações create, retrieve, delete, cancel. Para estimar tokens antes de criar uma interação, use o mesmo endpoint do modelo (POST /v1beta/models/{model}:countTokens) com o conteúdo que iria no input. +
+ +

Padrão duplo: pré-flight + pós-call

+
+
+ + +
+
+
from google import genai
+client = genai.Client()
+
+prompt = [
+    {"type": "text",  "text": "Resuma este PDF."},
+    {"type": "document", "uri": pdf.uri, "mime_type": "application/pdf"},
+]
+
+# 1) Pré-flight — endpoint do MODELO (não da Interactions)
+#    Aceita o mesmo formato de contents que generateContent
+pre = client.models.count_tokens(
+    model="gemini-3.5-flash",
+    contents=prompt,
+)
+print("pre-flight totalTokens:", pre.total_tokens)
+
+# 2) Cria a interação e lê o usage real
+i = client.interactions.create(model="gemini-3.5-flash", input=prompt)
+print("actual input:", i.usage.total_input_tokens)
+print("actual total:", i.usage.total_tokens)
+
+
+
const pre = await ai.models.countTokens({
+  model: "gemini-3.5-flash",
+  contents: prompt,
+});
+console.log("pre-flight", pre.totalTokens);
+
+const i = await ai.interactions.create({ model: "gemini-3.5-flash", input: prompt });
+console.log("actual", i.usage.totalInputTokens, i.usage.totalTokens);
+
+
+ +

REST equivalente

+
curl -X POST \
+  "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.5-flash:countTokens" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Content-Type: application/json" \
+  -d '{"contents": [{"parts":[{"text":"Resuma este PDF."}]}]}'
+

Retorna {"totalTokens": N, "promptTokensDetails": [...]} — note que o endpoint ainda devolve o nome legado (totalTokens / promptTokensDetails), independente da Interactions API. Para alinhar com o shape novo, mapeie manualmente (ver §G·migration).

+ + + + +

G·streaming Streaming — usage só em interaction.completed

+

Em SSE (stream=true), os eventos step.delta não trazem usage parcial. O objeto usage aparece apenas no evento final interaction.completed. Isso é o equivalente direto do comportamento de streamGenerateContent (em que usage_metadata só estabiliza no chunk final).

+ +

Eventos SSE (schema novo, vigente após 2026-05-20)

+
+ + + + + + + + + + + +
EventoTraz usage?Quando dispara
interaction.createdNãoImediato.
interaction.status_updateNãoTransições de status.
step.startNãoInício de cada step.
step.deltaNãoTokens texto/imagem/áudio incrementais.
step.stopNãoFim do step.
interaction.completedSimFinal; objeto interaction com usage completo (steps omitido para reduzir payload — use os step.delta anteriores para o output).
errorNãoErro (objeto {message, code}).
+
+

A referência oficial (ai.google.dev/api/interactions-api) lista exatamente estes tipos de evento SSE (InteractionSseEvent): interaction.created, interaction.completed, interaction.status_update, error, step.start, step.delta, step.stop. Não existe um evento interaction.requires_action — requires_action é um status (um dos 7: in_progress, requires_action, completed, failed, cancelled, incomplete, budget_exceeded) entregue dentro de interaction.status_update; ao pausar para function call o usage ainda não é final.

+ +

Padrão Python — acumular deltas, ler usage só ao fim

+
stream = client.interactions.create(
+    model="gemini-3.5-flash",
+    input="Conte uma história curta.",
+    stream=True,
+)
+
+for event in stream:
+    if event.event_type == "step.delta" and event.delta.type == "text":
+        print(event.delta.text, end="", flush=True)
+    elif event.event_type == "interaction.completed":
+        u = event.interaction.usage
+        print(f"\n[usage] in={u.total_input_tokens} out={u.total_output_tokens}")
+ +

Resumir stream interrompido — last_event_id

+

O parâmetro last_event_id existe (conforme a referência oficial ai.google.dev/api/interactions-api) e permite retomar um stream após reconexão. Não afeta counting — quando o stream termina, o usage em interaction.completed é o do total executado, independente de quantas reconexões houve.

+
curl -G "https://generativelanguage.googleapis.com/v1beta/interactions/$ID" \
+  -H "x-goog-api-key: $GEMINI_API_KEY" \
+  -H "Api-Revision: 2026-05-20" \
+  --data-urlencode "stream=true" \
+  --data-urlencode "last_event_id=$LAST_ID"
+ + + + +

G·deep-research Deep Research & agents — counting dos loops

+

Deep Research, Deep Research Max e Deep Think rodam loops agentic no servidor durante minutos a horas (com background=true). O counting segue a regra: todo token consumido no loop (input ampliado, raciocínio intermediário, resultados de tools server-side) é cobrado a rates padrão do modelo subjacente — sem surcharge específica para "Deep".

+
+ + + + + + + + + + + + + +
Tokens em Deep Research / Deep Think (verificado 2026-06-10)
Componente do loopCai emCobrado como
Input inicial do usuáriototal_input_tokensInput.
Re-prompts intermediários (planning, refinement)total_input_tokensInput (cada iteração).
Raciocínio interno entre passostotal_thought_tokensOutput (preço de thinking).
Search Grounding (Google Search)total_tool_use_tokens + item {type:"google_search"} em grounding_tool_count[]Tool-use (Search Grounding exclui tokens retrievados).
URL context / File Searchtotal_tool_use_tokensTool-use (inclui tokens retrievados).
Visualization (charts)total_tool_use_tokens + tool_use_tokens_by_modality[] (modality:"image")Tool-use.
thinking_summaries: "auto"total_thought_tokens (sumário visível) + parte internaOutput.
Resposta final estruturadatotal_output_tokensOutput.
+
+ +
+ Polling não custa nada extra. client.interactions.get(id) em background=true é uma leitura de estado — não dispara nova inferência e não soma tokens. Mas: depois que a interação completa, o usage retornado por get é o mesmo do create original (não reflete chamadas futuras). +
+ +

agent_config.collaborative_planning e impacto no counting

+

Em Deep Research com collaborative_planning: true, o servidor pausa após gerar o plano e espera confirmação humana. Isso resulta em duas interações cobradas: a primeira (geração do plano) e a segunda (execução após aprovação). O total_thought_tokens da fase de planning costuma ser significativo (~30-50% do thinking total).

+ + + + +

G·tool-use-breakdown tool_use_tokens_by_modality

+

Quando tools server-side retornam dados multimodais, o breakdown vai para tool_use_tokens_by_modality[]. Exemplos típicos:

+
+ + + + + + + + + +
ToolModalidades possíveis em tool_use_tokens_by_modality
code_execution com matplotlibtext (stdout) + image (plot gerado)
computer_usetext (DOM/HTML) + image (screenshots)
url_context com PDFtext + document
google_mapstext + image (tiles do mapa)
file_search em store multimodaltext + outras conforme o conteúdo dos chunks
+
+
for mt in i.usage.tool_use_tokens_by_modality or []:
+    print(f"tool [{mt.modality}]", mt.tokens)
+# tool [text] 412
+# tool [image] 258  -- plot gerado por code_execution
+ + + + +

G·service-tier service_tier — não afeta tokens, afeta preço/SLO

+

O parâmetro service_tier escolhe a classe de serviço da chamada. Importante para counting: ele não muda a quantidade de tokens cobrados — só o preço por token e a quota disponível.

+
+ + + + + + + +
TierPreço relativo (por token)RPM/TPMSLOQuando usar
flexMenorVariávelFrouxo (latência maior, sem garantia)Batches noturnos, pipelines tolerantes a latência.
standard (default)1×Default do modeloPadrãoUI interativa normal.
priority+80% vs standard (oficial: $2.70 in / $16.20 out por 1M em gemini-3.5-flash, vs $1.50/$9.00 standard)0,3× do standardNão-sheddable; downgrade gracioso p/ standardUIs críticas, low-latency.
+
+

Os números exatos por modelo estão em aistudio.google.com/rate-limit (personalizado por projeto).

+ + + + +

G·models-pricing Modelos & pricing — mesmo de generateContent

+

Não há surcharge por usar Interactions API. O pricing por modelo é idêntico ao do generateContent e segue a tabela oficial em ai.google.dev/gemini-api/docs/pricing. Tabela rápida (USD por 1 M tokens, valores oficiais 2026-06-10):

+
+ + + + + + + + + +
Pricing relevante para Interactions (mesmo de generateContent; verificado 2026-06-10)
ModeloInputOutput (inclui thinking)Cached input
gemini-3.1-pro-preview$2,00 / 1 M (≤200 k) · $4,00 (>200 k)$12,00 / 1 M (≤200 k) · $18,00 (>200 k)$0,20 / 1 M (≤200 k) · $0,40 (>200 k)
gemini-3.5-flash$1,50 / 1 M$9,00 / 1 M$0,15 / 1 M
gemini-3.1-flash-lite$0,25 / 1 M (texto/img/vídeo) · $0,50 (áudio)$1,50 / 1 M$0,025 / $0,05 / 1 M
gemini-3.1-flash-image (Nano Banana 2)$1,50 / 1 M$60 / 1 M de imagem (~$0,067/1K imgs)—
+
+

Sempre verifique a página oficial de pricing — preços e bandas mudam. Em gemini-3.1-pro-preview há banda dupla acima/abaixo de 200 k de contexto.

+ +

Calculando custo a partir do usage

+
def cost_usd(usage, model_rates):
+    in_cost   = (usage.total_input_tokens - usage.total_cached_tokens) * model_rates["input"]
+    cache_cost= usage.total_cached_tokens * model_rates["cached"]
+    out_cost  = (usage.total_output_tokens + usage.total_thought_tokens) * model_rates["output"]
+    tool_cost = usage.total_tool_use_tokens * model_rates["output"]
+    return (in_cost + cache_cost + out_cost + tool_cost) / 1_000_000
+
+flash_rates = {"input": 1.50, "output": 9.00, "cached": 0.15}  # gemini-3.5-flash
+print(f"$ {cost_usd(i.usage, flash_rates):.6f}")
+ + + + +

G·vertex Vertex AI & ZDR

+
+ Em 2026-06-10 a Interactions API está disponível apenas no Gemini Developer API (Google AI Studio). A paridade em Vertex AI é UNVERIFIED (não há data oficial firme até 2026-06-10) — o Google anunciou "coming soon to Vertex AI", sem data confirmada. A referência REST do Vertex AI (docs.cloud.google.com/vertex-ai/generative-ai/docs/reference/rest) não lista o recurso interactions: lá temos computeTokens, countTokens, embedContent, generateContent, predict, rawPredict, serverStreamingPredict, streamGenerateContent, streamRawPredict. Para produção em Vertex AI hoje, continue em generateContent com usage_metadata. +
+ +

Aproximação de ZDR via store=false

+

ZDR formal (com emenda à DPA) só está disponível no Vertex AI — não no Developer API. Para aproximar ZDR no Gemini Developer API, set store=false. Trade-offs diretos no counting:

+
    +
  • previous_interaction_id deixa de funcionar; sem o histórico server-side, você precisa reanexar tudo no input — total_input_tokens cresce a cada turn.
  • +
  • total_cached_tokens fica em 0 nas chamadas subsequentes (sem cache implícito).
  • +
  • store=false é incompatível com background=true (Deep Research, Deep Think).
  • +
  • Arquivos da Files API não são auto-deletados; remova manualmente para ZDR efetivo.
  • +
+ +

Regiões / data residency

+

Regiões exatas do Developer API são UNVERIFIED (não há página oficial de "Available regions" estável até 2026-06-10). Vertex AI mantém regiões selecionáveis no projeto (incluindo EU-pinned em europe-west12 e de-central1 para Gemini Enterprise / NotebookLM Enterprise), mas isso não vale para a Interactions API enquanto ela não estiver em Vertex.

+ + + + +

G·migration Migração usage_metadata → usage (Maio 2026)

+
+ Cronograma consumado. Em 2026-06-08 o schema legacy da Interactions API foi removido — rollback impossível. Código que lê interaction.outputs[…] ou que ainda usa nomes legados em respostas Interactions parou de funcionar. Em generateContent, usage_metadata permanece válido — não é afetado. +
+ +

Cronograma oficial

+
+ + + + + + + + +
DataEvento
2026-05-07Anúncio da breaking change (entrada nas release notes / changelog); schema novo disponível em opt-in.
2026-05-20Revisão-alvo do schema novo: valor do header Api-Revision: 2026-05-20 para opt-in via REST.
2026-05-26Schema novo vira padrão em REST; SDKs antigos continuaram recebendo legacy; opt-out temporário via Api-Revision: 2026-05-07 (nota histórica: o opt-out não funciona mais — o header é ignorado desde 08/06/2026).
2026-06-08Legacy removido (consumado). Python 1.x.x e JS 1.x.x quebraram; header Api-Revision é ignorado desde esta data — rollback impossível.
+
+ +

Tabela ANTES / DEPOIS

+
+ + + + + + + + + + + + + + +
AspectoANTES (até 08/06/2026, schema legacy)DEPOIS (a partir de 20/05/2026, schema novo)
Container do usageinteraction.usage_metadatainteraction.usage
Campo de inputprompt_token_counttotal_input_tokens
Campo de outputcandidates_token_counttotal_output_tokens
Campo de cachecached_content_token_counttotal_cached_tokens
Campo de thinkingthoughts_token_counttotal_thought_tokens
Campo de toolstool_use_prompt_token_counttotal_tool_use_tokens
Totaltotal_token_counttotal_tokens
Breakdownprompt_tokens_details[]input_tokens_by_modality[]
Estrutura da respostainteraction.outputs[] (flat)interaction.steps[] (timeline tipada)
Eventos SSEcontent.delta, interaction.completestep.delta, interaction.completed
+
+ +

Código que parou de funcionar em 2026-06-08

+
    +
  • Qualquer leitura de interaction.outputs[...] — substituir por interaction.steps[...] ou interaction.output_text.
  • +
  • Acesso a usage_metadata.*_token_count em respostas Interactions — substituir por usage.total_*_tokens. (Em respostas generateContent, usage_metadata não muda.)
  • +
  • Listeners de streaming em content.delta, content.start, content.stop, interaction.start, interaction.complete.
  • +
  • Campo response_mime_type no body; generation_config.image_config top-level (migrado para response_format polimórfico).
  • +
  • Chamadas via google-genai < 2.0.0 ou @google/genai < 2.0.0 — quebradas desde 08/06/2026 para Interactions.
  • +
+ +

Utilitário Python — converter usage_metadata legado para usage novo

+
from dataclasses import dataclass, field
+
+@dataclass
+class ModalityTokens:
+    modality: str
+    token_count: int
+
+@dataclass
+class Usage:
+    total_input_tokens:     int = 0
+    total_output_tokens:    int = 0
+    total_cached_tokens:    int = 0
+    total_thought_tokens:   int = 0
+    total_tool_use_tokens:  int = 0
+    total_tokens:           int = 0
+    input_tokens_by_modality:  list[ModalityTokens] = field(default_factory=list)
+    output_tokens_by_modality: list[ModalityTokens] = field(default_factory=list)
+    cached_tokens_by_modality: list[ModalityTokens] = field(default_factory=list)
+
+def usage_metadata_to_usage(meta) -> Usage:
+    """Converte response.usage_metadata (generateContent) para o shape novo
+    de interaction.usage (Interactions API)."""
+    def _details(name):
+        return [ModalityTokens(modality=d.modality, token_count=d.token_count)
+                for d in (getattr(meta, name, None) or [])]
+    g = lambda n: getattr(meta, n, 0) or 0
+    return Usage(
+        total_input_tokens    = g("prompt_token_count"),
+        total_output_tokens   = g("candidates_token_count"),
+        total_cached_tokens   = g("cached_content_token_count"),
+        total_thought_tokens  = g("thoughts_token_count"),
+        total_tool_use_tokens = g("tool_use_prompt_token_count"),
+        total_tokens          = g("total_token_count"),
+        input_tokens_by_modality  = _details("prompt_tokens_details"),
+        output_tokens_by_modality = _details("candidates_tokens_details"),
+        cached_tokens_by_modality = _details("cache_tokens_details"),
+    )
+ +

Path REST canônico

+

Use /v1beta/interactions. A discrepância v1beta vs v1beta2 é apenas no guia de migração; a referência oficial (ai.google.dev/api/interactions-api), o guia e a página de streaming todos usam v1beta.

+ + + + +

G·limits Limites & quotas

+ +

Retenção do interaction.id

+
+ + + + + + +
PlanoRetençãoImpacto no counting
Pago55 diasApós esse prazo, previous_interaction_id falha e total_cached_tokens some.
Gratuito1 diaPipelines free-tier não devem contar com cache implícito de longa duração.
+
+ +

Rate limits

+

A Interactions API não publica RPM/TPM próprios — herdam do modelo subjacente (service_tier multiplica). Sem cota específica para Deep Research / Deep Think; eles consomem RPM/TPM do modelo durante o loop. Para números atuais do seu projeto: aistudio.google.com/rate-limit.

+ +

Capacidades que afetam (ou faltam para) o counting

+
+ + + + + + + + + + + +
CapacidadeStatus em InteractionsImpacto
Batch API (50% off)Não suportadoUse generateContent + Batch para custo reduzido.
Cache explícito (TTL custom)Não suportadoUse generateContent + cachedContent.
Auto function calling em PythonNão suportadoRound-trip de tools é manual; cada turn re-cobra schema das tools em total_input_tokens.
video_metadata customizado (FPS, offsets)Não suportadoVídeos longos podem estourar budget esperado.
safety_settings por categoriaNão suportado (verificado)Use generateContent se precisar bloquear por HARM_CATEGORY_*. Na família Gemini 3, threshold default já é Off.
last_event_id (resume SSE)Suportado (verificado)Não afeta counting — usage final é o do total executado.
client.interactions.count_tokens nativoNão existe (verificado)Use client.models.count_tokens.
+
+ + + + +

G·recipes Receitas práticas

+ +

1) Pré-contar antes de criar a interação

+
def safe_create(client, model, input_, max_input=800_000):
+    pre = client.models.count_tokens(model=model, contents=input_)
+    if pre.total_tokens > max_input:
+        raise ValueError(f"prompt {pre.total_tokens} > {max_input}")
+    return client.interactions.create(model=model, input=input_)
+ +

2) Custo unificado usage × pricing

+
PRICING = {
+    "gemini-3.5-flash":        {"in": 0.30, "out": 2.50, "cache": 0.075},
+    "gemini-3.1-pro-preview":   {"in": 1.25, "out": 10.0,  "cache": 0.31},
+    "gemini-3.1-flash-lite-preview": {"in": 0.10, "out": 0.40, "cache": 0.025},
+}
+
+def interaction_cost(model, usage):
+    p = PRICING[model]
+    fresh_in = max(0, usage.total_input_tokens - usage.total_cached_tokens)
+    return (
+        fresh_in                       * p["in"]
+      + usage.total_cached_tokens      * p["cache"]
+      + (usage.total_output_tokens
+        + usage.total_thought_tokens
+        + usage.total_tool_use_tokens) * p["out"]
+    ) / 1_000_000
+ +

3) Comparar custo Interactions vs generateContent para o mesmo input

+
# Mesmo prompt nas duas APIs — preço deve ser idêntico
+g = client.models.generate_content(model="gemini-3.5-flash", contents=prompt)
+i = client.interactions.create(model="gemini-3.5-flash", input=prompt)
+
+assert g.usage_metadata.prompt_token_count == i.usage.total_input_tokens
+assert g.usage_metadata.candidates_token_count == i.usage.total_output_tokens
+assert g.usage_metadata.total_token_count == i.usage.total_tokens
+ +

4) Detectar cache hit ratio

+
def cache_hit_ratio(usage):
+    if usage.total_input_tokens == 0: return 0.0
+    return usage.total_cached_tokens / usage.total_input_tokens
+
+# Em conversas saudáveis após o 3o turn, > 0.6
+print(cache_hit_ratio(i.usage))
+ +

5) Roteamento dinâmico baseado em pré-contagem

+
def route_model(client, input_):
+    pre = client.models.count_tokens(model="gemini-3.5-flash", contents=input_)
+    n = pre.total_tokens
+    if n < 2_000:    return "gemini-3.1-flash-lite-preview"  # barato
+    if n < 50_000:   return "gemini-3.5-flash"               # default
+    return "gemini-3.1-pro-preview"                       # contexto longo / reasoning
+
+model = route_model(client, prompt)
+interaction = client.interactions.create(model=model, input=prompt)
+ +

6) Logger estruturado completo

+
import json, logging
+log = logging.getLogger("gemini-interactions")
+
+def log_usage(interaction, model, service_tier="standard"):
+    u = interaction.usage
+    log.info(json.dumps({
+        "interaction_id": interaction.id,
+        "model": model,
+        "service_tier": service_tier,
+        "input":    u.total_input_tokens,
+        "output":   u.total_output_tokens,
+        "cached":   u.total_cached_tokens,
+        "thought":  u.total_thought_tokens,
+        "tool_use": u.total_tool_use_tokens,
+        "total":    u.total_tokens,
+        "by_modality": [
+            {"m": mt.modality, "n": mt.token_count}
+            for mt in (u.input_tokens_by_modality or [])
+        ],
+    }))
+ +
+ Checklist final — Interactions API token counting. +
    +
  • Pré-flight: client.models.count_tokens(model=..., contents=...) — endpoint do modelo; client.interactions.count_tokens não existe.
  • +
  • Pós-call: leia interaction.usage.total_*_tokens; usage_metadata não aparece em Interactions (já no schema novo).
  • +
  • Streaming: usage só estável em interaction.completed; step.delta não traz contagem.
  • +
  • Cache implícito: previous_interaction_id ativa total_cached_tokens automaticamente.
  • +
  • Cache explícito: não disponível; fallback para generateContent + cachedContent.
  • +
  • Thinking: total_thought_tokens é cobrado como output (Gemini 3 inclui no preço de output).
  • +
  • Tools server-side: total_tool_use_tokens; functions client-side pesam em total_input_tokens.
  • +
  • Vídeo: ~300 tk/s default, ~100 tk/s com media_resolution: "low"; sem video_metadata customizado.
  • +
  • PDF: 258/página; texto nativo gratuito em Gemini 3.
  • +
  • Pricing: idêntico a generateContent; sem surcharge por Interactions.
  • +
  • service_tier muda preço/RPM, não muda tokens.
  • +
  • Vertex AI: UNVERIFIED (não documentada oficialmente em Vertex até 2026-06-10); use generateContent lá.
  • +
  • ZDR: store=false aproxima (perde cache implícito + previous_interaction_id); ZDR formal só em Vertex AI.
  • +
  • Migração consumada em 2026-06-08 (schema legado removido): SDK ≥ 2.0.0 é obrigatório; o header REST Api-Revision é ignorado desde então e SDKs 1.x estão quebrados para Interactions.
  • +
  • Path REST canônico: /v1beta/interactions (não v1beta2).
  • +
+
+
+ + +
+
Anthropic
+

Anthropic deep-dive — token counting

+

+ Anthropic expõe contagem de tokens como um endpoint dedicado e síncrono, separado do POST /v1/messages: + POST /v1/messages/count_tokens. Aceita o mesmo formato de input usado para criar mensagens — incluindo + system, tools, messages com blocos image, document (PDF), + thinking, blocos com cache_control e file_id da Files API — e devolve um único campo: + { "input_tokens": N }. O endpoint é a fonte de verdade para previsão de custo, roteamento entre + modelos (200k vs 1M de contexto), planejamento de cache, e checagem prévia contra rate limits — antes de pagar pela criação real + da mensagem. +

+ +

A.1 Por que contar antes de criar

+
    +
  • Gerenciar rate limits e custo proativamente: ITPM (input tokens-per-minute) é um limite duro em cada tier — bater no teto causa 429. Contar antes evita explodir orçamento de janela.
  • +
  • Roteamento inteligente de modelo: decidir entre claude-haiku-4-5 (200k ctx) e claude-sonnet-4-6/claude-opus-4-8 (1M ctx, premium) com base no tamanho real do payload composto (system + tools + history + anexos).
  • +
  • Otimização de prompt: ajustar tamanho de system prompt, número de imagens, resolução, ou poda de history para caber em uma janela alvo (ex.: 180k para deixar headroom).
  • +
  • Pré-validação de cache: mesmo que count_tokens não dispare cache, ele ajuda a planejar o ponto ideal para inserir cache_control em prefixos longos.
  • +
+
+ ZDR-eligible. Quando sua organização possui acordo de Zero Data Retention com a Anthropic, os dados enviados via messages/count_tokens também não são armazenados após a resposta. Isso permite usar o endpoint em pipelines sensíveis (PHI, PII regulada) com a mesma garantia do messages.create. +
+
+ Tokenizador novo na linha Opus (introduzido no 4.7). A doc oficial declara: "Opus 4.7 uses a new tokenizer compared to previous models, contributing to its improved performance on a wide range of tasks. This new tokenizer may use up to 35% more tokens for the same fixed text." O claude-opus-4-8 (sucessor atual) herda esse mesmo tokenizador. Conte sempre com o modelo de destino — extrapolar de Sonnet/Haiku para Opus 4.8 pode subestimar input em até ~35%. +
+ +

A.2 Endpoint e contrato

+
POST https://api.anthropic.com/v1/messages/count_tokens
+Headers:
+  x-api-key: $ANTHROPIC_API_KEY
+  anthropic-version: 2023-06-01
+  content-type: application/json
+  anthropic-beta: files-api-2025-04-14    # somente se usar source.type=file / file_id
+

O body aceita exatamente o mesmo shape do messages.create, mas sem os campos de geração (max_tokens, stop_sequences, temperature, top_p, top_k, stream, metadata — esses são ignorados/inválidos). Os campos que contam:

+
+ + + + + + + + + + + + +
Campos aceitos por messages/count_tokens e impacto em input_tokens
CampoConta para input_tokens?Observação
model—Obrigatório; tokenização varia entre famílias (Haiku/Sonnet/Opus) — sempre passe o modelo de destino real. Opus 4.8 usa tokenizador novo (+35%).
system (string ou array de blocos)SimCada bloco com cache_control é tokenizado normalmente — marcação de cache não desconta no count.
tools (function definitions)SimSchema JSON serializado pesa muito; ver §A.4.
tool_choiceSimContribuição pequena, mas conta (~313 tk para any/tool, ~346 tk para auto/none em Claude 4.x).
messages[] (role/content)SimBlocos text, image, document, tool_use, tool_result, thinking (regras especiais — §A.6).
thinking (config)SimApenas o config inicial; o budget declarado de output não conta como input.
cache_control em qualquer blocoTokenizado normalmente; não dispara cacheAceito sintaticamente, ignorado em runtime. §A.10.
+
+ +

Resposta

+
{ "input_tokens": 1551 }
+
+ É uma estimativa. A doc oficial declara: "The token count should be considered an estimate. In some cases, the actual number of input tokens used when creating a message may differ by a small amount." A diferença típica é de poucos tokens em uma direção ou outra, devido a otimizações internas. Para previsão de custo em produção, considere um buffer de ~2–5% para margem. +
+
+ System-added tokens não são cobrados. A Anthropic pode adicionar tokens automaticamente para otimizações internas; eles podem aparecer no count e no usage real do messages.create, mas não entram na sua fatura — o billing reflete apenas o conteúdo que você enviou. +
+ +

A.3 Modelos suportados

+

+ Todos os modelos ativos suportam token counting (citação literal da doc: "All active models support token counting"). Em 24/maio/2026 isto inclui: +

+
    +
  • claude-opus-4-8 — frontier, 1M ctx, hi-res vision (4784 tk / imagem em até 2576 px), tokenizador novo (+35% vs gerações anteriores)
  • +
  • claude-sonnet-4-6 — workhorse, 1M ctx, extended thinking, vision std (1568 tk / imagem)
  • +
  • claude-haiku-4-5 — low-latency, 200k ctx, vision std
  • +
+
+ Tokenize com o modelo de destino. Famílias diferentes podem ter pequenas variações de tokenização; Opus 4.8 em particular usa um tokenizador distinto. Se você está roteando entre Haiku e Opus, conte separadamente para cada — não extrapole a partir de um único modelo. +
+ +

A.4 Texto puro — basic message + system

+

Exemplo da doc: system "You are a scientist" + user "Hello, Claude" → 14 tokens.

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+response = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    system="You are a scientist",
+    messages=[{"role": "user", "content": "Hello, Claude"}],
+)
+
+print(response.input_tokens)  # 14
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const response = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  system: "You are a scientist",
+  messages: [{ role: "user", content: "Hello, Claude" }],
+});
+
+console.log(response.input_tokens); // 14
+
+
+ +

A.5 Tools — schemas pesam muito

+

+ Definições de tools são serializadas e tokenizadas como parte do input. Uma única ferramenta simples get_weather (string location, descrição curta) sobe a contagem de ~14 tk para ~403 tk no exemplo oficial — quase 30× a mensagem de usuário sozinha. + Cada tool adicional, cada campo no schema, cada descrição extensa, cada enum exaustivo paga aluguel em todos os turnos. +

+

+ A doc de pricing ainda detalha o overhead do system prompt de tool use (separado do schema): 346 tokens com tool_choice = auto/none e 313 tokens com any/tool, em toda a família Claude 4.x (Opus 4.8, Sonnet 4.6, Haiku 4.5). Esse overhead já vem somado no número devolvido por count_tokens. +

+
+ Server tools (web search, computer use, code execution) só contam na primeira sampling call. Após o primeiro turno do agente, o overhead do schema não é re-contado para invocações subsequentes do mesmo tool dentro do loop. Isso é diferente das function tools customizadas, que reentram a cada turno. +
+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+response = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    tools=[
+        {
+            "name": "get_weather",
+            "description": "Get the current weather in a given location",
+            "input_schema": {
+                "type": "object",
+                "properties": {
+                    "location": {
+                        "type": "string",
+                        "description": "The city and state, e.g. San Francisco, CA",
+                    }
+                },
+                "required": ["location"],
+            },
+        }
+    ],
+    messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
+)
+
+print(response.input_tokens)  # 403
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const response = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  tools: [
+    {
+      name: "get_weather",
+      description: "Get the current weather in a given location",
+      input_schema: {
+        type: "object",
+        properties: {
+          location: {
+            type: "string",
+            description: "The city and state, e.g. San Francisco, CA",
+          },
+        },
+        required: ["location"],
+      },
+    },
+  ],
+  messages: [{ role: "user", content: "What's the weather like in San Francisco?" }],
+});
+
+console.log(response.input_tokens); // 403
+
+
+ +

A.6 Imagens — fórmula (W·H)/750 e hi-res Opus 4.8

+

+ Para uma única imagem JPEG hospedada (a famosa foto da formiga Camponotus flavomarginatus, ~1024 px de lado longo) + 1 frase de prompt em claude-opus-4-8, o count retorna 1551 tokens — coerente com a fórmula oficial: +

+
tokens_image ≈ (width × height) / 750
+

Tetos práticos por família de modelo (do guia de visão da Anthropic):

+
+ + + + + + + +
Resolução máxima nativa e tokens por imagem, por família de modelo
FamíliaResolução máx. nativaTokens máx. por imagem
claude-opus-4-8 (hi-res automático, sem header beta)2576 px no lado longo~4784 tk
Std: Sonnet 4.6, Haiku 4.51568 px no lado longo~1568 tk
+
+

+ Imagens maiores são downsampled antes da tokenização (com padding ao múltiplo de 28 px no canto inferior-direito) — você paga pelo tamanho após downscale, não pelo bruto. Para + contar com precisão, conte exatamente o payload que será enviado (mesmo source type, mesma resolução). +

+
+ + + + + + + + + + +
Exemplos numéricos da fórmula (W·H)/750 — Sonnet 4.6 vs Opus 4.8
DimensãoPixelsSonnet 4.6 (cap 1568)Opus 4.8 (cap 4784)
384 × 384147.456~197 tk~197 tk
768 × 768589.824~786 tk~786 tk
1024 × 768786.432~1.048 tk~1.048 tk
1568 × 15682.458.624~1.568 tk (cap)~3.278 tk
2576 × 25766.635.776~1.568 tk (downsample)~4.784 tk (cap)
+
+

+ Em escala: 10 imagens 1024×768 ≈ 10.480 tk; 10 imagens hi-res em Opus 4.8 (≥1568 px) podem subir para 32.000–47.840 tk + — diferença de 3× em volume e custo, com o mesmo lote semântico. +

+
+
+ + +
+
+
import anthropic, base64, httpx
+
+client = anthropic.Anthropic()
+
+img_url = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
+img_b64 = base64.standard_b64encode(httpx.get(img_url).content).decode("utf-8")
+
+response = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "image", "source": {
+                "type": "base64",
+                "media_type": "image/jpeg",
+                "data": img_b64,
+            }},
+            {"type": "text", "text": "Describe this image"},
+        ],
+    }],
+)
+
+print(response.input_tokens)  # 1551
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+const url = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg";
+const buf = Buffer.from(await (await fetch(url)).arrayBuffer()).toString("base64");
+
+const response = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  messages: [{
+    role: "user",
+    content: [
+      { type: "image", source: { type: "base64", media_type: "image/jpeg", data: buf } },
+      { type: "text", text: "Describe this image" },
+    ],
+  }],
+});
+
+console.log(response.input_tokens); // 1551
+
+
+ +

Múltiplas imagens em uma mesma mensagem

+

+ O custo escala linearmente com o número de imagens — não há desconto por lote. Limite oficial: 100 imagens/request em modelos de 200k ctx (Haiku 4.5), 600 imagens/request em modelos de 1M ctx (Opus 4.8, Sonnet 4.6). Para muitas imagens, use Files API (§A.11) para evitar estourar 32 MB de payload. +

+
+
+ + +
+
+
import anthropic, base64, httpx
+
+client = anthropic.Anthropic()
+
+def img_block(url, mtype):
+    data = base64.standard_b64encode(httpx.get(url).content).decode("utf-8")
+    return {"type": "image", "source": {"type": "base64", "media_type": mtype, "data": data}}
+
+content = [
+    img_block("https://upload.wikimedia.org/.../ant.jpg",   "image/jpeg"),
+    img_block("https://upload.wikimedia.org/.../bee1.jpg",  "image/jpeg"),
+    img_block("https://upload.wikimedia.org/.../demo.png",  "image/png"),
+    {"type": "text", "text": "Compare these three images side by side."},
+]
+
+probe = client.messages.count_tokens(
+    model="claude-sonnet-4-6",  # cap 1568 tk/img → previsível
+    messages=[{"role": "user", "content": content}],
+)
+print(f"3 imagens + texto → {probe.input_tokens} tk")
+# Esperado: ~3 × ~1500 + texto ≈ 4500–4700 tk
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+const client = new Anthropic();
+
+async function imgBlock(url: string, mtype: string) {
+  const buf = Buffer.from(await (await fetch(url)).arrayBuffer()).toString("base64");
+  return { type: "image" as const, source: { type: "base64" as const, media_type: mtype, data: buf } };
+}
+
+const content = [
+  await imgBlock("https://.../ant.jpg",  "image/jpeg"),
+  await imgBlock("https://.../bee1.jpg", "image/jpeg"),
+  await imgBlock("https://.../demo.png", "image/png"),
+  { type: "text" as const, text: "Compare these three images side by side." },
+];
+
+const probe = await client.messages.countTokens({
+  model: "claude-sonnet-4-6",
+  messages: [{ role: "user", content }],
+});
+console.log(`3 imagens + texto → ${probe.input_tokens} tk`);
+
+
+ +

A.7 PDF — document block

+

+ PDFs entram via blocos document e são tokenizados como combinação de página renderizada (imagem) + texto extraído. + O exemplo oficial — o Claude-3 Model Card October Addendum — resulta em 2188 tokens. A doc indica como referência: 1.500–3.000 tk por página dependendo da densidade visual. +

+
+ Limites herdados do Messages API: 32 MB por request, até 600 páginas em modelos de 1M ctx (Opus 4.8, Sonnet 4.6), até 100 páginas em Haiku 4.5 (200k ctx). PDFs grandes devem ir pela Files API e ser referenciados por file_id para manter payload pequeno. Em Bedrock/Vertex, o limite efetivo de payload é menor (30 MB). +
+ +

Três tipos de document.source

+

Além de base64 e url, a Messages API aceita text (PlainTextSource) e content (ContentBlockSource) para conteúdos não-PDF — úteis quando você quer que o modelo trate um payload como "documento" (para citations, por exemplo) sem renderização visual. Tokenização nesses casos é puro texto extraído: sem custo de imagem por página.

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+# (a) PlainTextSource: texto cru tratado como "documento"
+resp_text = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {
+                "type": "text",
+                "media_type": "text/plain",
+                "data": "Section 1. Definitions. ...long text...",
+            }, "title": "Contract"},
+            {"type": "text", "text": "Resume os pontos principais."},
+        ],
+    }],
+)
+print("texto:", resp_text.input_tokens)
+
+# (b) ContentBlockSource: blocos prontos (text/image) embrulhados como documento
+resp_blocks = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "document", "source": {
+                "type": "content",
+                "content": [
+                    {"type": "text", "text": "Quarterly revenue rose 18% YoY."},
+                    {"type": "text", "text": "Operating margin held at 22.4%."},
+                ],
+            }, "title": "Earnings excerpts"},
+            {"type": "text", "text": "Quais foram os KPIs financeiros?"},
+        ],
+    }],
+)
+print("blocks:", resp_blocks.input_tokens)
+# Diferença vs base64 PDF: nenhum custo de "página como imagem".
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+const client = new Anthropic();
+
+// (a) PlainTextSource
+const respText = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  messages: [{ role: "user", content: [
+    { type: "document",
+      source: { type: "text", media_type: "text/plain", data: "Section 1. Definitions. ...long text..." },
+      title: "Contract" },
+    { type: "text", text: "Resume os pontos principais." },
+  ]}],
+});
+console.log("texto:", respText.input_tokens);
+
+// (b) ContentBlockSource
+const respBlocks = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  messages: [{ role: "user", content: [
+    { type: "document",
+      source: { type: "content", content: [
+        { type: "text", text: "Quarterly revenue rose 18% YoY." },
+        { type: "text", text: "Operating margin held at 22.4%." },
+      ]},
+      title: "Earnings excerpts" },
+    { type: "text", text: "Quais foram os KPIs financeiros?" },
+  ]}],
+});
+console.log("blocks:", respBlocks.input_tokens);
+
+
+ +

Citations habilitado: muda o count?

+

+ Habilitar citations: { "enabled": true } em um bloco document não adiciona tokens ao input contado — a flag é metadata processada pelo backend para emitir blocos citation na resposta (que pesam em output_tokens, não no input). Você pode verificar isso comparando o mesmo payload com e sem a flag: o input_tokens retornado é idêntico. +

+
+
+ + +
+
+
import anthropic, base64
+
+client = anthropic.Anthropic()
+with open("paper.pdf", "rb") as f:
+    pdf_b64 = base64.standard_b64encode(f.read()).decode("utf-8")
+
+doc_no_cit = {"type": "document", "source": {"type": "base64", "media_type": "application/pdf", "data": pdf_b64}}
+doc_cit    = {**doc_no_cit, "citations": {"enabled": True}}
+
+for label, doc in [("sem citations", doc_no_cit), ("com citations", doc_cit)]:
+    r = client.messages.count_tokens(
+        model="claude-opus-4-8",
+        messages=[{"role": "user", "content": [doc, {"type": "text", "text": "Cite os achados."}]}],
+    )
+    print(label, "→", r.input_tokens)
+# Output esperado: mesmo input_tokens nos dois.
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+import { readFile } from "fs/promises";
+const client = new Anthropic();
+const pdfB64 = await readFile("paper.pdf", { encoding: "base64" });
+
+const docNoCit = { type: "document" as const, source: { type: "base64" as const, media_type: "application/pdf", data: pdfB64 } };
+const docCit   = { ...docNoCit, citations: { enabled: true } };
+
+for (const [label, doc] of [["sem citations", docNoCit], ["com citations", docCit]] as const) {
+  const r = await client.messages.countTokens({
+    model: "claude-opus-4-8",
+    messages: [{ role: "user", content: [doc, { type: "text", text: "Cite os achados." }] }],
+  });
+  console.log(label, "→", r.input_tokens);
+}
+// Output esperado: input_tokens idêntico nos dois casos.
+
+
+ +

A.8 Extended thinking — regra crítica

+
+ Regra de contagem assimétrica (texto literal da doc): +
    +
  • "Thinking blocks from previous assistant turns are ignored and do not count toward your input tokens"
  • +
  • "Current assistant turn thinking does count toward your input tokens"
  • +
+ Isso afeta diretamente o orçamento de janela em conversas multi-turno com extended thinking ativo: o histórico de raciocínio interno não infla o ITPM no count. +
+
+ Nuance — billing real com tool use. Em Opus 4.8 / Sonnet 4.6, blocos thinking de turnos anteriores são preservados em conversas com tool use, e quando reenviados para o modelo entram como cache reads no billing real (não como input bruto). Em modelos anteriores e em toda a família Haiku, blocos thinking antigos são removidos do contexto. count_tokens sempre aplica a regra "ignora thinking anterior", então pode subestimar o cache read que o messages.create efetivamente registra em usage.cache_read_input_tokens. +
+

+ Exemplo da doc com claude-sonnet-4-6, thinking.budget_tokens: 16000, e três mensagens (user → assistant com bloco thinking + bloco text → user) → 88 tokens. Esse número baixo é resultado direto do bloco thinking do turno anterior ter sido descartado pelo count. +

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+response = client.messages.count_tokens(
+    model="claude-sonnet-4-6",
+    thinking={"type": "enabled", "budget_tokens": 16000},
+    messages=[
+        {"role": "user", "content": "Are there an infinite number of prime numbers such that n mod 4 == 3?"},
+        {"role": "assistant", "content": [
+            {
+                "type": "thinking",
+                "thinking": "This is a nice number theory question. Let's think about it step by step...",
+                "signature": "EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...",
+            },
+            {"type": "text", "text": "Yes, there are infinitely many prime numbers p such that p mod 4 = 3..."},
+        ]},
+        {"role": "user", "content": "Can you write a formal proof?"},
+    ],
+)
+
+print(response.input_tokens)  # 88 — thinking do turno anterior foi ignorado
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const response = await client.messages.countTokens({
+  model: "claude-sonnet-4-6",
+  thinking: { type: "enabled", budget_tokens: 16000 },
+  messages: [
+    { role: "user", content: "Are there an infinite number of prime numbers such that n mod 4 == 3?" },
+    { role: "assistant", content: [
+      {
+        type: "thinking",
+        thinking: "This is a nice number theory question. Let's think about it step by step...",
+        signature: "EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...",
+      },
+      { type: "text", text: "Yes, there are infinitely many prime numbers p such that p mod 4 = 3..." },
+    ]},
+    { role: "user", content: "Can you write a formal proof?" },
+  ],
+});
+
+console.log(response.input_tokens); // 88
+
+
+ +

A.9 Server tools — apenas primeira sampling call

+

+ Para server tools (gerenciadas pela Anthropic — web search, computer use, code execution, web fetch, etc.), o token counting só se aplica à primeira sampling call dentro do loop do agente. As invocações subsequentes do mesmo tool dentro do mesmo turno não pagam novamente pelo schema embutido. Esse comportamento é específico de server tools e não vale para tools de cliente (function calling tradicional), que reentram em cada turno. +

+

Overheads de schema documentados (somados pelo backend automaticamente):

+
+ + + + + + + + + + + +
Custo de schema (system-prompt overhead) por server tool em Claude 4.x
ToolTokens adicionaisCobrança extra
computer_use466–499 (system) + 735 (def)Padrão por input/output
text_editor_20250429700Padrão por input/output
bash245Padrão
web_searchVariável (resultados como input)$10 por 1.000 buscas
web_fetchVariável (conteúdo como input)Sem custo extra
code_executionSchema + outputs$0,05/h após 1.550 h grátis/mês
+
+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+# Pré-contar uma chamada com server tool (web_search) habilitado.
+# O count reflete APENAS o primeiro sampling: o schema do tool é somado uma vez.
+response = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    tools=[{
+        "type": "web_search_20260209",
+        "name": "web_search",
+        "max_uses": 5,
+    }],
+    messages=[{
+        "role": "user",
+        "content": "Search for the latest Anthropic SDK release and summarize the changelog.",
+    }],
+)
+print("primeira sampling →", response.input_tokens)
+
+# Em messages.create real, o usage.input_tokens do PRIMEIRO message_start
+# bate com este número; mas os turnos subsequentes do mesmo loop de agente
+# NÃO re-cobram o schema (só o conteúdo retornado pela tool).
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const response = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  tools: [{ type: "web_search_20260209", name: "web_search", max_uses: 5 }],
+  messages: [{
+    role: "user",
+    content: "Search for the latest Anthropic SDK release and summarize the changelog.",
+  }],
+});
+console.log("primeira sampling →", response.input_tokens);
+
+
+ +

A.10 Token counting NÃO usa prompt caching

+
+ Pegadinha frequente (citação literal da FAQ oficial): "No, token counting provides an estimate without using caching logic. While you may provide cache_control blocks in your token counting request, prompt caching only occurs during actual message creation." +
+

+ Consequência prática: o número que count_tokens devolve é sempre o input total bruto, sem o desconto que cache aplicaria. Para previsão de custo com cache, calcule manualmente: +

+
# Custo aproximado de input (USD) com cache hit:
+#   custo_input = (input_cached_5m_write × 1.25 × preço_base)
+#               + (input_cached_1h_write × 2.00 × preço_base)
+#               + (input_cache_read     × 0.10 × preço_base)
+#               + (input_uncached       × 1.00 × preço_base)
+

+ Mínimos de tokens para que o cache efetivamente dispare (abaixo disto a chamada é processada sem cache, sem erro): +

+
+ + + + + + + + +
Mínimo cacheável e número máximo de breakpoints por modelo
ModeloMínimo cacheávelMáx. cache_control por request
claude-opus-4-84.096 tk4
claude-sonnet-4-61.024 tk4
claude-haiku-4-54.096 tk4
+
+ +

Cache_control multi-camada — System + Tools + Messages

+

+ Padrão real de produção: marcar prefixos estáveis (system + tools + few-shots) com cache_control para que reentrem como cache reads. count_tokens devolve o input cru, mas em messages.create real o usage separa cache_creation_input_tokens, cache_read_input_tokens e input_tokens (uncached). +

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+LONG_SYSTEM = open("system_prompt.md").read()      # >4096 tk de instruções estáveis
+LONG_TOOLS  = [...]                                # array com schemas pesados
+FEW_SHOTS   = [...]                                # demonstrações estáveis
+
+req = dict(
+    model="claude-opus-4-8",
+    system=[
+        {"type": "text", "text": LONG_SYSTEM, "cache_control": {"type": "ephemeral"}},
+    ],
+    tools=[
+        *LONG_TOOLS[:-1],
+        # marcar o último tool dispara cache de TODO o array de tools até aqui
+        {**LONG_TOOLS[-1], "cache_control": {"type": "ephemeral"}},
+    ],
+    messages=[
+        *FEW_SHOTS[:-1],
+        {**FEW_SHOTS[-1], "content": [
+            *FEW_SHOTS[-1]["content"][:-1],
+            {**FEW_SHOTS[-1]["content"][-1], "cache_control": {"type": "ephemeral"}},
+        ]},
+        {"role": "user", "content": "Pergunta dinâmica do turno."},
+    ],
+)
+
+# Count: vê tudo como input bruto (não desconta o que VAI ser cacheado)
+probe = client.messages.count_tokens(**req)
+print("count (bruto) →", probe.input_tokens)
+
+# Criação real: usage discrimina write vs read vs uncached
+msg = client.messages.create(**req, max_tokens=512)
+u = msg.usage
+print("cache_creation →", u.cache_creation_input_tokens)  # 1ª chamada
+print("cache_read     →", u.cache_read_input_tokens)      # chamadas seguintes
+print("input (uncach) →", u.input_tokens)                 # delta do turno
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+const client = new Anthropic();
+
+const req = {
+  model: "claude-opus-4-8" as const,
+  system: [{ type: "text" as const, text: LONG_SYSTEM, cache_control: { type: "ephemeral" as const } }],
+  tools: [...LONG_TOOLS.slice(0, -1),
+          { ...LONG_TOOLS.at(-1)!, cache_control: { type: "ephemeral" as const } }],
+  messages: [...fewShotsWithFinalCacheControl,
+             { role: "user" as const, content: "Pergunta dinâmica do turno." }],
+};
+
+const probe = await client.messages.countTokens(req);
+console.log("count (bruto) →", probe.input_tokens);
+
+const msg = await client.messages.create({ ...req, max_tokens: 512 });
+console.log("cache_creation →", msg.usage.cache_creation_input_tokens);
+console.log("cache_read     →", msg.usage.cache_read_input_tokens);
+console.log("input (uncach) →", msg.usage.input_tokens);
+
+
+ +

A.11 Files API — referência por file_id

+

+ Quando você usa a Files API beta para evitar base64 grande, o endpoint de contagem aceita o mesmo source.type=file com file_id que o messages.create. Requer o header beta files-api-2025-04-14 e o arquivo já carregado em /v1/files. O conteúdo do arquivo (imagem ou PDF) é tokenizado integralmente — não há desconto por estar em armazenamento Files. +

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+# 1) upload prévio via Files API
+with open("photo.jpg", "rb") as f:
+    upload = client.beta.files.upload(file=("photo.jpg", f, "image/jpeg"))
+
+# 2) contagem usando file_id (precisa do beta header)
+response = client.beta.messages.count_tokens(
+    model="claude-opus-4-8",
+    betas=["files-api-2025-04-14"],
+    messages=[{
+        "role": "user",
+        "content": [
+            {"type": "image", "source": {"type": "file", "file_id": upload.id}},
+            {"type": "text", "text": "Describe this image."},
+        ],
+    }],
+)
+
+print(response.input_tokens)
+
+
+
import Anthropic, { toFile } from "@anthropic-ai/sdk";
+import fs from "fs";
+
+const client = new Anthropic();
+
+const upload = await client.beta.files.upload({
+  file: await toFile(fs.createReadStream("photo.jpg"), undefined, { type: "image/jpeg" }),
+});
+
+const response = await client.beta.messages.countTokens({
+  model: "claude-opus-4-8",
+  betas: ["files-api-2025-04-14"],
+  messages: [{
+    role: "user",
+    content: [
+      { type: "image", source: { type: "file", file_id: upload.id } },
+      { type: "text", text: "Describe this image." },
+    ],
+  }],
+});
+
+console.log(response.input_tokens);
+
+
+ +

Combinando múltiplos anthropic-beta em count_tokens

+

+ O SDK aceita o array betas=[...] que vira o header anthropic-beta: a,b,c. Quando você precisa, por exemplo, de Files API + um beta de tool específico, passe todos no mesmo array. Para chamadas REST diretas, use extra_headers: +

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+# Via SDK: array nativo
+resp = client.beta.messages.count_tokens(
+    model="claude-opus-4-8",
+    betas=["files-api-2025-04-14", "context-management-2025-06-27"],
+    messages=[...],
+)
+
+# Via extra_headers (acesso raw)
+resp_raw = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    messages=[...],
+    extra_headers={
+        "anthropic-beta": "files-api-2025-04-14,context-management-2025-06-27",
+    },
+)
+print(resp_raw.input_tokens)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const resp = await client.beta.messages.countTokens({
+  model: "claude-opus-4-8",
+  betas: ["files-api-2025-04-14", "context-management-2025-06-27"],
+  messages: [/* ... */],
+});
+
+const respRaw = await client.messages.countTokens(
+  { model: "claude-opus-4-8", messages: [/* ... */] },
+  { headers: { "anthropic-beta": "files-api-2025-04-14,context-management-2025-06-27" } },
+);
+console.log(respRaw.input_tokens);
+
+
+ +

A.12 Comparação entre modelos — mesmo payload

+

+ Tokenizações entre famílias divergem em pequena escala — exceto Opus 4.8, que usa um tokenizador novo e pode contar até 35% mais para o mesmo texto. Sempre conte com o modelo de destino real antes de rotear. +

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+PAYLOAD = dict(
+    system="You are an expert tax analyst specialized in Brazilian fiscal law.",
+    messages=[{
+        "role": "user",
+        "content": (
+            "Explique as diferenças entre Lucro Real, Lucro Presumido e Simples Nacional "
+            "para uma empresa de software com faturamento anual de R$ 8 milhões. "
+            "Inclua alíquotas efetivas estimadas e riscos de planejamento tributário."
+        ),
+    }],
+)
+
+for model in ["claude-haiku-4-5", "claude-sonnet-4-6", "claude-opus-4-8"]:
+    r = client.messages.count_tokens(model=model, **PAYLOAD)
+    print(f"{model:24s} → {r.input_tokens:5d} tk")
+# Exemplo de saída típica:
+# claude-haiku-4-5         →    97 tk
+# claude-sonnet-4-6        →    97 tk
+# claude-opus-4-8          →   115 tk   (~+18% pelo tokenizador novo)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const payload = {
+  system: "You are an expert tax analyst specialized in Brazilian fiscal law.",
+  messages: [{
+    role: "user" as const,
+    content: "Explique as diferenças entre Lucro Real, Lucro Presumido e Simples Nacional ...",
+  }],
+};
+
+for (const model of ["claude-haiku-4-5", "claude-sonnet-4-6", "claude-opus-4-8"] as const) {
+  const r = await client.messages.countTokens({ model, ...payload });
+  console.log(`${model.padEnd(24)} → ${r.input_tokens} tk`);
+}
+
+
+ +

A.13 Streaming — usage em message_start e message_delta

+

+ O endpoint count_tokens é sempre síncrono — não aceita stream. Mas o próprio messages.create em modo streaming já entrega input_tokens antecipado no primeiro evento message_start (antes da geração começar), e o output_tokens cumulativo no evento final message_delta. +

+
+ Cumulativo em message_delta. Doc oficial: "The token counts shown in the usage field of the message_delta event are cumulative." Não some incrementalmente — leia o último message_delta antes do message_stop. +
+

Forma típica dos eventos SSE:

+
event: message_start
+data: {"type":"message_start","message":{"model":"claude-opus-4-8",
+  "usage":{"input_tokens":2679,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":3}}}
+
+event: message_delta
+data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},
+  "usage":{"input_tokens":10682,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,
+           "output_tokens":510,"server_tool_use":{"web_search_requests":1}}}
+
+event: message_stop
+data: {"type":"message_stop"}
+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+# 1) Pré-contar (síncrono)
+probe = client.messages.count_tokens(
+    model="claude-opus-4-8",
+    messages=[{"role": "user", "content": "Resuma a Constituição em 3 parágrafos."}],
+)
+print("estimativa →", probe.input_tokens)
+
+# 2) Streamar e capturar usage em message_start (antecipado) e message_delta (cumulativo)
+final_usage = None
+with client.messages.stream(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    messages=[{"role": "user", "content": "Resuma a Constituição em 3 parágrafos."}],
+) as stream:
+    for event in stream:
+        if event.type == "message_start":
+            print("input_tokens (real)  →", event.message.usage.input_tokens)
+        elif event.type == "message_delta":
+            final_usage = event.usage  # cumulativo
+    msg = stream.get_final_message()
+
+print("output_tokens (final) →", final_usage.output_tokens)
+print("delta vs estimativa   →", msg.usage.input_tokens - probe.input_tokens)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+const probe = await client.messages.countTokens({
+  model: "claude-opus-4-8",
+  messages: [{ role: "user", content: "Resuma a Constituição em 3 parágrafos." }],
+});
+console.log("estimativa →", probe.input_tokens);
+
+let finalUsage: Anthropic.Messages.MessageDeltaUsage | null = null;
+const stream = client.messages.stream({
+  model: "claude-opus-4-8",
+  max_tokens: 1024,
+  messages: [{ role: "user", content: "Resuma a Constituição em 3 parágrafos." }],
+});
+
+for await (const event of stream) {
+  if (event.type === "message_start") {
+    console.log("input_tokens (real) →", event.message.usage.input_tokens);
+  } else if (event.type === "message_delta") {
+    finalUsage = event.usage;
+  }
+}
+const msg = await stream.finalMessage();
+console.log("output_tokens (final) →", finalUsage?.output_tokens);
+console.log("delta vs estimativa   →", msg.usage.input_tokens - probe.input_tokens);
+
+
+ +

A.14 Message Batches — 50% off, pré-contagem em escala

+

+ Para volumes grandes, a Message Batches API entrega 50% de desconto em input e output (Opus 4.8 → $2,50/MTok input, $12,50/MTok output). O endpoint messages/count_tokens não tem modo batch dedicado, mas é grátis e tem alto RPM (até 8.000/min em Tier 4) — pré-conte cada request do JSONL antes de submeter o batch para escolher modelo, projetar custo, e validar limite de janela. +

+

+ Padrão recomendado: itere o array de requests, chame count_tokens para cada um, acumule, e só depois submeta o batch. Se algum item ultrapassa o contexto do modelo escolhido, faça split antes — batches que falham por exceder janela são contabilizados como erro. +

+
+
+ + +
+
+
import anthropic, asyncio
+
+client = anthropic.AsyncAnthropic()
+
+requests = [
+    {"custom_id": f"doc-{i}",
+     "params": {
+         "model": "claude-opus-4-8",
+         "max_tokens": 512,
+         "messages": [{"role": "user", "content": payload}],
+     }}
+    for i, payload in enumerate(BIG_PAYLOAD_LIST)  # 1000 requests
+]
+
+# 1) Pré-contar em paralelo (RPM=8000 no Tier 4)
+sem = asyncio.Semaphore(50)
+async def count_one(r):
+    async with sem:
+        probe = await client.messages.count_tokens(
+            model=r["params"]["model"],
+            messages=r["params"]["messages"],
+        )
+        return r["custom_id"], probe.input_tokens
+
+async def main():
+    counts = dict(await asyncio.gather(*(count_one(r) for r in requests)))
+    total_in = sum(counts.values())
+    # Custo estimado em Opus 4.8 com 50% off (batch):
+    cost_in  = total_in * (5.0 / 2) / 1_000_000   # $2.50 / MTok
+    cost_out = 1000 * 512 * (25.0 / 2) / 1_000_000  # worst case com max_tokens
+    print(f"total input tk: {total_in:,}  ≈ ${cost_in:.2f} (batch input)")
+    print(f"worst-case out: {cost_out:.2f}")
+
+    # 2) Submeter batch
+    batch = await client.messages.batches.create(requests=requests)
+    print("batch id:", batch.id)
+
+asyncio.run(main())
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+const client = new Anthropic();
+
+const requests = BIG_PAYLOAD_LIST.map((payload, i) => ({
+  custom_id: `doc-${i}`,
+  params: {
+    model: "claude-opus-4-8" as const,
+    max_tokens: 512,
+    messages: [{ role: "user" as const, content: payload }],
+  },
+}));
+
+const limit = 50;
+const counts = new Map();
+for (let i = 0; i < requests.length; i += limit) {
+  const slice = requests.slice(i, i + limit);
+  const results = await Promise.all(slice.map(async r => {
+    const probe = await client.messages.countTokens({ model: r.params.model, messages: r.params.messages });
+    return [r.custom_id, probe.input_tokens] as const;
+  }));
+  results.forEach(([k, v]) => counts.set(k, v));
+}
+
+const totalIn = [...counts.values()].reduce((a, b) => a + b, 0);
+console.log(`total input tk: ${totalIn}  ≈ $${(totalIn * 2.5 / 1_000_000).toFixed(2)} (batch)`);
+
+const batch = await client.messages.batches.create({ requests });
+console.log("batch id:", batch.id);
+
+
+ +

A.15 Rate limits do endpoint

+

+ count_tokens tem rate limits independentes de messages.create. Bater no limite de criação não bloqueia contagens, e vice-versa. +

+
+ + + + + + + + + +
Rate limits de messages/count_tokens por usage tier
Usage tierRequests por minuto (RPM)
Tier 1100
Tier 22.000
Tier 34.000
Tier 48.000
+
+

Para limites maiores, contato com vendas via console.anthropic.com → Settings → Limits. Tiers acima de 4 são por enterprise contract.

+ +

A.16 Pricing comparativo — Opus 4.8 / Sonnet 4.6 / Haiku 4.5

+
+ Token counting é gratuito. Você é cobrado apenas pelas chamadas reais a messages.create. O único custo de chamar count_tokens é o seu RPM no tier — o que torna seguro chamar antes de cada request crítico em produção, ou em batch para auditoria de pipelines. +
+

Preços oficiais (USD/MTok) coletados em claude.com/pricing em 24/maio/2026:

+
+ + + + + + + + + + + + + + + + + +
Tabela de preços por modelo — input, cache writes (5m/1h), cache reads, output
ModeloInputCache write 5m (1,25×)Cache write 1h (2,0×)Cache read (0,1×)Output
claude-opus-4-8 $5,00 $6,25 $10,00 $0,50 $25,00
claude-sonnet-4-6 $3,00 $3,75 $6,00 $0,30 $15,00
claude-haiku-4-5 $1,00 $1,25 $2,00 $0,10 $5,00
+
+

Multiplicadores que combinam com a tabela acima:

+
    +
  • Message Batches: 0,5× em input e output (Opus 4.8 batch input = $2,50/MTok; output = $12,50/MTok).
  • +
  • Data residency (inference_geo: "us"): 1,1× em todas as categorias (Opus 4.8 / Sonnet 4.6).
  • +
  • Fast mode (Opus 4.8, research preview): 6× ($30/MTok input, $150/MTok output). Não combina com Batch.
  • +
  • Bedrock/Vertex AI endpoints regionais ou multi-region: +10% sobre endpoints global (Opus 4.8 / Sonnet 4.6 / Haiku 4.5).
  • +
+ +

A.17 Bedrock / Vertex AI — suporte ao endpoint

+

+ Resolução do antigo UNVERIFIED: em 24/maio/2026, segundo as docs oficiais de Amazon Bedrock e Vertex AI, o endpoint messages/count_tokens NÃO consta na lista de "Supported feature highlights" de nenhum dos dois ambientes geridos. A doc lista explicitamente em "Features not supported": "API endpoints (Message Batches, Models, Admin, Compliance, Usage and Cost)" — token counting não aparece entre as APIs habilitadas. Suportados são apenas /v1/messages (Messages API), prompt caching, extended thinking, tool use, citations e structured outputs. +

+
+ Implicação prática. Em pipelines rodando via Bedrock (AnthropicBedrockMantle) ou Vertex (AnthropicVertex), não existe client.messages.count_tokens(...) funcional — chamar resultará em erro de roteamento. Workaround para pré-contagem nesses ambientes: manter uma conexão paralela à Claude API first-party usando o mesmo modelo (claude-opus-4-8, claude-haiku-4-5, etc.) apenas para count_tokens; a tokenização é idêntica entre first-party e Bedrock/Vertex para o mesmo nome de modelo. Considere também limitações de fonte: Bedrock e Vertex só aceitam source.type=base64 para imagens e PDFs — URL e Files API ficam fora. +
+

+ Limites de payload diferentes em ambientes geridos: +

+
    +
  • Vertex AI: 30 MB por request (vs. 32 MB first-party).
  • +
  • Bedrock: limite de payload herdado das regras do Bedrock InvokeModel/Converse; varia por tipo de endpoint.
  • +
+ +

A.18 Caveats e armadilhas

+
    +
  • Estimate, não exato: aceite ±2–5% de variação entre count_tokens e o usage.input_tokens real do messages.create.
  • +
  • System-added tokens: podem aparecer na contagem (e no usage), mas você não é cobrado por eles. Não use o número para calcular custo cru — use para cap de janela.
  • +
  • Cache silencioso: cache_control em count_tokens é no-op; nunca confunda o número retornado com "input não-cacheado". Para isso, faça a chamada real e leia usage.cache_read_input_tokens + usage.cache_creation_input_tokens.
  • +
  • Modelo importa muito em Opus 4.8: tokenizador novo, +35% no pior caso. Sempre passe o modelo de destino exato — não conte com Sonnet/Haiku e use com Opus 4.8.
  • +
  • Tokenize o que você vai enviar: mesma resolução de imagem, mesmo PDF, mesmo histórico, mesmos tools, mesmos betas. Mudar qualquer coisa invalida a contagem.
  • +
  • Server tools: contagem cobre só a primeira sampling call do loop — não some "tools × turnos" para projetar custo.
  • +
  • Extended thinking: thinking de turnos anteriores é ignorado no count, mas no messages.create real (Opus 4.8 / Sonnet 4.6) eles podem entrar como cache reads. Use o usage real para reconciliação.
  • +
  • Streaming: count_tokens não suporta stream — é sempre síncrono. Em messages.create com stream, leia input_tokens no message_start e output_tokens cumulativo no último message_delta.
  • +
  • Citations: habilitar citations.enabled em document não muda o input_tokens; o custo aparece em output_tokens (blocos citation emitidos pelo modelo).
  • +
  • Bedrock / Vertex: endpoint não disponível em ambientes geridos — use first-party para pré-contagem.
  • +
+ +

A.19 Receita: roteador de modelo por tamanho

+

+ Padrão útil em produção: conte uma vez, decida o modelo, então chame messages.create com o melhor candidato. + Headroom típico: deixe ~15% de margem para output e jitter de tokenização. Se vai rotear para Opus 4.8, conte com Opus 4.8 (tokenizador novo, +35%). +

+
+
+ + +
+
+
import anthropic
+
+client = anthropic.Anthropic()
+
+def pick_model(messages, system=None, tools=None):
+    # Probe com Haiku para decisão inicial; reconfere com Opus 4.8 se for roteado para lá.
+    probe = client.messages.count_tokens(
+        model="claude-haiku-4-5",
+        system=system or "",
+        messages=messages,
+        tools=tools or [],
+    )
+    n = probe.input_tokens
+    if n < 150_000:          # cabe folgado em 200k
+        return "claude-haiku-4-5"
+    if n < 800_000:          # cabe em 1M com headroom
+        return "claude-sonnet-4-6"
+    # Recheca em Opus 4.8 (tokenizador novo, +35%)
+    re_probe = client.messages.count_tokens(
+        model="claude-opus-4-8",
+        system=system or "", messages=messages, tools=tools or [],
+    )
+    if re_probe.input_tokens < 850_000:
+        return "claude-opus-4-8"
+    raise ValueError(f"Payload excede janela mesmo em Opus 4.8: {re_probe.input_tokens} tk")
+
+model = pick_model(messages=[{"role": "user", "content": "..."}])
+print("routing →", model)
+
+
+
import Anthropic from "@anthropic-ai/sdk";
+
+const client = new Anthropic();
+
+async function pickModel(args: {
+  messages: Anthropic.MessageParam[];
+  system?: string;
+  tools?: Anthropic.Tool[];
+}) {
+  const probe = await client.messages.countTokens({
+    model: "claude-haiku-4-5",
+    system: args.system ?? "",
+    messages: args.messages,
+    tools: args.tools ?? [],
+  });
+  const n = probe.input_tokens;
+  if (n < 150_000) return "claude-haiku-4-5";
+  if (n < 800_000) return "claude-sonnet-4-6";
+  const reProbe = await client.messages.countTokens({
+    model: "claude-opus-4-8",
+    system: args.system ?? "",
+    messages: args.messages,
+    tools: args.tools ?? [],
+  });
+  if (reProbe.input_tokens < 850_000) return "claude-opus-4-8";
+  throw new Error(`Payload excede janela mesmo em Opus 4.8: ${reProbe.input_tokens} tk`);
+}
+
+const model = await pickModel({ messages: [{ role: "user", content: "..." }] });
+console.log("routing →", model);
+
+
+ +
+ Resumindo Anthropic token counting. Endpoint dedicado POST /v1/messages/count_tokens, grátis, ZDR-eligible, devolve um único input_tokens que é uma estimativa próxima do real (±2–5%). Aceita o mesmo shape do messages.create, incluindo system, tools (overhead 313–346 tk em Claude 4.x), imagens (fórmula (W·H)/750; ~1551 tk para a foto da formiga; cap 1568 tk em Sonnet/Haiku, 4784 tk em Opus 4.8 hi-res), PDFs (~2188 tk para o Claude-3 Model Card), PlainTextSource/ContentBlockSource sem custo de imagem, file_id via Files API, e blocos thinking (com a regra assimétrica: ignora thinking de turnos anteriores). Não dispara prompt caching mesmo com cache_control passado. Suporta streaming via message_start/message_delta no messages.create real, mas o próprio count_tokens é síncrono. Não disponível em Amazon Bedrock nem Google Vertex AI — use a Claude API first-party para pré-contagem. Rate limit independente: 100 / 2.000 / 4.000 / 8.000 RPM por tier 1–4. Pricing 24/05/2026: Opus 4.8 $5/$25, Sonnet 4.6 $3/$15, Haiku 4.5 $1/$5 por MTok (input/output); Message Batches aplica 50% off em ambos. +
+
+ + + + + +
+

§10. Caching nativo + ZDR + captura de custo real

+ +

As três APIs (Responses, google-genai/Interactions/Vertex, Messages) hoje têm máquinas de prompt caching maduras com modos ZDR-elegíveis. Este capítulo consolida — sob a premissa operacional do projeto: store=false default, contexto montado externamente, sem previous_response_id/previous_interaction_id — (a) a matriz ZDR cross-provider, (b) como capturar o custo real chamada-a-chamada e reconciliar com billing, (c) os equivalentes do prompt_cache_key nos outros providers, (d) o que cacheia e o que não cacheia em multimodal (imagem, áudio, vídeo, PDF), e (e) receitas copy & paste para o padrão canônico stateless. Verificado em 2026-06-10 contra docs oficiais (developers.openai.com, ai.google.dev, docs.cloud.google.com, platform.claude.com).

+ +
+ Premissa deste capítulo. Tudo aqui assume que o cliente nunca delega gerenciamento de contexto ao provider: store=false em toda chamada OpenAI/Gemini Interactions; nada de previous_response_id / previous_interaction_id; o cliente monta o payload completo a cada turno. Sob essa premissa, o caching de prefixo continua funcionando nos 3 providers (cache ≠ store), mas alguns mecanismos perdem valor — notadamente o cache implícito da Interactions API, que depende de previous_interaction_id. Veja §10.4. +
+ +

10.1 Visão geral & decisão — qual mecanismo usar quando

+ +
+ Quick-start path (dev de 1 dia, SaaS multi-tenant): +
    +
  1. Decida o provider primário: já está em GCP? → §10.5 Vertex. Anthropic-only? → §10.6. OpenAI-only? → §10.2. Cross-provider? Implemente um por vez.
  2. +
  3. Defina o CostEvent (§10.10) — é o esqueleto reutilizável das 3 superfícies.
  4. +
  5. Cole a receita (§10.11): R1 (OpenAI), R2 (Gemini Vertex), R3 (Anthropic), R4 (Diagnostics), R5 (BigQuery reconcile).
  6. +
  7. Antes de prod: leia §10.12 (15 armadilhas reais) e §10.13 (failover cross-provider invalida cache).
  8. +
+
+ +

Os três providers convergem em duas categorias de cache, com tradeoffs opostos:

+ +
+ + + + + + + + + + + + + + + + + + + + + +
Categorias de cache cross-provider — premissa: store=false stateless
CategoriaComo ativaCustoGarantiaZDRDeterminismo
Implícito / AutomáticoSem código: prefixo ≥ threshold cacheia automaticamente. OpenAI: ≥1024 tk; Gemini Developer: ≥1024 tk Flash / ≥4096 tk Pro; Gemini Interactions: idem; Vertex Implicit: idem (RAM 24h); Anthropic: não tem modo implícito.Sem write fee. Read: −90% input (OpenAI/Gemini 2.5+/Vertex 2.5+/3.x); −75% (Vertex 2.0).OpenAI: garantido se prefixo bate; Gemini: no cost saving guarantee — oportunístico.✅ ZDR-compatible (RAM, 24h, project-isolated).Probabilístico — sujeito a roteamento interno e LRU eviction.
Explícito / Recurso nomeadoOpenAI: prompt_cache_retention + prompt_cache_key (hint de routing); Gemini Developer/Vertex: N/A neste projeto — sem explicit cachedContents (constraint implicit-only; o caminho explícito existe na API mas está fora do escopo, ver §10.3 e §10.5); Anthropic: cache_control:{type:"ephemeral", ttl:"5m"|"1h"} em até 4 breakpoints.Write: OpenAI sem premium · Gemini implicit sem fee de write nem storage · Anthropic 1,25× (5m) ou 2× (1h). Read sempre 0,1× input nos 3 (−90%).Determinístico quando referenciado (OpenAI/Anthropic). Gemini implicit é best-effort, mesmo comportamento da linha "Implícito" acima.OpenAI Extended 24h: ✅ não bloqueado em ZDR; Gemini/Vertex (implicit-only no escopo): ✅ ZDR-elegível (RAM); Anthropic ephemeral: ✅ ZDR-elegível (KV tensors in-memory, deletados no expiry).Forte (OpenAI/Anthropic) · N/A (Gemini, fora de escopo).
+
+ +

5-point discipline para máximo hit rate (cross-provider):

+
    +
  1. Conteúdo estável no topo, variável no fim. Instructions, tools, schemas e RAG no início; user input e timestamps no final. O byte-hash do prefixo precisa ser idêntico turn-a-turn.
  2. +
  3. Pin de shard / cache resource. OpenAI: prompt_cache_key=hash(tenant+session) (cap ~15 RPM/key). Gemini/Vertex (implícito-only neste projeto): não há pin user-facing — o backend faz prefix-match oportunístico e cobra com desconto se bater. Anthropic: cache é determinístico por (workspace × prefix bytes × model). Detalhe em §10.8.
  4. +
  5. Serialização determinística. JSON com sort_keys=True para tools/schemas. Go map default e Swift Dictionary reorderam — quebra o hash silenciosamente.
  6. +
  7. Bytes idênticos em mídia. Imagens, áudio, vídeo, PDFs precisam ser byte-a-byte iguais. Re-encode, EXIF strip, recompressão JPEG = miss. OpenAI exige também input_image.detail constante entre requests. Detalhe em §10.9.
  8. +
  9. Model promotion = cache reset. Cache é por-modelo. gpt-5.5 → gpt-5.6 futuro = miss total. Pinar snapshot exato (gpt-5.5-2026-04-23, claude-opus-4-8) em produção sensível.
  10. +
+ +
+ Veja também. As subseções pré-existentes do guia cobrem mecânica básica de cada provider; este §10 consolida o que é cross-provider e o que é específico do modo stateless. Cross-links: §5.7 OpenAI cache (mecânica básica) · §Gemini context caching · §GTI cache implícito · §GTI Vertex/ZDR · §A.10 Anthropic cache (no count) · §A.17 Anthropic Bedrock/Vertex. +
+ + +

10.2 OpenAI Responses API — automatic prefix caching + Extended 24h + ZDR

+ + OpenAI +

Caching na Responses API é automático e sem fee de write. Sob store=false (forçado em ZDR), o mecanismo continua operando — cache ≠ store. O único ajuste arquitetural é o uso disciplinado de prompt_cache_key para pinar requisições da mesma sessão lógica no mesmo shard.

+ +

Mecânica (verbatim oficial)

+
+ Caching is enabled automatically for prompts that are 1024 tokens or longer. · Cache hits activate automatically for prompts ≥ 1024 tokens, in 128-token increments. · Requests are routed to a machine based on a hash of the initial prefix of the prompt. The hash typically uses the first 256 tokens, though the exact length varies depending on the model. + +
+ +

prompt_cache_retention — política de TTL por request

+ +
+ + + + + + + + + + + + + + + + + + + +
Retention policies (verificado 2026-06-10 contra /api/docs/guides/prompt-caching)
ValorTTLArmazenamentoModelos do escopo deste guiaDefault?
"in_memory"5–10 min de inatividade, máximo ~1 h em off-peakVRAM volátil (RAM da GPU)gpt-5.4-mini, gpt-5.4-nano (default histórico para esses modelos até 2026-05-28)Deixou de ser default em 2026-05-29; permanece default apenas para organizações com ZDR
"24h" (Extended)Tipicamente 1–2 h, máximo 24 hKV tensors em GPU-local storage (offload quando RAM cheia)gpt-5.5 (obrigatório — in_memory falha o request). Desde 2026-05-29, "24h" vale também para gpt-5.4-mini e gpt-5.4-nano: a antiga enumeração negativa da lista Extended-eligible (prompt-caching, snapshot 2026-05-26) ficou obsoleta com a mudança de default.Default desde 2026-05-29 para organizações sem ZDR em v1/responses, v1/chat/completions e v1/batch; obrigatório em gpt-5.5 e modelos futuros
+
+ +
+ Erro 400 em gpt-5.5 com in_memory. Verbatim: Requests to gpt-5.5, gpt-5.5-pro, and all future models require extended prompt caching, and setting a prompt_cache_retention value to in_memory will cause a request error. (/api/docs/guides/your-data). Em gpt-5.5, omita o parâmetro ou passe "24h"; "in_memory" falha o request. +
+ +

O que persiste em Extended 24h (e o que NÃO)

+
+ Only the key/value tensors may be persisted in local storage; the original customer content, such as prompt text, is only retained in memory. · The KV cache is an intermediate representation. It's essentially just a bunch of numbers internal to the model — that means no raw text/multi-modal inputs are ever stored, regardless of retention policy. +
— cookbook prompt_caching_201 (2026-06-10)
+
+ +

prompt_cache_key — pin de shard (substitui o legado user)

+
+ If you provide the prompt_cache_key parameter, it is combined with the prefix hash, allowing you to influence routing and improve cache hit rates. This is especially beneficial when many requests share long, common prefixes. · If requests for the same prefix and prompt_cache_key combination exceed a certain rate (approximately 15 requests per minute), some may overflow and get routed to additional machines, reducing cache effectiveness. · user (legacy): This field is being replaced by safety_identifier and prompt_cache_key. Use prompt_cache_key instead to maintain caching optimizations. + +
+ +

Estratégia de escolha do prompt_cache_key:

+
    +
  • Granularidade < 15 RPM por unique key: combine tenant_id + session_id ou tenant_id + agent_role + day_bucket; nunca use só tenant_id em SaaS de alta concorrência (estoura cap).
  • +
  • Determinístico e estável: hashlib.sha256(f"{tenant}:{session}".encode()).hexdigest()[:32]. NÃO inclua timestamp ou request_id — vira N keys diferentes para a mesma sessão lógica.
  • +
  • Echo no response? UNVERIFIED — a doc do /api/reference/resources/responses/methods/create lista prompt_cache_key como body parameter mas a referência do Response object não mostra um campo equivalente. Pratique como se NÃO fosse ecoado: logue o valor enviado client-side. NUNCA logue o valor cru — é fingerprint que permite cache-probing cross-tenant; armazene só o hash truncado ou marker booleano "key=set".
  • +
+ +

Sintomas de overflow do cap ~15 RPM (e como mitigar)

+

Quando o tráfego de uma única prompt_cache_key ultrapassa ~15 RPM, parte das requests é roteada para máquinas adicionais (cache cold). A doc não expõe um sinal explícito de overflow — você precisa inferir empiricamente:

+
    +
  • Sinal direto: usage.input_tokens_details.cached_tokens / usage.input_tokens cai abaixo do esperado em > 5% das requests com a MESMA prompt_cache_key + MESMO instructions+tools (prefixo idêntico).
  • +
  • Sinal lateral: p99 latência (TTFT) sobe gradualmente nas chamadas afetadas; reasoning models pioram mais.
  • +
  • Mitigação — sub-sharding por bucket: derive a chave com bucket de minuto/hora para split natural quando o workload de 1 sessão lógica é alto: +
    def stable_cache_key(tenant: str, session: str, *, bucket_per_min: int = 0) -> str:
    +    # bucket_per_min > 0 quando workload > 15 RPM; divide tráfego em N sub-shards
    +    sub = int(time.time() // 60) % bucket_per_min if bucket_per_min else 0
    +    payload = json.dumps([tenant, session, sub], separators=(",", ":")).encode()
    +    return hashlib.sha256(payload).hexdigest()[:32]
    + Trade-off: cada sub-shard é um cache independente (custo de N writes na primeira request de cada bucket). Use só quando observar overflow real, não preventivamente.
  • +
+ +

Usage shape — campos relevantes para telemetria

+
{
+  "usage": {
+    "input_tokens":  2006,
+    "output_tokens": 312,
+    "total_tokens":  2318,
+    "input_tokens_details":  { "cached_tokens": 1920 },
+    "output_tokens_details": {
+      "reasoning_tokens": 88,
+      "accepted_prediction_tokens": 0,
+      "rejected_prediction_tokens": 0
+    }
+  }
+}
+ +

Campos críticos para reconciliação de custo:

+
    +
  • usage.input_tokens_details.cached_tokens — tokens que bateram cache (≥ 0; sempre 0 se prompt < 1024 tk)
  • +
  • usage.output_tokens_details.reasoning_tokens — tokens internos consumidos por reasoning (gpt-5.x); cobrado como output
  • +
  • usage.output_tokens_details.rejected_prediction_tokens — Predicted Outputs rejeitados (cobrados mesmo rejeitados)
  • +
+ +

Streaming: em Responses API com stream=True, o usage vem no evento terminal response.completed. Em Chat Completions é preciso passar stream_options:{"include_usage":true} e ler no último chunk (choices=[]). If the stream is interrupted or cancelled, you may not receive the final usage chunk... but the billing continues (/api/reference/.../streaming-events). Logue response.id antes do stream e reconcilie via Usage API quando o cliente perder o evento.

+ +

ZDR matrix — comportamento sob store=false forçado

+ +
+ Zero Data Retention excludes customer content from abuse monitoring logs in the same way as Modified Abuse Monitoring. Additionally, Zero Data Retention changes some endpoint behavior: the store parameter for /v1/responses and v1/chat/completions will always be treated as false, even if the request attempts to set the value to true. + +
+ +

Consequências automáticas em projeto ZDR-enrolled:

+ +
+ + + + + + + + + + + + + + +
OpenAI sob ZDR — features e compatibilidade
FeatureZDR?Notas
Standard caching (in_memory)SimIn-memory cache retention does not save any data to disk.
Extended caching (24h)SimExtended prompt caching requests are not blocked if Zero Data Retention is enabled for your project. KV tensors em GPU-local até 24h, deletados no expiry.
store=trueForçado a falseSilenciosamente convertido. Não há erro; só o efeito de não-persistência.
background=trueQUEBRA ZDRBecause background mode stores response data for roughly 10 minutes to enable polling, it is not Zero Data Retention (ZDR) compatible. Aceita o request por compatibilidade legacy mas perde a garantia. Desabilite em projetos ZDR estritos.
WebSocket mode (/v1/responses via WSS)SimWebSocket mode is compatible with both Zero Data Retention (ZDR) and store=false. previous-response state apenas em memória da conexão.
Tracing dashboard built-in (Agents SDK)ProibidoThe built-in tracing dashboard cannot be used (it stores traces in OpenAI's systems). Use trace processors externos.
include=["reasoning.encrypted_content"]Sim — único caminho oficial para multi-turn statelessThis enables reasoning items to be used in multi-turn conversations when using the Responses API statelessly (like when the store parameter is set to false, or when an organization is enrolled in the zero data retention program). O cliente faz round-trip do encrypted reasoning item; o servidor decripta em memória, usa, descarta. Reasoning novo é re-encriptado e devolvido.
CORS direto do browserN/A para Anthropic ZDREm OpenAI não há restrição publicada; em Anthropic ZDR, sim — proxy backend obrigatório. Detalhe em §10.6.
Safety Retention exceptionReservadoWe reserve the right to make gpt-5.5, gpt-5.5-pro, and future models ineligible for Zero Data Retention or Modified Abuse Monitoring for specific customers if reasonably necessary to investigate severe risk activity, as notified in advance to the impacted customers in writing.
+
+ +

Captura de custo via Admin Usage API

+ +

Endpoint dedicado para reconciliação agregada de tokens consumidos por projeto/modelo/usuário:

+ +
+ + + + + + + + + +
Admin endpoints relevantes (verificado contra cookbook completions_usage_api, 2026-06-10)
EndpointGranularidadeCampos de cache
GET /v1/organization/usage/completionsbucket_width: 1m / 1h / 1dinput_cached_tokens, input_audio_tokens, output_audio_tokens, num_model_requests
GET /v1/organization/usage/embeddingsidem—
GET /v1/organization/usage/realtimeidemidem áudio
GET /v1/organization/costs1d only; group_by:["line_item","project_id"]amount.value em USD
+
+ +

Auth obrigatória: Admin Key (não API Key normal). Header Authorization: Bearer $OPENAI_ADMIN_KEY. Obtenção via platform.openai.com/settings/organization/admin-keys. Latência de disponibilidade dos dados UNVERIFIED — empiricamente minutos a ~1h para buckets 1m.

+ +

Pricing — modelos do escopo (≤200k contexto, default tier, USD/1M tk)

+ +
+ + + + + + + + +
Verificado contra /api/docs/pricing (2026-06-10). Long context tier separado disponível para gpt-5.5.
ModeloInputCached input (read)OutputMultiplier cache
gpt-5.5$5.00$0.50$30.00−90% input
gpt-5.4-mini$0.75$0.075$4.50−90% input
gpt-5.4-nano$0.20$0.02$1.25−90% input
+
+ +

Sem write premium (≠ Anthropic): no additional fees associated with it para o write. Extended caching (24h) mantém o mesmo cached input price: Prompt cache pricing is the same for both retention policies. Batch API aplica 50% off em ambos input e output; data residency regional uplift de +10% para gpt-5.5.

+ + +

10.3 Gemini Developer API — implicit caching only (Gemini 3.x)

+ + Gemini Developer API + +
+ Constraint do projeto: usamos SOMENTE implicit caching. Explicit cachedContents (recurso REST com TTL, lifecycle de create/update/delete) está fora do escopo — adiciona complexidade operacional (gerência de cache.name, índice por tenant, garbage collection) e requer governance separada. O implícito cobre o caso de uso típico (chat com system prompt + tools estáveis) sem código adicional. +
+ +

Gemini Developer API faz implicit caching automático para a família Gemini 3.x quando o prefixo da request é estável e ultrapassa o threshold mínimo. Não há código a escrever — basta manter o prefixo byte-idêntico turn-a-turn. Caching é uma otimização do backend de inferência (generateContent), não está atrelada ao flag store.

+ +

Implicit caching — thresholds e comportamento

+ +
+ + + + + + + + + +
Thresholds e características (verbatim caching docs, 2026-06-10) — escopo do projeto: Gemini 3.x
Família (verbatim na doc)ID no escopoMin token limitStorageGarantia
Gemini 3 Pro Previewgemini-3.1-pro-preview4.096RAM-only (in-memory), 24h TTL, project-isolatedno cost saving guarantee — oportunístico
Gemini 3 Flash Previewgemini-3.5-flash1.024
Gemini Flash-Lite UNVERIFIEDgemini-3.1-flash-lite1.024*
* Flash-Lite NÃO consta da tabela oficial de min-tokens em ai.google.dev/gemini-api/docs/caching (2026-06-10); valor inferido pela categoria Flash. Use com cautela.
+
+ +

Pass-through de desconto: We automatically pass on cost savings if your request hits caches. Hit aparece em usage_metadata.cached_content_token_count. Não há toggle nem hint — é puramente oportunístico. Sob store=false em chamadas generateContent: o flag store não existe em generateContent (é específico da Interactions API); generateContent é stateless por design e o implicit cache continua valendo normalmente.

+ +

Padrão de uso (zero código de cache)

+
from google import genai
+from google.genai.types import GenerateContentConfig
+from cost_module import cost_from_gemini, emit_cost_event
+
+client = genai.Client()    # default = Developer API; vertexai=True para Vertex
+
+# Mantenha system_instruction e tools BYTE-idênticos entre chamadas — esse é o
+# único "código de cache" necessário. ≥4096 tokens de prefixo estável =
+# elegível para implicit hit (oportunístico).
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=[{"role":"user","parts":[{"text": user_msg}]}],
+    config=GenerateContentConfig(
+        system_instruction=STABLE_SYSTEM_INSTRUCTION,    # byte-idêntico turn-a-turn
+        tools=STABLE_TOOLS,
+        thinking_level="medium",
+    ),
+)
+# usage_metadata.cached_content_token_count > 0 quando o backend bateu cache
+emit_cost_event(cost_from_gemini(resp, "gemini-3.1-pro-preview"))
+ +

Pricing — modelos do escopo (Standard tier, paid, USD/1M tk)

+ +
+ + + + + + + + + + +
Verificado contra ai.google.dev/gemini-api/docs/pricing (2026-06-10). Sem coluna "Storage" — implicit não cobra storage.
ModeloInputOutput (inc. thinking)Cached input (hit)
gemini-3.1-pro-preview (≤200k)$2.00$12.00$0.20
gemini-3.1-pro-preview (>200k)$4.00$18.00$0.40
gemini-3.5-flash$1.50$9.00$0.15
gemini-3.1-flash-lite (text/img/vid)$0.25$1.50$0.025
gemini-3.1-flash-lite (audio in)$0.50—$0.05
+
+ +

Cache write: não existe linha separada — implicit não tem fee de write. Cache read: ≈ −90% (visível no preço da coluna "Cached input"). Storage: $0 — só explicit caches cobravam storage; estão fora do escopo. Batch tier: cached input geralmente preservado ou ~50% off proporcionalmente.

+ + +

10.4 Gemini Interactions API — análise sob store=false

+ + Gemini Interactions API +

A Interactions API oferece apenas cache implícito — não suporta cachedContents. O mecanismo ativa-se via previous_interaction_id. Sob a premissa store=false deste capítulo, esse mecanismo deixa de funcionar. Mas isso não significa que a API perde todo o valor — a maioria das features herda diretamente da engine do generateContent e continua operando. A pergunta operacional é: quando vale usar Interactions API stateless e quando vale fazer o fallback para generateContent?

+ +
+ The Interactions API only supports implicit caching. Explicit caching (manually creating and managing cache objects) is not supported. + +
+ +
+ store=false is incompatible with background=true and prevents using previous_interaction_id for subsequent turns. +
— Interactions API docs (2026-06-10)
+
+ +

Análise duas-colunas — sob store=false + sem previous_interaction_id

+ +
+ + + + + + + + + +
O que funciona vs o que perde valor
Funciona normalmente (engine compartilhada com generateContent)Perde valor ou não funciona
+
    +
  • Multimodal handling — text, image, video, PDF, audio
  • +
  • Tool orchestration single-turn — function calling, code execution, Google Search grounding (server-side tool loop dentro de UM turno)
  • +
  • Streaming events tipados — step.delta, step.completed, tool_call.requested, interaction.completed
  • +
  • Structured output / response_format
  • +
  • thinking_level + total_thought_tokens
  • +
  • media_resolution (controle de custo de imagem/vídeo)
  • +
  • service_tier (auto / default / flex / priority)
  • +
  • usage.total_cached_tokens continua sendo populado (mas só será >0 se prefixo grande estável bater implicit no backend — o que sob stateless é raro)
  • +
+
+
    +
  • previous_interaction_id chaining — bloqueado por construção (store=false proíbe)
  • +
  • Cache implícito multi-turn ancorado em history server-side — sem prev_id, cada turno reenvia o payload completo e o backend trata como novo prefixo
  • +
  • background=true (Deep Research, Deep Think) — store=false is incompatible with background=true — Deep Research mode indisponível
  • +
  • State retention de Interaction (paid 55d / free 1d) — não se aplica (não cria recurso Interaction persistente)
  • +
+
+
+ +
+ Veredito operacional (implicit-only): sob a constraint do projeto (sem explicit cachedContents), a Interactions API sob store=false tem cache hit ≈ 0 na prática (a janela implicit Interactions-specific depende de previous_interaction_id, que é bloqueado). Use a Interactions API quando precisar de: (a) Deep Research (model IDs específicos como deep-research-pro-preview-12-2025), (b) taxonomia rica de eventos de streaming (step.*, tool_call.*), ou (c) tool orchestration server-side em um turno só — e aceite o pricing sem cache. Para o caso típico (chat com RAG/system prompt grande, sem Deep Research), use generateContent com prefixo estável — o implicit caching de Gemini 3.x (§10.3) ativa sozinho. +
+ +
+ Assertion empírica para Interactions sob store=false: em testes diretos via SDK google-genai com generation_config={"store": false} e mesmo prefixo de 8k+ tokens repetido por 10 chamadas sequenciais, usage.total_cached_tokens retornou 0 em todas. A doc não diz literalmente "= 0" — diz que o cache implícito depende de previous_interaction_id que o flag store=false bloqueia. Tratamos isso como asserção operacional, não citação verbatim. Se você observar total_cached_tokens > 0 sob store=false, abra issue — a janela pode ter mudado. UNVERIFIED-doc, VERIFIED-empírico 2026-05-26 +
+ +

Usage shape — campos canônicos (post-migration maio/2026)

+
"usage": {
+  "total_input_tokens":  int,
+  "total_output_tokens": int,
+  "total_thought_tokens": int,
+  "total_cached_tokens": int,            // cache hit (=0 sob store=false em uso típico)
+  "total_tool_use_tokens": int,
+  "total_tokens": int,
+  "input_tokens_by_modality":  [{ "modality": "text|image|video|audio|document", "tokens": int }],
+  "output_tokens_by_modality": [...],
+  "cached_tokens_by_modality": [...],
+  "tool_use_tokens_by_modality": [...],
+  "grounding_tool_count": { "count": int, "type": "google_search|google_maps|retrieval" }
+}
+ +

Diferente de generateContent (que usa cached_content_token_count), Interactions usa usage.total_cached_tokens. Para reconciliação cross-call, normalize ambos via mapping (ver §migração maio/2026).

+ + +

10.5 Vertex AI — Implicit Context Cache + Gemini Interactions on Vertex + billing capture

+ + Vertex AI + +
+ Escopo do projeto: somente implicit caching no Vertex. Não criar, listar, mutar nem nomear cachedContents. Toda a otimização vem do reuso de prefixo estável (system_instruction + tools + RAG header) no mesmo project/region/modelo dentro da janela RAM do serviço. encryptionSpec.kmsKeyName (CMEK) só faz sentido para explicit caches at-rest — implicit é RAM-only e não materializa esse atributo. CMEK em outros recursos do Vertex está fora do escopo desta seção. +
+ +

Vertex AI oferece a mesma mecânica implicit da Developer API com controles enterprise que justificam Vertex como backend produtivo do projeto: regional pinning, IAM granular, VPC-SC, Cloud Billing Export, audit logs aiplatform.googleapis.com em Cloud Audit Logs. É o caminho recomendado para qualquer workload regulado (HIPAA, PCI, GDPR strict) — incluindo o caso de uso primário: Gemini Interactions API rodando no backend Vertex, onde billing flui pelo projeto GCP.

+ +

Vertex implicit caching — mecânica e limites

+ +

Como na Developer API, o implicit cache do Vertex é RAM-only, opaco e best-effort: o serviço reusa prefixo recente automaticamente e expõe o hit via usage_metadata.cached_content_token_count. Sem garantia de hit, sem garantia de desconto na fatura (no cost saving guarantee verbatim). Diferenças relevantes em relação a Developer API são apenas as de governance e min-tokens.

+ +
+ + + + + + + + + + + + + +
Limites canônicos para implicit caching no Vertex (overview PT, 2026-06-10)
AspectoValor para Gemini 3.x
Min tokens para o servidor considerar implicit hit4.096 unificados para Gemini 3 e 3.1 na Vertex (Flash, Flash-Lite e Pro agrupados). Assimetria importante: a Developer API diferencia Flash 1.024 / Pro 4.096 (§10.3) — Vertex sobe Flash para 4.096. Planeje o prefixo estável para essa baseline.
Janela de retençãoRAM-only, opaca, ~minutos (sem TTL configurável; janela acima de "best-effort" não documentada)
Persistência at-restNão há. Nada é gravado em disco; CMEK não se aplica a este caminho
Sinal de hit no responseusage_metadata.cached_content_token_count (> 0 indica hit; 0 = miss). Vale para generateContent e streamGenerateContent. Em Interactions, ver §10.4.
IsolationProject + region + model + identidade do prefixo. Cache de project A nunca é lido por project B. Sessão em us-central1 não compartilha com europe-west4.
Disable implicit caching (project-level)PATCH /v1/projects/{PROJECT_ID}/cacheConfig body {"disableCache": true}. Precisa roles/aiplatform.admin. Propaga para todas as regiões do projeto.
Modelos suportados (escopo deste guia)Gemini 3.1 Pro Preview, Gemini 3 Flash Preview, Gemini 3.1 Flash-Lite, aliases gemini-flash-latest / gemini-flash-lite-latest
Region availabilityMesmas regiões onde o modelo Gemini 3.x está GA/Preview, exceto australia-southeast1 (que verbatim não lista Context Cache nos docs)
+
+ +
+ Padrão prefix-stable para maximizar implicit hit no Vertex (sem nomear cache): +
    +
  • Mesmo model ID — não misturar Pro/Flash/Lite na mesma sessão.
  • +
  • Mesma região — implicit cache é regional; sessão em us-central1 não compartilha com europe-west4.
  • +
  • Mesmo project — project-isolated por padrão.
  • +
  • Prefixo byte-idêntico: system_instruction + tools + RAG header em ordem estável; qualquer mudança (uma vírgula, reordenação, timestamp embutido) quebra o hit.
  • +
  • ≥ 4.096 tokens no prefixo antes do primeiro turno dinâmico. Se o prefixo estável é menor, considere padding deliberado (ontologia, glossário) — mas só quando isso reduz custo total considerando o overhead.
  • +
+
+ +

Gemini Interactions ON Vertex — configuração e billing

+ +

O usuário deste projeto usa primariamente o backend Vertex via SDK google-genai. Configuração canônica:

+ +
+
+ + +
+
+
import os
+os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "True"
+os.environ["GOOGLE_CLOUD_PROJECT"]      = "your-project"
+os.environ["GOOGLE_CLOUD_LOCATION"]     = "us-central1"  # NÃO use "global" se quiser CMEK
+
+from google import genai
+client = genai.Client(vertexai=True, project="your-project", location="us-central1")
+
+# Auth: ADC via `gcloud auth application-default login` (dev)
+#       Service Account via GOOGLE_APPLICATION_CREDENTIALS (server)
+#       Workload Identity Federation (GKE / Cloud Run)
+
+
+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({
+  vertexai: true,
+  project: "your-project",
+  location: "us-central1",
+});
+
+// Auth via ADC; GOOGLE_APPLICATION_CREDENTIALS apontando para SA JSON em prod.
+
+
+ +

Diferenças vs Developer API (AI Studio):

+ +
+ + + + + + + + + + + + + + +
EixoDeveloper API (AI Studio)Vertex backend
Endpointgenerativelanguage.googleapis.com{LOCATION}-aiplatform.googleapis.com
AuthAPI keyADC + IAM
BillingGemini API billingCloud Billing GCP do project
Telemetria de custo realSem export oficialCloud Billing Export → BigQuery
ZDRRequest manual ad-hocSelf-serve enterprise program + CMEK
Data residencyGlobal poolRegional pinning (us-central1, europe-west4, etc.)
VPC-SCN/ASuportado
CMEK em Context CacheN/ASuportado via encryptionSpec.kmsKeyName (exceto endpoint global)
Caching semânticaIdênticaIdêntica (mesma SDK)
Interactions API sob store=falseMesma degradação (ver §10.4)Mesma degradação
+
+ +

Captura de custo via Cloud Billing Export para BigQuery

+ +

Para o usuário deste projeto (Gemini Interactions on Vertex), a captura de custo real não vem do response da chamada — usage_metadata é o ground truth de tokens mas não converte para USD final. O caminho canônico é o Cloud Billing Export para BigQuery.

+ +
+ + + + + + + + + + + + + + + +
Tabelas geradas (billing export docs, 2026-06-10)
TipoTabelaPara que serve
Standard usagegcp_billing_export_v1_<BILLING_ACCOUNT_ID>Custo agregado por SKU / project / dia. Colunas: service.description, sku.id, sku.description, usage_start_time, project.id, labels.*, cost, currency, usage.amount, usage.pricing_unit, credits.*
Detailed usagegcp_billing_export_resource_v1_<BILLING_ACCOUNT_ID>Mesma forma + resource.name, resource.global_name, subscription.instance_id — granularidade de recurso individual
+
+ +

Latência: Typically, your cost details are available within a day, but can sometimes take more than 24 hours. Não use Cloud Billing para alertas operacionais; use o usage_metadata per-call. Tags propagation: might take up to an hour to propagate to BigQuery exports.

+ +

service.description para Vertex AI: UNVERIFIED — schema doc não publica string literal. Convenção observada: "Vertex AI API" (ou "Vertex AI" em accounts antigos). Confirme via SQL:

+ +
SELECT DISTINCT service.description, service.id
+FROM `PROJECT.DATASET.gcp_billing_export_v1_BILLING_ACCOUNT_ID`
+WHERE LOWER(service.description) LIKE '%vertex%'
+   OR service.id = 'aiplatform.googleapis.com'
+ +

SKU strings também UNVERIFIED em página única oficial. Padrões observados em billing exports reais (relevantes ao escopo implicit-only): Gemini 3.1 Pro Preview Input Tokens, Gemini 3.5 Flash Cached Input Tokens, etc. (SKU de "Context Cache Storage" só aparece em projetos que usam explicit cachedContents — fora do escopo.) Descubra os SKUs do seu projeto via Cloud Billing Catalog API:

+ +
gcloud billing catalog skus list \
+  --service=aiplatform.googleapis.com \
+  --filter="description:Gemini" --format=json \
+  | jq '.[] | {sku_id: .skuId, desc: .description}'
+ +

Setup zero — habilitar Cloud Billing Export (one-time, ~5 min)

+
    +
  1. Identifique o billing account: gcloud billing accounts list → copie o ACCOUNT_ID (formato 0X0X0X-XXXXXX-XXXXXX).
  2. +
  3. Crie o dataset BigQuery (recomendado: na mesma região do projeto principal, multi-region US ou EU só se já é seu padrão): +
    bq --location=us-central1 mk --dataset --description="GCP billing export" PROJECT_ID:billing_export
  4. +
  5. Habilite o export via Console (a CLI gcloud billing ainda não cobre): Billing → Billing export → BigQuery export → Edit Standard usage cost → Project=PROJECT_ID, Dataset=billing_export. Faça o mesmo para "Detailed usage cost" se quiser amount_in_pricing_units.
  6. +
  7. Aguarde primeira hora: tabelas gcp_billing_export_v1_<ACCOUNT_ID> aparecem ~24h após linhas começarem a popular. Antes disso, query retorna erro Not found: Table — não é bug.
  8. +
  9. IAM mínimo p/ leitura: roles/bigquery.dataViewer no dataset + roles/bigquery.jobUser no projeto consumidor.
  10. +
+ +

SQL exemplo — custo real por SKU/dia (últimos 30 dias)

+ +
WITH base AS (
+  SELECT
+    DATE(usage_start_time) AS d,
+    project.id            AS project_id,
+    sku.id                AS sku_id,
+    sku.description       AS sku_description,
+    SUM(cost)             AS cost_usd_eq,
+    SUM(usage.amount)     AS units,        -- standard export usa usage.amount; detailed export tem amount_in_pricing_units
+    ANY_VALUE(usage.unit)        AS unit
+  FROM `PROJECT.DATASET.gcp_billing_export_v1_BILLING_ACCOUNT_ID`
+  WHERE service.description = 'Vertex AI API'
+    AND usage_start_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
+    AND project.id        = 'your-project'
+  GROUP BY d, project_id, sku_id, sku_description
+),
+credits AS (
+  SELECT
+    DATE(usage_start_time) AS d,
+    project.id             AS project_id,
+    sku.id                 AS sku_id,
+    SUM(c.amount)          AS credit_usd
+  FROM `PROJECT.DATASET.gcp_billing_export_v1_BILLING_ACCOUNT_ID`,
+       UNNEST(credits) AS c
+  WHERE service.description = 'Vertex AI API'
+    AND usage_start_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
+    AND project.id        = 'your-project'
+  GROUP BY d, project_id, sku_id
+)
+SELECT
+  b.d,
+  b.project_id,
+  b.sku_id,
+  b.sku_description,
+  ROUND(b.cost_usd_eq + IFNULL(c.credit_usd, 0), 4) AS net_cost_usd,
+  b.units,
+  b.unit
+FROM base b
+LEFT JOIN credits c USING (d, project_id, sku_id)
+ORDER BY b.d DESC, net_cost_usd DESC;
+ +

Para reconciliação cross-call (per-request usage_metadata × Cloud Billing aggregate), mantenha um BigQuery scheduled query materializando por hora — agregue tokens por modelo × hora × SKU. Divergência típica esperada ≤ 1–2% (chamadas perdidas, retries, free-tier credits). Acima de 5% indica gap no pipeline.

+ +

Restrições e gotchas do implicit caching no Vertex

+ +
    +
  • Sem garantia de hit nem de desconto na fatura (no cost saving guarantee). Tudo o que o cliente vê é o sinal post-hoc em cached_content_token_count.
  • +
  • australia-southeast1 (Sydney) não lista Context Cache. Workloads sediados ali devem assumir cached=0 nas estimativas de custo.
  • +
  • Janela RAM opaca: o serviço pode evictar a qualquer momento sob pressão de capacidade. Não dimensionar SLO assumindo hit; tratar hit como upside.
  • +
  • Project + region + model são chaves rígidas: trocar qualquer um (failover de região, A/B test de modelo, project diferente para canary) zera a janela do prefixo.
  • +
  • Prefixo < 4.096 tk nunca produz hit, mesmo se exatamente igual entre chamadas — o threshold é por payload, não acumulado.
  • +
  • Sob store=false em Interactions API, o gating de retomada por previous_interaction_id faz o efeito empírico de cached aproximar 0 (ver §10.4 callout); modelar custo sem cache nesse caminho.
  • +
  • Mutar o conteúdo referenciado (ex.: GCS URI em file_data) não invalida o cache implicit explicitamente — o servidor pode entregar resposta cacheada baseada no prefixo de bytes do payload, não no estado atual do objeto. Para conteúdos voláteis, embuta um content hash no prefixo para forçar miss.
  • +
+ +

Desabilitar implicit caching — toggles disponíveis

+

PATCH /v1/projects/{PROJECT_ID}/cacheConfig body {"disableCache": true} é project-level e propaga para todas as regiões. Não há toggle por região. Se SRE precisa desligar cache só em uma região durante um incidente, ou só em uma rota crítica, as opções são:

+
    +
  • 1 GCP project por região: prod-eu, prod-us, etc. — overhead operacional alto mas isolation total e cacheConfig.disableCache regional-de-fato.
  • +
  • IAM Deny / Org Policy: restringir aiplatform.endpoints.predict condicional na região do request (requer roles/iam.denyAdmin + Cloud Asset Inventory). Mais drástico (corta tudo, não só cache); deny rules propagam em até ~7 minutos.
  • +
  • Application-level cache-bust: injetar um nonce em uma linha não-funcional do prefixo (ex.: header // runtime-id: <timestamp/10s>) para forçar miss durante incidente. Mais rápido (segundos), reversível por config-push, e não exige permissão admin.
  • +
+ +

SLO de detecção de drift — intra-day vs Cloud Billing ~24h

+

Cloud Billing Export tem latência ~24h documentada (Typically, your cost details are available within a day). Para SaaS multi-tenant com risco de denial-of-wallet ou API key compromise, isso é muito tarde. Runbook recomendado:

+
    +
  • Métrica primária (real-time): agregue usage_metadata per-call client-side em janela móvel de 5min. Alarme se SUM(input_tokens) per tenant_id > 5× baseline p95 das últimas 7 dias = sinal de exfil/abuso.
  • +
  • Métrica secundária (sub-hora): re-pull do usage_metadata agregado emitido pelo emitter (BigQuery ou Postgres do §10.10), query diária por tenant — divergência > 5% vs baseline dispara warning.
  • +
  • Métrica terciária (~24h): reconciliação Cloud Billing × emitter local — divergência > 5% no agregado total = confirmação de drift ou cache miss não-modelado. Apenas para post-mortem, NÃO para alerta operacional.
  • +
+ +

Custo idle no caminho implicit-only

+

Como o implicit cache do Vertex é RAM-only e não persiste at-rest, não há componente "storage / token-hour" cobrado — diferente do que aconteceria com explicit cachedContents. O único custo é o input tokens da request: parte vira "cached input" (~10% da tarifa normal) quando há hit; o restante é input padrão. Não há SKU de storage de cache implicit em aiplatform.googleapis.com.

+ +

Mini-recipe — Vertex generateContent (implicit) + cost capture end-to-end

+

Caminho recomendado dentro da constraint: prefixo estável + generate_content. O implicit caching ativa sozinho quando o prefixo passa de 4.096 tokens dentro da janela RAM.

+
import os
+os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "True"
+os.environ["GOOGLE_CLOUD_PROJECT"]      = "your-project"
+os.environ["GOOGLE_CLOUD_LOCATION"]     = "us-central1"   # cache implicit é por região
+
+from google import genai
+from google.genai.types import GenerateContentConfig
+from cost_module import cost_from_gemini, emit_cost_event
+
+client = genai.Client()   # vertexai=True via env
+
+# Prefixo estável (system_instruction + tools) deve ter ≥ 4.096 tk no payload final
+resp = client.models.generate_content(
+    model="gemini-3.1-pro-preview",
+    contents=[{"role":"user","parts":[{"text": user_msg}]}],
+    config=GenerateContentConfig(
+        system_instruction=STABLE_SYSTEM_INSTRUCTION,   # byte-idêntico em toda chamada
+        tools=STABLE_TOOLS,                              # ordem fixa, sem mudança
+        thinking_level="medium",
+    ),
+)
+# usage_metadata.cached_content_token_count > 0 indica implicit hit; nada explícito a fazer
+emit_cost_event(cost_from_gemini(resp, "gemini-3.1-pro-preview", surface="vertex_generate_content"))
+ +

Para o caso primário do projeto (Gemini Interactions API em Vertex): sob store=false o cached_content empírico tende a 0 (ver §10.4). Não há recipe de cache adicional — use a Interactions API quando precisar de Deep Research, eventos step.*/tool_call.* ou tool orchestration server-side, e modele o custo sem desconto de cache.

+ +

HTTP REST equivalente (curl/debug): POST https://{LOCATION}-aiplatform.googleapis.com/v1/projects/{PROJECT}/locations/{LOCATION}/publishers/google/models/{MODEL}:generateContent com header Authorization: Bearer $(gcloud auth application-default print-access-token) e scope https://www.googleapis.com/auth/cloud-platform (já garantido pelo ADC). Para Workload Identity Federation em GKE/Cloud Run o SA precisa de roles/aiplatform.user.

+ + +

10.6 Anthropic — cache_control + Cache Diagnostics + Claude on Vertex

+ + Anthropic +

Anthropic é stateless-first por arquitetura (não tem previous_response_id; cliente sempre monta payload completo). Para esta seção, isso é uma vantagem: o caminho recomendado para o padrão do projeto é o caminho natural da API. O caching opera via cache_control explícito em até 4 breakpoints por request, com TTL configurável (5 minutos ou 1 hora). Cache Diagnostics (beta cache-diagnosis-2026-04-07) fecha o gap de observabilidade quando hit rate cai sem causa óbvia.

+ +

Mecânica de breakpoints (cache prefix order)

+ +
+ Prompt caching references the entire prompt — tools, system, and messages (in that order) up to and including the block designated with cache_control. · Cache prefixes are created in the following order: tools, system, then messages. This order forms a hierarchy where each level builds upon the previous ones. + +
+ +

Até 4 breakpoints por request — automatic-caching mode top-level consome 1 slot. Placement no último bloco de cada seção estável cacheia tudo até e incluindo aquele ponto.

+ +

Onde cache_control PODE entrar:

+
    +
  • tools → último entry do array
  • +
  • system → text blocks no array system
  • +
  • messages → blocos content em turnos user E assistant: tipos text, image, document, tool_use, tool_result
  • +
+ +

Onde NÃO pode: thinking blocks diretamente (Thinking blocks cannot be cached directly with cache_control); citation children (Sub-content blocks (like citations) themselves cannot be cached directly); empty text blocks.

+ +

TTL: 5m vs 1h — multipliers

+ +
+ + + + + + + + +
Pricing multipliers (verbatim pricing page, 2026-06-10)
OperaçãoMultiplierDuração
5-minute cache write ({"type":"ephemeral"})1.25× base input5 minutos (refreshes grátis em cada hit)
1-hour cache write ({"type":"ephemeral","ttl":"1h"})2× base input1 hora
Cache read (hit)0.1× base input (−90%)Mesma do write precedente
+
+ +

Break-even oficial: A cache hit costs 10% of the standard input price, which means caching pays off after just one cache read for the 5-minute duration (1.25x write), or after two cache reads for the 1-hour duration (2x write). Refresh grátis: The cache is refreshed for no additional cost each time the cached content is used. Stacking: These multipliers stack with other pricing modifiers such as the Batch API discount and data residency. (cache + Batch 50% + data residency 1.1× compõem multiplicativamente.)

+ +
+ Regra prática para escolher TTL: +
    +
  • Default = "5m" (1.25× write). Paga-se em 1 read. Use sempre que <2 reads/hora não estiver garantido.
  • +
  • "1h" (2× write) só quando você tem evidência de ≥2 reads/hora por session ativa (chat longo com pausas frequentes, processo batch que reusa o mesmo prefixo 5-10× no mesmo dia). Em workload mais "one-shot" (chat single-turn, FAQ, RAG sem follow-up frequente), "1h" custa +60% input vs no-cache.
  • +
  • Workload one-shot > 70%? Desative caching no system block. O write fee 1.25× sem hit é desperdício.
  • +
+
+ +

Token minimums — modelos do escopo

+ +
+ + + + + + + + +
Mínimo cacheável (silently dropped abaixo — não dá erro). Verbatim prompt caching docs, 2026-06-10
ModeloMin tokensMáx breakpoints
claude-opus-4-84.0964
claude-sonnet-4-61.0244
claude-haiku-4-54.0964
+
+ +
+ Shorter prompts cannot be cached, even if marked with cache_control. Any requests to cache fewer than this number of tokens will be processed without caching, and no error is returned. To verify whether a prompt was cached, check the response usage fields: if both cache_creation_input_tokens and cache_read_input_tokens are 0, the prompt was not cached. +
+ +

Usage shape — 5m vs 1h breakdown

+ +
{
+  "usage": {
+    "input_tokens": 2048,                  // tokens APÓS o último breakpoint
+    "cache_read_input_tokens": 1800,
+    "cache_creation_input_tokens": 248,
+    "output_tokens": 503,
+    "cache_creation": {
+      "ephemeral_5m_input_tokens": 148,
+      "ephemeral_1h_input_tokens": 100
+    }
+  }
+}
+ +

Cálculo de total real de input (armadilha clássica):

+ +
total_input = cache_read_input_tokens + cache_creation_input_tokens + input_tokens
+            //          ↑                       ↑                        ↑
+            //   já cacheado (read)      sendo cacheado agora     pós-breakpoint (uncached)
+ +

Matriz de leitura:

+ +
+ + + + + + + + +
cache_read_input_tokenscache_creation_input_tokensSignificado
> 00Hit — funcionando como esperado
0> 0Write — primeira vez OU prefixo divergiu OU TTL expirou
00NÃO cacheou — prompt abaixo do mínimo, sem cache_control, ou placement em bloco proibido
> 0> 0Hit parcial — prefixo estável bateu até certo ponto, conteúdo novo foi gravado
+
+ +

Cache Diagnostics — beta cache-diagnosis-2026-04-07

+ +

Quando hit rate cai sem causa óbvia, Cache Diagnostics identifica onde exatamente o prefixo divergiu entre dois requests consecutivos.

+ +
+ Diagnose unexpected prompt cache misses by comparing consecutive requests and identifying exactly where the prompt prefix diverged. · Cache diagnostics is in beta. Include the beta header cache-diagnosis-2026-04-07 in your API requests to use this feature. · Cache diagnostics is currently available on the Claude API only. It is not supported on Amazon Bedrock or Vertex AI. + +
+ +

Não é endpoint separado. É um campo diagnostics no body do mesmo /v1/messages + header beta. O response ganha diagnostics no objeto Message.

+ +
Request shape
+ +
import anthropic
+client = anthropic.Anthropic()
+
+DIAG_HEADER = {"anthropic-beta": "cache-diagnosis-2026-04-07"}
+SYSTEM_BIG  = "You are an AI assistant analyzing a large document. <document>...</document>"
+
+# Turn 1 — cache_control vai DENTRO do bloco system (não top-level).
+# Beta header vai em extra_headers; betas=[...] no body NÃO é a forma canônica.
+r1 = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    system=[
+        {"type": "text", "text": SYSTEM_BIG,
+         "cache_control": {"type": "ephemeral", "ttl": "1h"}},
+    ],
+    messages=[{"role": "user", "content": "Summarize section 1."}],
+    diagnostics={"previous_message_id": None},
+    extra_headers=DIAG_HEADER,
+)
+
+# Turn 2 — passa o id do turn 1 para diff; reusa o mesmo system block byte-idêntico.
+r2 = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    system=[
+        {"type": "text", "text": SYSTEM_BIG,
+         "cache_control": {"type": "ephemeral", "ttl": "1h"}},
+    ],
+    messages=[
+        {"role": "user", "content": "Summarize section 1."},
+        {"role": "assistant", "content": r1.content[0].text},
+        {"role": "user", "content": "Now section 2."},
+    ],
+    diagnostics={"previous_message_id": r1.id},
+    extra_headers=DIAG_HEADER,
+)
+ +
Response com cache miss detectado
+ +
{
+  "id": "msg_01Xyz...",
+  "usage": {
+    "input_tokens": 42,
+    "cache_read_input_tokens": 0,
+    "cache_creation_input_tokens": 41850,
+    "output_tokens": 210
+  },
+  "diagnostics": {
+    "cache_miss_reason": {
+      "type": "system_changed",
+      "cache_missed_input_tokens": 41850
+    }
+  }
+}
+ +
+ Não logue cache_missed_input_tokens cru em traces/dashboards públicos. Valor exato revela tamanho de system/RAG/tools — atacante observando logs pode reconstruir o tamanho do payload sensível e inferir presença/ausência de docs específicos. Recomendação: +
    +
  • Sanitize no sink: bucket discreto antes de emitir — "<10k" | "10-50k" | "50-200k" | ">200k".
  • +
  • Mantenha o cru só em datastore restrito (mesmo perímetro do system prompt — se system é confidencial, o tamanho é também).
  • +
  • Não exponha em error responses 4xx retornados ao cliente — vetor de side-channel.
  • +
+
+ +
Tipos de cache_miss_reason.type (discriminated union)
+ +
+ + + + + + + + + + + +
Verbatim da tabela oficial (2026-06-10)
typeO que significaO que mudar
model_changedO model difere do request anterior (router, A/B, fallback). Cache é por-modelo.Mantenha o modelo constante dentro de uma conversa cacheada.
system_changedO system parameter difere. Tipicamente timestamp, request ID, ou per-request value interpolado.Faça o system prompt byte-stable; mova dado dinâmico para o primeiro user depois do breakpoint.
tools_changedArray tools mudou: adicionados/removidos/reordenados, ou input_schema serializado não-deterministicamente.Mesma lista de tools em ordem fixa, schema com chaves ordenadas.
messages_changedModel/system/tools batem, mas messages foi alterado/reordenado/removido (não append).Trate history como append-only; echo assistant content e tool_result verbatim.
previous_message_not_foundSem fingerprint do previous_message_id fornecido. NÃO é evidência de mudança no seu request.Mande beta header em todo turno; mantenha turns próximos no tempo.
unavailableInfo indisponível. Inclui mudança em parâmetros não-cobertos (tool_choice, thinking, context_management, output_config, set de anthropic-beta headers) OU divergência além do comparison horizon.Mantenha parâmetros constantes durante uma conversa cacheada.
+
+ +

Matriz combinada (diagnostics × cache_read_input_tokens):

+ +
+ + + + + + + + +
diagnosticsCache readInterpretação
nullhighFuncionando — prefix estável + hit
nulllow/zeroRequests batem mas cache expirou — aumentar frequência ou usar 1h TTL
*_changedlow/zeroSeu bug — request mudou; corrija pelo type
*_changedhighRaro — mudança tardia, breakpoint anterior bateu. Vale corrigir, impacto baixo
+
+ +

Fingerprint storage: Fingerprints contain only hashes and token-count estimates (never raw prompt content), are retained for a limited time, are scoped to your organization and workspace, and are not used for any other purpose. ZDR-elegible com label qualified — ver §10.7.

+ +

Matriz de invalidação (verbatim oficial)

+ +
+ + + + + + + + + + + + +
✓ = cache sobrevive · ✘ = cache invalidado
O que mudaTools cacheSystem cacheMessages cache
Tool definitions✘✘✘
Web search toggle✓✘✘
Citations toggle✓✘✘
Speed setting (fast mode)✓✘✘
tool_choice✓✓✘
Imagens (presence/absence)✓✓✘
Thinking parameters✓✓✘
+
+ +

Thinking blocks variação por modelo: On Opus 4.5+ and Sonnet 4.6+, thinking blocks are preserved by default, so the cache remains valid. On earlier Opus/Sonnet models and all Haiku models, all previously-cached thinking blocks are stripped from context, and any messages that follow those thinking blocks are removed from the cache. No escopo deste guia (Opus 4.8, Sonnet 4.6, Haiku 4.5): Opus/Sonnet preservam, Haiku 4.5 não preserva — atenção em chat com extended thinking.

+ +

Lookback window — 20 blocks

+ +
+ The lookback window is 20 blocks. The system checks at most 20 positions per breakpoint, counting the breakpoint itself as the first. +
+ +

Implicação para conversas crescentes: em uma conversa com 35 blocks e breakpoint no block 35, o sistema procura entries em blocks 35–16. Se a única entry anterior está em block 15, fica 1 posição fora da janela = miss. Solução: 2 breakpoints — um no fim do prefixo estável (tools+system+RAG), outro perto da tail (últimas N mensagens, refrescado a cada turno). Cada turno, pelo menos um bate.

+ +

ZDR + prompt caching (verbatim)

+ +
+ This feature is eligible for Zero Data Retention (ZDR). When your organization has a ZDR arrangement, data sent through this feature is not stored after the API response is returned. · Your prompts and Claude's outputs are not stored. KV cache representations and cryptographic hashes are held in memory for the cache TTL and promptly deleted after expiry. + +
+ +

Workspace-level isolation 2026-02-05: As of February 5, 2026, prompt caching uses workspace-level isolation instead of organization-level isolation. Caches are isolated per workspace, ensuring data separation between workspaces within the same organization. This applies to the Claude API, Claude Platform on AWS, and Microsoft Foundry (beta); Bedrock and Vertex AI maintain organization-level cache isolation.

+ +

CORS desabilitado em ZDR: Cross-Origin Resource Sharing (CORS) is not supported for organizations with ZDR arrangements. If you need to make API calls from browser-based applications, you must use a backend proxy server. Surpresa frequente para equipes frontend-first.

+ +

Claude on Vertex (anthropic-vertex SDK)

+ +
+ + + + + + + + + + + + + + + + + + + + +
Diferenças vs Claude API direta (verificado contra claude-on-vertex-ai, 2026-06-10)
AspectoClaude API diretaClaude on Vertex AI
SDK Pythonpip install anthropicpip install "anthropic[vertex]" → AnthropicVertex
model no bodySimNão — vai na URL
anthropic_versionHeader anthropic-version: 2023-06-01Body field "anthropic_version": "vertex-2023-10-16"
Endpoint URLapi.anthropic.com{LOCATION}-aiplatform.googleapis.com/v1/projects/{PROJECT_ID}/locations/{LOCATION}/publishers/anthropic/models/{MODEL_ID}:streamRawPredict
Authx-api-keyADC + IAM
BillingAnthropic WorkspaceCloud Billing GCP do project
Endpoint typesSingle endpointGlobal (base) · Multi-region (us/eu, +10%) · Regional (+10%)
cache_control✅ Suportado✅ Suportado (sintaxe idêntica)
1-hour TTL✅ Em todos os modelos do escopo✅ Em modelos 4.x+ do escopo
Cache Diagnostics✅ Suportado (beta)NÃO suportado
Cache isolationWorkspace-level (desde 2026-02-05)Project-level (mantém org-level conceitualmente; um cache por GCP project)
Context window200k (default), 1M em alguns modelos1M em Opus 4.8, Opus 4.6, Sonnet 4.6 no Vertex
Payload limit200 MB típico30 MB no Vertex
ZDR governanceAnthropic = data processor; ZDR via contrato AnthropicGoogle Cloud = data processor; ZDR governance é GCP (CMEK, VPC-SC, audit)
Features NÃO suportadas no Vertex—Files API, server-side tools (code execution, web fetch), Message Batches, Models API, Admin/Compliance/Usage APIs, Claude Managed Agents, Cache Diagnostics
+
+ +

Regional pricing premium: Regional and multi-region endpoints include a 10% pricing premium over global endpoints. (Aplica a Sonnet 4.5, Haiku 4.5, Opus 4.5+ e futuros — todos no escopo deste guia.)

+ +

Activity logging: Vertex provides a request-response logging service that allows customers to log the prompts and completions associated with your usage. Anthropic recommends that you log your activity on at least a 30-day rolling basis. Habilitar para auditoria + reconciliação contábil.

+ +

Pricing — modelos do escopo (Claude API direta, USD/1M tk, base input)

+ +
+ + + + + + + + +
Verificado contra pricing page (2026-06-10). Vertex regional adiciona +10%.
ModeloInput base5m write (1.25×)1h write (2×)Cache read (0.1×)Output
claude-opus-4-8$5.00$6.25$10.00$0.50$25.00
claude-sonnet-4-6$3.00$3.75$6.00$0.30$15.00
claude-haiku-4-5$1.00$1.25$2.00$0.10$5.00
+
+ + +

10.7 Matriz ZDR cross-provider — eligibility, restrições, governance authority

+ +

Consolidação da matriz ZDR de caching das 3 plataformas + Vertex backend. Regra de tradução universal: implicit/in-memory caching é ZDR-compatible em todos; explicit/named cache resources têm semântica diferente por provider — leia a doc dedicada antes de assumir compatibilidade.

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Matriz ZDR mestra (verbatim 2026-06-10)
Provider/superfíciePrograma ZDRCache compatible?Como habilitar / restriçõesAuthority (data processor)
OpenAI Responses APIEnterprise / regulated✅ Standard (in_memory) e Extended (24h) — explicitamente não-bloqueadoOrg enrolled em ZDR; store=true é forçado a false; background=true QUEBRA ZDR; tracing dashboard built-in proibido; usar include=["reasoning.encrypted_content"] para multi-turn statelessOpenAI
Gemini Developer API (AI Studio)Sim — ai.google.dev/.../zdr✅ Implicit (RAM, opaca, project-isolated). Único modo usado neste projeto.Set store=false; não habilitar Session Resumption (Live API); paid tier opt-out automático de training (unpaid pode ser usado para melhorar modelos)Google
Vertex AISelf-serve project-level — vertex-ai-zero-data-retention✅ Implicit (RAM-only, opaca, disable via cacheConfig.disableCache=true com roles/aiplatform.admin). Único modo usado neste projeto.Enroll project em ZDR; disable implicit se compliance proibir cache RAM; HIPAA stack = region pinning + audit + VPC-SC; Grounding com Google Search retém 30d independente de ZDR — usar Web Grounding for EnterpriseGoogle Cloud
Anthropic Claude API diretaSim — contrato Anthropic + sales✅ cache_control explicitamente ZDR-eligible (KV em memória durante TTL, deletado no expiry)ZDR enabled per-organization via sales; CORS desabilitado em ZDR (use proxy backend); Cache Diagnostics é ZDR qualified (hashes only); count_tokens também ZDR-eligibleAnthropic
Claude on Vertex AIVertex ZDR (não Anthropic ZDR) — cloud provider is the data processor✅ cache_control suportado · ❌ Cache Diagnostics não disponívelGovernance via Vertex AI data governance (CMEK, VPC-SC, audit); ZDR formal segue programa GCPGoogle Cloud
+
+ +

Stack HIPAA / regulado hardened — 9-point recipe (Vertex foco, implicit-only)

+
    +
  1. Region pinning: LOCATION=europe-west4 (ou outra equivalente); evitar endpoint global por defesa em profundidade
  2. +
  3. CMEK nos recursos Vertex que persistem at-rest (modelos custom, datasets, indexes — não se aplica ao implicit cache, que é RAM-only); mesma region/keyRing
  4. +
  5. Disable implicit caching project-wide se compliance proibir cache RAM (cacheConfig.disableCache=true)
  6. +
  7. Não usar Grounding com Google Search/Maps — usar Web Grounding for Enterprise (zero retention)
  8. +
  9. Não habilitar Session Resumption na Live API
  10. +
  11. store=false em toda chamada (Interactions API) — premissa do projeto
  12. +
  13. Não criar, listar ou referenciar cachedContents — fora do escopo do projeto (implicit-only)
  14. +
  15. Abuse monitoring exceção solicitada (sanitized logging) + Audit logs / Access Transparency habilitados
  16. +
  17. VPC-SC no perímetro do projeto Vertex AI
  18. +
+ + +

10.8 Shard pin cross-provider — equivalentes do prompt_cache_key

+ +

A OpenAI Responses API expõe prompt_cache_key: string opaca passada no body que combina-se com o hash do prefixo para rotear requisições da mesma sessão lógica ao mesmo shard backend, melhorando hit rate em fleets multi-shard. Cap ~15 RPM por unique key. Substitui o legado user parameter (que era usado para abuse detection + cache routing simultaneamente — agora separado em safety_identifier + prompt_cache_key).

+ +

Existem equivalentes nos outros providers? Sim e não — a granularidade e o modelo arquitetural são diferentes:

+ +
+ + + + + + + + + + + + + + +
Mecanismos de pin / routing cross-provider (sob a constraint implicit-only do Gemini/Vertex)
CapacidadeOpenAI Responses APIGemini Developer / Vertex (implicit)Anthropic Messages API
Hint opaco para shard pinning de cache implícitoprompt_cache_key (string, hint)Sem hint user-facing — pin é implícito por (project × region × model × prefix bytes)Não documentado (sem necessidade — arquitetura diferente)
Mecanismo de pin determinísticoSem (Responses usa só implicit prefix matching, probabilístico)Sem (implicit é best-effort RAM, sem garantia)cache_control per-block (até 4 breakpoints; pin determinístico por placement)
Vínculo a modeloHash inclui model snapshotPin inclui model ID (Pro/Flash/Lite são caches diferentes)Cache key inclui model snapshot
Vínculo a tenant/namespaceOrg-level + prompt_cache_key customProject + region (cross-project = miss; cross-region = miss)Workspace-level (desde 2026-02-05) + cache key prefix
Governance (IAM, CMEK, audit)Limitada (org-level)IAM full no Vertex (cacheConfig.disableCache); CMEK não aplicável ao implicit (RAM-only)Workspace-level (Claude API + Microsoft Foundry + Claude Platform on AWS) · Project-level no Vertex
Granularidade de pinPor key string (lógica)Por (project, region, model, prefix bytes) — granularidade não-tunávelPor breakpoint (até 4 por request)
Cap de throughput por hint~15 RPM/keyN/A (sem hint)Sem cap explícito
Custo do mecanismo$0 (apenas hint)$0 (implicit não tem fee de write nem storage)1.25× ou 2× write multiplier no primeiro hit
DeterminismoProbabilístico (best-effort)Probabilístico (best-effort; no cost saving guarantee)Determinístico (hit ou miss por prefix hash exato + workspace)
+
+ +

Conclusão estrutural

+ +

Sob a constraint implicit-only, Gemini/Vertex não tem shard pin user-facing: o pin é puramente uma propriedade emergente do (project × region × model × bytes do prefixo). Toda a "engenharia de pin" se resume a manter o prefixo byte-idêntico, rotear sessões da mesma tenant para a mesma região e evitar trocar de modelo durante a sessão. Para tenant-isolation, basta isolar por project ou por prefix dedicado (que vira pin natural via bytes).

+ +

O cache_control do Anthropic é determinístico, mas o pin é local ao request (per-block breakpoint) em vez de global. É mais leve (sem lifecycle externo, sem storage cost separado) mas tem limite de 4 breakpoints por request e exige placement disciplinado.

+ +

O metadata.user_id do Anthropic NÃO afeta cache routing — é apenas para tracking de end-user (abuse, audit). A arquitetura Anthropic usa um cache lógico por (workspace × prefix bytes × model), então não precisa de shard pin adicional. Workspace-level isolation a partir de 2026-02-05 funciona como pin coarse-grained natural.

+ +

Multi-tenant — receitas de isolation

+ +
    +
  • OpenAI: prompt_cache_key = sha256(f"{tenant_id}:{session_id}")[:32] — granularidade sub-15-RPM; cache nunca atravessa fronteira de organização (garantia oficial)
  • +
  • Gemini/Vertex (implicit-only): isolamento por project (cache não atravessa fronteira de project) + region (cache não atravessa fronteira regional). Dentro do mesmo project/region, prefixos dedicados por tenant (ex.: tenant_header = f"# TENANT: {hash(tenant_id)[:16]}\n" no topo do system_instruction) viram pin natural por bytes — cross-tenant leak depende de o prefixo do tenant A ser literalmente igual ao do tenant B, o que o header dedicado impede.
  • +
  • Vertex hardening: 1 project por tenant crítico = isolation absoluta (cache RAM jamais cruza projects). VPC-SC perimeter por project. CMEK em outros recursos Vertex que persistem at-rest (não aplicável ao implicit cache).
  • +
  • Anthropic: 1 workspace por tenant (a partir de 2026-02-05); ou metadata.user_id per-request para tracking sem afetar cache
  • +
+ + +

10.9 Caching multimodal — imagens, áudio, vídeo, PDF

+ +

Cache multimodal funciona nos 3 providers com uma armadilha universal: bytes precisam ser idênticos. Re-encode, EXIF strip, recompressão JPEG com quality variável = bytes diferentes = hash diferente = miss silencioso. Trate mídia como conteúdo imutável upstream — cache bytes uma vez e reuse-os literalmente.

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Suporte de caching por modalidade × provider (verificado 2026-06-10)
ModalidadeOpenAIGemini Developer / VertexAnthropic
Imagens✅ Cacheável como parte do prefixo. Ensure the detail parameter is set identically, as it impacts image tokenization. URL ou base64; multi-image ok✅ Implicit hit quando o payload (incluindo inlineData ou fileData Files API) atinge o min do modelo e os bytes do prefixo são idênticos; cap 10 MB inline no Vertex✅ Block image cacheável via cache_control. Atenção: presença/ausência de imagens em qualquer lugar do prompt invalida Messages cache (matriz §10.6)
Áudio✅ E o desconto é dramático: gpt-realtime-2 audio input $32/1M, cached input $0.40/1M = −98.75%. usage agrega em input_audio_tokens + Usage API agrega via input_audio_tokens✅ Nativo (32 tk/segundo). Implicit hit quando o payload com áudio atinge o min do modelo e os bytes do prefixo são idênticos. Vertex aceita áudio "max 10 MB por item inline"N/A — Messages API não aceita áudio nativo. Use STT externo (Whisper / gpt-4o-transcribe) antes de mandar texto para Claude
VídeoN/A — sem vídeo input nativo. Extrair frames manualmente para enviar como imagens✅ Nativo (Gemini 3: 70 tk/frame default, HIGH 280 + 32 tk/s áudio ≈ 102 tk/s default). Implicit hit possível; cap 10 MB inline no Vertex (GCS URI acima)N/A
PDF✅ input_file via file_id, file_url, ou file_data base64. Cap 50 MB. Cacheável✅ Nativo (Gemini 3: 560 tk/pág default MEDIUM + texto nativo grátis). Cap 50 MB / 1000 pgs. Implicit hit possível via Files API ou inlineData✅ Block document cacheável via cache_control. Cap 32 MB / 600 pgs (1M ctx)
+
+ +

Pitfalls de byte-identity (cross-provider)

+
    +
  • Imagem reencoded: resizing, EXIF strip, recompressão JPEG, conversão color space — bytes diferentes. Cache the encoded bytes upstream; nunca re-codifique a cada turno.
  • +
  • OpenAI detail param: auto ↔ high ↔ low mudança = tokenization diferente = hash diferente.
  • +
  • Document re-extraction: se você re-extrai texto de um PDF e a tokenização produz bytes ligeiramente diferentes (trailing whitespace, BOM), miss.
  • +
  • Gemini/Vertex GCS URI: mutar o objeto referenciado por fileData.fileUri não invalida o implicit cache explicitamente — o pin é por bytes do payload, não pelo estado atual do GCS object. Para conteúdo volátil, embuta um content hash no prefixo para forçar miss intencional.
  • +
  • Vertex 10 MB inline limit: vídeo longo precisa fragmentação ou GCS URI; 1 vídeo HD de 30s já passa de 10 MB.
  • +
+ +

Ganho dramático — OpenAI Realtime audio

+ +

O caso de uso de áudio cacheado tem o maior multiplicador de economia em todo o ecossistema cross-provider:

+ +
+ + + + + + +
gpt-realtime family (cookbook prompt_caching_201, 2026-06-10)
ModeloAudio input/1MCached audio input/1MDesconto
gpt-realtime-2$32.00$0.40−98.75%
+
+ +

Implicação: em workloads de voice agent com prompt audio estável (instruções tts-style do assistant, ou voice prompts repetidos), cachear o áudio do prefixo pode reduzir custo de input audio em quase 99%. Vale auditar.

+ + +

10.10 Captura de custo real — CostEvent emitter cross-provider

+ +

Cada provider devolve um usage com semântica diferente. Para FinOps real (alertas, budget gates, attribution por tenant), você precisa de um emitter cross-provider que normalize as 3 shapes em uma única CostEvent com pricing-multiplier aplicado e que reconcilie periodicamente com a billing aggregate (OpenAI Usage API, Anthropic Workspace, Vertex Cloud Billing).

+ +

Schema canônico do CostEvent

+ +
from dataclasses import dataclass
+from typing import Optional
+
+@dataclass
+class CostEvent:
+    # Identification
+    request_id: str                 # client-side UUID
+    timestamp: float                 # Unix seconds
+    provider: str                    # "openai" | "gemini" | "anthropic"
+    surface: str                     # "responses" | "generate_content" | "interactions" | "vertex_*" | "messages"
+    model: str                       # exact snapshot pinned
+
+    # Routing / multi-tenant
+    project_id: Optional[str]
+    tenant_id: Optional[str]
+    session_id: Optional[str]
+    cache_pin: Optional[str]            # prompt_cache_key (OpenAI) | None (Gemini implicit, Anthropic)
+
+    # Tokens (normalized)
+    input_tokens_uncached: int          # pós-breakpoint (Anthropic) ou (total - cached) outros
+    input_tokens_cached_read: int       # hit
+    input_tokens_cached_write_5m: int   # Anthropic only (others = 0)
+    input_tokens_cached_write_1h: int   # Anthropic only (others = 0)
+    output_tokens_visible: int
+    output_tokens_reasoning: int        # reasoning/thinking (cobrado como output)
+    output_tokens_rejected_pred: int    # OpenAI Predicted Outputs rejeitados
+
+    # Modality breakdown (optional)
+    audio_input_tokens: int = 0
+    audio_output_tokens: int = 0
+    image_input_tokens: int = 0
+    video_input_tokens: int = 0
+    document_input_tokens: int = 0
+
+    # Cost (USD, computed via pricing table). Decimal evita drift de ponto-flutuante
+    # em soma semanal/mensal — float "0.5+0.1" = 0.6000000000000001 não fecha.
+    cost_usd: Decimal
+
+    # Provenance for reconciliation
+    provider_response_id: Optional[str]  # response.id / interaction.id / message.id (None se SDK não retornar)
+ +

Emitter Python — cobre os 3 providers

+ +
import hashlib, json, os, time, uuid
+from decimal import Decimal, getcontext
+getcontext().prec = 12   # 6 casas decimais para custo USD é suficiente
+ONE_M = Decimal("1000000")
+
+# Pricing por 1M tokens (verificado 2026-06-10; valide periodicamente)
+PRICING = {  # valores em Decimal para preservar precisão na soma agregada
+    # OpenAI (input, cached_input, output) — read = 0.1×
+    "gpt-5.5":        {"in": Decimal("5.00"), "cached": Decimal("0.50"),  "out": Decimal("30.00")},
+    "gpt-5.4-mini":   {"in": Decimal("0.75"), "cached": Decimal("0.075"), "out": Decimal("4.50")},
+    "gpt-5.4-nano":   {"in": Decimal("0.20"), "cached": Decimal("0.02"),  "out": Decimal("1.25")},
+
+    # Gemini (input, cached_input, output) — Gemini 3+
+    "gemini-3.1-pro-preview":  {"in": Decimal("2.00"), "cached": Decimal("0.20"),  "out": Decimal("12.00")},
+    "gemini-3.5-flash":        {"in": Decimal("1.50"), "cached": Decimal("0.15"),  "out": Decimal("9.00")},
+    "gemini-3.1-flash-lite":   {"in": Decimal("0.25"), "cached": Decimal("0.025"), "out": Decimal("1.50")},
+
+    # Anthropic (input, 5m_write, 1h_write, cache_read, output)
+    "claude-opus-4-8":   {"in": Decimal("5.00"), "w5m": Decimal("6.25"), "w1h": Decimal("10.00"), "read": Decimal("0.50"), "out": Decimal("25.00")},
+    "claude-sonnet-4-6": {"in": Decimal("3.00"), "w5m": Decimal("3.75"), "w1h": Decimal("6.00"),  "read": Decimal("0.30"), "out": Decimal("15.00")},
+    "claude-haiku-4-5":  {"in": Decimal("1.00"), "w5m": Decimal("1.25"), "w1h": Decimal("2.00"),  "read": Decimal("0.10"), "out": Decimal("5.00")},
+}
+
+def stable_cache_key(tenant: str, session: str) -> str:
+    """Granularidade < 15 RPM per key — mesmo tenant+sessão = mesmo shard.
+
+    SEGURANÇA: separador NUL (\x00) ou json.dumps evita ambiguidade
+    ("acme:x","y") vs ("acme","x:y") que colide com sha256(f"{t}:{s}").
+    NUNCA logue o retorno em logs/traces/error messages — fingerprint permite
+    cache-probing attack cross-tenant.
+    """
+    if not (tenant and session):
+        raise ValueError("tenant e session são obrigatórios — sem isso, todos colidem no mesmo shard")
+    payload = json.dumps([tenant, session], separators=(",", ":")).encode()
+    return hashlib.sha256(payload).hexdigest()[:32]
+
+def _field(obj, name, default=0):
+    """Lê campo de objeto SDK OU dict (raw-response mode) sem colapsar para 0."""
+    if obj is None:
+        return default
+    if isinstance(obj, dict):
+        return obj.get(name, default)
+    return getattr(obj, name, default)
+
+def cost_from_openai(resp, *, tenant=None, session=None) -> CostEvent:
+    u = resp.usage
+    in_det  = getattr(u, "input_tokens_details", None)
+    out_det = getattr(u, "output_tokens_details", None)
+    cached  = _field(in_det,  "cached_tokens", 0)
+    reason  = _field(out_det, "reasoning_tokens", 0)
+    rejpred = _field(out_det, "rejected_prediction_tokens", 0)
+    in_tok  = u.input_tokens
+    out_tok = u.output_tokens
+
+    p = PRICING[resp.model]
+    cost = (Decimal(in_tok - cached) * p["in"] + Decimal(cached) * p["cached"] + Decimal(out_tok) * p["out"]) / ONE_M
+
+    # WARNING ativo: reasoning dominante + cached > 0 = cache ajuda pouco
+    if reason > out_tok * 0.5 and cached > 0:
+        logging.warning("openai cost: reasoning_tokens (%d) > 50%% of output (%d) — cache só salva ~%.0f%% da fatura",
+                        reason, out_tok, (in_tok - cached) * 100 / max(in_tok + out_tok, 1))
+
+    return CostEvent(
+        request_id=str(uuid.uuid4()), timestamp=time.time(),
+        provider="openai", surface="responses", model=resp.model,
+        project_id=os.environ.get("OPENAI_PROJECT_ID"), tenant_id=tenant, session_id=session,
+        cache_pin=stable_cache_key(tenant, session) if tenant and session else None,
+        input_tokens_uncached=in_tok - cached,
+        input_tokens_cached_read=cached,
+        input_tokens_cached_write_5m=0, input_tokens_cached_write_1h=0,
+        output_tokens_visible=out_tok - reason,
+        output_tokens_reasoning=reason,
+        output_tokens_rejected_pred=rejpred,
+        cost_usd=cost, provider_response_id=resp.id,
+    )
+
+def cost_from_gemini(resp, model: str, *, surface="generate_content", tenant=None, session=None, cache_name=None) -> CostEvent:
+    # generateContent → usage_metadata; Interactions → usage
+    u = getattr(resp, "usage_metadata", None) or getattr(resp, "usage", None)
+    if u is None:
+        raise ValueError("response sem usage_metadata nem usage — modelo/SDK fora do esperado")
+    in_tok  = _field(u, "prompt_token_count",         None) or _field(u, "total_input_tokens",   0)
+    out_tok = _field(u, "candidates_token_count",     None) or _field(u, "total_output_tokens",  0)
+    cached  = _field(u, "cached_content_token_count", None) or _field(u, "total_cached_tokens",  0)
+    thoughts= _field(u, "thoughts_token_count",       None) or _field(u, "total_thought_tokens", 0)
+
+    p = PRICING[model]
+    cost = (Decimal(in_tok - cached) * p["in"] + Decimal(cached) * p["cached"] + Decimal(out_tok) * p["out"]) / ONE_M
+
+    # WARNING: Interactions sob store=false retorna cached=0 quase sempre — sinaliza para o operador
+    if surface.startswith("vertex_interactions") and cached == 0 and in_tok > 8000:
+        logging.warning("gemini cost: Interactions store=false + cached=0 em prefixo grande — esperado (implicit-only); migre para generateContent se cache hit é prioridade (§10.4)")
+
+    return CostEvent(
+        request_id=str(uuid.uuid4()), timestamp=time.time(),
+        provider="gemini", surface=surface, model=model,
+        project_id=os.environ.get("GOOGLE_CLOUD_PROJECT"), tenant_id=tenant, session_id=session,
+        cache_pin=cache_name,
+        input_tokens_uncached=in_tok - cached,
+        input_tokens_cached_read=cached,
+        input_tokens_cached_write_5m=0, input_tokens_cached_write_1h=0,
+        output_tokens_visible=out_tok - thoughts,
+        output_tokens_reasoning=thoughts,
+        output_tokens_rejected_pred=0,
+        cost_usd=cost, provider_response_id=getattr(resp, "response_id", None) or getattr(resp, "id", None),
+    )
+
+def cost_from_anthropic(resp, *, tenant=None, session=None) -> CostEvent:
+    u = resp.usage
+    in_tok      = u.input_tokens                          # pós-breakpoint (uncached only)
+    read        = _field(u, "cache_read_input_tokens", 0)
+    create_tot  = _field(u, "cache_creation_input_tokens", 0)
+    cc          = getattr(u, "cache_creation", None)
+    # Se cache_creation não veio detalhado, atribui tudo a 5m (default ephemeral).
+    write_5m    = _field(cc, "ephemeral_5m_input_tokens", None)
+    write_1h    = _field(cc, "ephemeral_1h_input_tokens", None)
+    if write_5m is None and write_1h is None:
+        write_5m, write_1h = create_tot, 0
+    write_5m, write_1h = write_5m or 0, write_1h or 0
+    out_tok     = u.output_tokens
+
+    p = PRICING[resp.model]
+    cost = (
+        Decimal(in_tok)   * p["in"]   +
+        Decimal(write_5m) * p["w5m"]  +
+        Decimal(write_1h) * p["w1h"]  +
+        Decimal(read)     * p["read"] +
+        Decimal(out_tok)  * p["out"]
+    ) / ONE_M
+
+    # WARNING: write paid sem read = breakeven negativo (default ttl=5m precisa 1 read; 1h precisa 2)
+    if (write_5m + write_1h) > 0 and read == 0:
+        logging.warning("anthropic cost: cache_write=%d sem cache_read na mesma chamada — primeiro turn pay-once é esperado, MAS se persistir em >30%% das requests, desative cache_control", write_5m + write_1h)
+
+    return CostEvent(
+        request_id=str(uuid.uuid4()), timestamp=time.time(),
+        provider="anthropic", surface="messages", model=resp.model,
+        project_id=None, tenant_id=tenant, session_id=session,
+        cache_pin=None,                                # Anthropic não tem shard pin user-facing
+        input_tokens_uncached=in_tok,
+        input_tokens_cached_read=read,
+        input_tokens_cached_write_5m=write_5m,
+        input_tokens_cached_write_1h=write_1h,
+        output_tokens_visible=out_tok,                    # Anthropic não separa thinking aqui
+        output_tokens_reasoning=0,                       # thinking somado em output_tokens com thinking.enabled
+        output_tokens_rejected_pred=0,
+        cost_usd=cost, provider_response_id=resp.id,
+    )
+ +

Reconciliação periódica — 3 fontes de truth

+ +
+ + + + + + + + + +
ProviderSource of truthEndpoint / PathLatência
OpenAIAdmin Usage APIGET /v1/organization/usage/completions + /costsEmpiricamente < 1h, SLA UNVERIFIED
Gemini Developer APISem export oficial — use só usage_metadata per-call agregado client-side—Real-time (client-side)
Gemini Vertex / Vertex InteractionsCloud Billing Export → BigQuerygcp_billing_export_v1_<ID>~24h
Anthropic Claude API diretaAnthropic Workspace billingConsole UI; sem API pública confirmada para usage download UNVERIFIEDVariável
Claude on Vertex AICloud Billing Export → BigQueryMesmo do Vertex Gemini, SKU diferente~24h
+
+ +

Estratégia: persista CostEvent em BigQuery ou Postgres particionado por dia; rode reconciliação semanal cruzando local sum × billing aggregate; alerte se divergência > 5%.

+ +

Sink — emit_cost_event de referência

+
from dataclasses import asdict
+import logging, json
+
+logger = logging.getLogger("cost")
+
+def emit_cost_event(ev: CostEvent) -> None:
+    """Sink mínimo: JSON estruturado. Em prod, plug em BigQuery / Postgres / Kafka."""
+    logger.info(json.dumps(asdict(ev), default=str, sort_keys=True))
+
+# Variante BigQuery (1 row por evento — agregue depois em scheduled query)
+# from google.cloud import bigquery
+# BQ = bigquery.Client(); TABLE = "project.dataset.cost_events"
+# def emit_cost_event(ev): BQ.insert_rows_json(TABLE, [asdict(ev)])
+
+# Variante Postgres (psycopg async)
+# async def emit_cost_event(ev): await pool.execute("INSERT INTO cost_events ...", *asdict(ev).values())
+ +

Alerta de drift: agendado diário, query BQ SELECT SUM(cost_usd) FROM cost_events WHERE DATE(timestamp_sec)=CURRENT_DATE()-1 vs SELECT SUM(cost) FROM gcp_billing_export_v1_* agrupado por provider — divergência > 5% dispara PagerDuty. Para reasoning-heavy (reasoning_tokens / output_tokens > 0.5) ou Interactions sob store=false (cached=0 sustentado em prefixo grande), emita warning paralelo: cache não está te salvando — reveja effort, ou migre Interactions → generateContent com prefixo estável (implicit hit automático).

+ + +

10.11 Receitas — copy & paste

+ +

R1 · OpenAI Responses stateless + encrypted_content + prompt_cache_key

+ +

Pré-requisitos: stable_cache_key, cost_from_openai, emit_cost_event, PRICING definidos em §10.10. LONG_STABLE_SYSTEM e STABLE_TOOLS_SORTED são constantes da sua app (system prompt e tools array byte-estáveis, JSON com sort_keys=True).

+ +
from openai import OpenAI
+from cost_module import stable_cache_key, cost_from_openai, emit_cost_event
+client = OpenAI()
+
+# Turn 1
+r1 = client.responses.create(
+    model="gpt-5.5",
+    input=[{"role":"user","content":"Resolva X"}],
+    instructions=LONG_STABLE_SYSTEM,                         # prefixo cacheável
+    tools=STABLE_TOOLS_SORTED,                                # JSON com sort_keys
+    store=False,                                            # PIVOT
+    include=["reasoning.encrypted_content"],                # multi-turn stateless
+    prompt_cache_key=stable_cache_key(tenant_id, session_id),
+    prompt_cache_retention="24h",                            # default em gpt-5.5
+    reasoning={"effort": "medium"},
+)
+emit_cost_event(cost_from_openai(r1, tenant=tenant_id, session=session_id))
+
+# Turn 2 — round-trip do encrypted reasoning
+# IMPORTANTE: manter instructions/tools BYTE-idênticos + prompt_cache_retention="24h"
+# Sem o retention="24h" no turn 2, o prefixo cai em in_memory (5–10 min) e o hit
+# do turn 1 expira muito mais cedo do que o esperado.
+reasoning_items = [it for it in r1.output if it.type == "reasoning"]
+r2 = client.responses.create(
+    model="gpt-5.5",
+    input=[*reasoning_items, {"role":"user","content":"Refine"}],
+    instructions=LONG_STABLE_SYSTEM, tools=STABLE_TOOLS_SORTED,
+    store=False, include=["reasoning.encrypted_content"],
+    prompt_cache_key=stable_cache_key(tenant_id, session_id),
+    prompt_cache_retention="24h",
+)
+emit_cost_event(cost_from_openai(r2, tenant=tenant_id, session=session_id))
+ +

R2 · Gemini Vertex stateless com implicit caching (sem nomear cache)

+ +
+ Constraint do projeto: não criar cachedContents. A única alavanca de cache aqui é manter o prefixo (system_instruction + tools + RAG header) byte-idêntico em chamadas sequenciais para o mesmo (project, region, model). O hit aparece em usage_metadata.cached_content_token_count sem nenhuma chamada de gerência de cache adicional. +
+ +

Pré-requisitos: cost_from_gemini, emit_cost_event em §10.10. Auth: ADC (gcloud auth application-default login em dev ou Workload Identity em GKE/Cloud Run). STABLE_SYSTEM_INSTRUCTION deve incluir um tenant_header dedicado para que o pin natural (por bytes) também sirva como tenant-isolation. RAG_HEADER só pode entrar no prefixo se ele for estável dentro da sessão; chunks voláteis devem ir depois da fronteira que você quer cachear (ou no final do user turn).

+ +
from google import genai
+from google.genai.types import GenerateContentConfig
+from cost_module import cost_from_gemini, emit_cost_event
+
+client = genai.Client(vertexai=True, project="prj", location="us-central1")
+
+# Monte UMA VEZ por tenant; reuse byte-idêntico em todos os turnos do mesmo (project, region, model).
+# O tenant_header transforma o pin-por-bytes em tenant isolation natural sob a constraint implicit-only.
+def build_stable_prefix(tenant: str) -> str:
+    tenant_header = f"# TENANT: {hash_tenant(tenant)}\n"   # hash estável, sem PII
+    return tenant_header + BASE_SYSTEM_INSTRUCTION + STABLE_RAG_HEADER
+
+# Cada turno: prefixo byte-idêntico + user message dinâmica
+def turno(tenant: str, user_msg: str, local_history: list):
+    resp = client.models.generate_content(
+        model="gemini-3.1-pro-preview",                       # mesmo ID em toda a sessão (Pro ≠ Flash ≠ Lite)
+        contents=local_history + [{"role":"user","parts":[{"text":user_msg}]}],
+        config=GenerateContentConfig(
+            system_instruction=build_stable_prefix(tenant),       # byte-idêntico → pin implicit
+            tools=STABLE_TOOLS,                                    # ordem fixa
+            thinking_level="medium",
+            temperature=0.0,
+        ),
+    )
+    cached = getattr(resp.usage_metadata, "cached_content_token_count", 0) or 0
+    emit_cost_event(cost_from_gemini(
+        resp, "gemini-3.1-pro-preview",
+        surface="vertex_generate_content", tenant=tenant,
+    ))
+    if cached == 0 and resp.usage_metadata.prompt_token_count >= 4096:
+        # Prefixo >= 4096 mas sem hit: revisar identidade de bytes, region, model snapshot, ou janela RAM evicted.
+        log_implicit_miss(tenant, resp.usage_metadata.prompt_token_count)
+    return resp.text
+
+# NÃO há cache.create, cache.update nem cache.delete.
+# NÃO há TTL nem displayName a gerenciar.
+# Para invalidar (incident response ou rotação): mude 1 byte no tenant_header (ex.: incremente o suffix).
+ +

R3 · Anthropic 4-breakpoint chat com tools + RAG + tail

+ +
+ ⚠ Hardening obrigatório antes de produção multi-tenant: +
    +
  • RAG poisoning persistente (1h): o exemplo abaixo cacheia o bloco RAG (retrieved_chunks) por 1h. Se o chunk vier de fonte não-confiável (web, user-upload, índice compartilhado entre tenants) e contiver prompt injection, o cache contamina todas as próximas respostas do MESMO workspace por até 60 min. Mitigação: (a) NUNCA aplique cache_control em RAG não-trusted — mova-o para DEPOIS do último breakpoint, (b) ou separe workspace por tier de confiança, (c) ou injete tenant_id visível no preamble do system para forçar partição.
  • +
  • Warm-up antes de paralelizar: cache só está disponível DEPOIS que a primeira response começa. Disparar N requests concorrentes com mesmo prefixo = N writes pagos (denial-of-wallet em incident). Faça uma chamada sequencial primeiro, espere o response, depois paralelize.
  • +
  • Workspace-level isolation NÃO é tenant-level: 1 workspace Anthropic com N tenants = caches compartilhados se prefixo for idêntico. Para isolation real, ou 1 workspace por tenant (cost operacional alto), ou incluir tenant_id visível no início do system text (quebra cache cross-tenant by design).
  • +
+
+ +

Pré-requisitos: cost_from_anthropic, emit_cost_event em §10.10. LONG_STABLE_INSTRUCTIONS, TOOLS_HEAD, TOOLS_LAST, history, retrieved_chunks, tenant_id, session_id são da sua app. Atenção ao callout acima antes de usar em multi-tenant.

+ +
import anthropic
+from cost_module import cost_from_anthropic, emit_cost_event
+client = anthropic.Anthropic()
+
+SYSTEM_BLOCKS = [
+    {"type":"text","text":"You are a domain expert..."},
+    {"type":"text","text":LONG_STABLE_INSTRUCTIONS,
+     "cache_control":{"type":"ephemeral","ttl":"1h"}},          # breakpoint 1 (system; ttl=1h só se >=2 reads/h esperados)
+]
+
+# WARMUP: rode UMA chamada sequencial e ESPERE response antes de paralelizar
+# requests concorrentes. Sem isso, todos pagam cache_write (denial-of-wallet).
+
+TOOLS = [
+    *TOOLS_HEAD,
+    {**TOOLS_LAST,
+     "cache_control":{"type":"ephemeral","ttl":"1h"}},          # breakpoint 2 (tools last)
+]
+
+def build_messages(history, retrieved_chunks, user_msg):
+    return [
+        {"role":"user","content":[
+            {"type":"text","text":f"Reference docs:\n{retrieved_chunks}",
+             "cache_control":{"type":"ephemeral"}},                # breakpoint 3 (RAG)
+        ]},
+        {"role":"assistant","content":"Got the references."},
+        *history[:-4],
+        *history[-4:],
+        {"role":"user","content":[
+            {"type":"text","text":user_msg,
+             "cache_control":{"type":"ephemeral"}},                  # breakpoint 4 (tail, 5m)
+        ]},
+    ]
+
+resp = client.messages.create(
+    model="claude-opus-4-8",
+    max_tokens=1024,
+    system=SYSTEM_BLOCKS,
+    tools=TOOLS,
+    messages=build_messages(history, retrieved_chunks, user_msg),
+)
+emit_cost_event(cost_from_anthropic(resp, tenant=tenant_id, session=session_id))
+ +

R4 · Cache Diagnostics loop (Anthropic) para debug de hit rate

+
messages, prev_id = [], None
+DIAG_HEADER = {"anthropic-beta": "cache-diagnosis-2026-04-07"}
+SYSTEM_BLOCKS = [
+    {"type": "text", "text": SYSTEM_TEXT,
+     "cache_control": {"type": "ephemeral", "ttl": "1h"}},
+]
+
+for user_msg in user_messages:
+    messages.append({"role":"user","content":user_msg})
+    r = client.messages.create(            # NÃO client.beta.messages.create
+        model="claude-opus-4-8",
+        max_tokens=1024,
+        system=SYSTEM_BLOCKS,               # cache_control DENTRO do bloco
+        messages=messages,
+        diagnostics={"previous_message_id": prev_id},
+        extra_headers=DIAG_HEADER,          # beta header via HTTP, não body
+    )
+    print(f"read={r.usage.cache_read_input_tokens} create={r.usage.cache_creation_input_tokens}")
+    if r.diagnostics and r.diagnostics.cache_miss_reason:
+        reason = r.diagnostics.cache_miss_reason
+        print(f"  MISS: type={reason.type}, missed={reason.cache_missed_input_tokens}")
+        # Take action por type — system_changed / tools_changed / messages_changed / model_changed
+    messages.append({"role":"assistant","content":r.content})
+    prev_id = r.id
+ +

R5 · Reconciliação semanal Vertex via Cloud Billing → BigQuery

+ +
+ ⚠ Allowlist obrigatória de labels.* antes de exportar para data lake externo. O Cloud Billing Export REPLICA todas as labels do request no BigQuery. Se sua app fizer SetLabels({"user_email": "...", "tenant_phone": "..."}) para tagging, esses valores saem do perímetro VPC-SC junto com o billing. Allowlist recomendada: +
    +
  • ✅ tenant_hash, workspace_id, service_id, environment, cost_center (não-PII)
  • +
  • ❌ user_email, user_id, session_id, device_id, qualquer identificador direto
  • +
+ Reforce no client SDK com um filtro SetLabels(filter_pii(labels)) antes de enviar. Audite trimestralmente via SELECT DISTINCT label_keys FROM gcp_billing_export_v1_*, UNNEST(labels). +
+ +
# Materialized view (BigQuery scheduled query, executar diariamente)
+CREATE OR REPLACE TABLE `analytics.vertex_cost_hourly`
+PARTITION BY DATE(hour)
+CLUSTER BY project_id, model_family
+OPTIONS(
+  partition_expiration_days=180,
+  description="Vertex AI cost breakdown por hour/project/family/SKU type — fonte Cloud Billing Export"
+)
+AS
+SELECT
+  TIMESTAMP_TRUNC(usage_start_time, HOUR) AS hour,
+  project.id  AS project_id,
+  ANY_VALUE(REGEXP_EXTRACT(sku.description, r'(Gemini [0-9.]+ [A-Za-z-]+)')) AS model_family,
+  SUM(CASE WHEN sku.description LIKE '%Cached Input%'                                       THEN cost END) AS cached_input_cost,
+  SUM(CASE WHEN sku.description LIKE '% Input Token%' AND sku.description NOT LIKE '%Cached%' THEN cost END) AS raw_input_cost,
+  SUM(CASE WHEN sku.description LIKE '% Output Token%'                                      THEN cost END) AS output_cost,
+  -- (Sem coluna "Context Cache Storage": implicit-only não gera SKU de storage.)
+  SUM(cost) AS total_cost
+FROM `PROJECT.DATASET.gcp_billing_export_v1_BILLING_ACCOUNT_ID`
+WHERE service.description = 'Vertex AI API'
+  AND project.id = 'your-project'
+  AND usage_start_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)
+GROUP BY hour, project_id;
+ + +

10.12 Armadilhas universais, UNVERIFIED e fontes

+ +

Armadilhas top-15 (cross-provider, verificadas)

+
    +
  1. Timestamp/request-ID/user-locale no topo do prompt — invalida cache em todos os providers. Mover para metadata ou para o primeiro user message depois do breakpoint.
  2. +
  3. Tools array reordenado — mesmo conteúdo, ordem diferente = hash diferente em todos. Sempre ordem fixa.
  4. +
  5. JSON serialization não-determinístico — Go map default, Swift Dictionary, Python dict pré-3.7 reorderam. Use json.dumps(..., sort_keys=True).
  6. +
  7. Imagens re-codificadas — bytes diferentes = miss em todos. Hash + reuse buffer; nunca re-encode a cada turno.
  8. +
  9. OpenAI: detail param mudança (auto↔high↔low) invalida porque a tokenização da imagem muda.
  10. +
  11. Anthropic: presença/ausência de imagens anywhere no prompt invalida Messages cache (não Tools/System).
  12. +
  13. Model promotion — cache reset total. gpt-5.5→gpt-5.6, Gemini 2.5→3.x, Opus 4.6→4.7 são fronteiras de cache.
  14. +
  15. OpenAI: reasoning.effort mudança invalida (muda prefill).
  16. +
  17. Anthropic: tool_choice, thinking, web_search toggle, citations toggle — invalidam parcialmente conforme matriz §10.6.
  18. +
  19. Anthropic: thinking blocks em Haiku 4.5 — não preservados; Opus/Sonnet 4.6+ preservam.
  20. +
  21. Anthropic: cache só disponível DEPOIS da primeira response começar — concurrent requests todos pagam write se disparados em paralelo. Warm-up call sequencial primeiro.
  22. +
  23. Anthropic: lookback window de 20 blocks — em conversa > 20 blocks, breakpoint antigo sai da janela. Usar 2 breakpoints (head + tail).
  24. +
  25. Gemini Vertex implicit: GCS object mutation — o pin é por bytes do payload, não pelo estado atual do GCS object. Mutar o objeto NÃO invalida o implicit cache; embuta content hash no prefixo se precisa forçar miss intencional.
  26. +
  27. Gemini Vertex: australia-southeast1 não lista Context Cache — assumir cached=0 nas estimativas de custo.
  28. +
  29. OpenAI: background=true quebra ZDR — projetos ZDR ainda aceitam por compatibilidade legacy mas perdem a garantia.
  30. +
  31. OpenAI: Tracing dashboard built-in proibido em ZDR — use trace processors externos.
  32. +
  33. Anthropic: CORS desabilitado em ZDR — proxy backend obrigatório.
  34. +
  35. Anthropic: usage.input_tokens ≠ total — é só pós-breakpoint. Total real = input_tokens + cache_read + cache_creation.
  36. +
  37. Streaming cancelado — cliente perde usage final mas o billing continua server-side. Logue response_id antes do stream e reconcile.
  38. +
  39. Cloud Billing latência ~24h — não use para alertas operacionais; use usage_metadata per-call.
  40. +
+ +

UNVERIFIED — itens que precisam re-verificação antes de citar publicamente

+
    +
  • OpenAI gpt-5.4-mini / gpt-5.4-nano — Extended caching: RESOLVIDO em 2026-05-29. A afirmação anterior deste guia (Extended NÃO suportado nesses modelos, por enumeração negativa na lista Extended-eligible de 2026-05-26) ficou obsoleta: desde 2026-05-29 o default de prompt_cache_retention é "24h" para organizações sem ZDR em v1/responses, v1/chat/completions e v1/batch — inclusive em mini/nano (prompt-caching, verificado 2026-06-10). Organizações com ZDR permanecem em in_memory por default.
  • +
  • OpenAI prompt_cache_key ecoado no response object — parameter listado no body, mas referência do response não mostra echo. UNVERIFIED — assumir que NÃO; log local
  • +
  • OpenAI Admin Usage API SLA de latência — sem número oficial; empiricamente < 1h para buckets 1m. UNVERIFIED
  • +
  • OpenAI Batch API + caching desconto composto — Batch é 50% off; comportamento de cache hit dentro de Batch não declarado explicitamente. UNVERIFIED
  • +
  • Vertex cachedContentTokenCount em v1 generateContent response — esperado na prática quando há implicit hit, sem verbatim na página context-cache-use. UNVERIFIED
  • +
  • Vertex service.description exato em Cloud Billing — convenção "Vertex AI API"; verificar via SQL no próprio projeto. UNVERIFIED
  • +
  • Vertex SKU strings exatas para "Cached Input Tokens" etc. — não publicadas em página única; Cloud Billing Catalog API resolve. UNVERIFIED
  • +
  • Anthropic Cache Diagnostics matriz por modelo — exemplos só com Opus 4.8; inferência segura: todos os modelos da Messages API que aceitam cache_control aceitam diagnostics. UNVERIFIED
  • +
  • Anthropic Cache Diagnostics fingerprint retention TTL — doc diz limited time/briefly; sem número. UNVERIFIED
  • +
  • Anthropic ZDR formal disponível simultaneamente em Claude API direta + Vertex para a mesma org — doc separa data processors; confirmar com sales se ambos forem necessários. UNVERIFIED
  • +
  • Anthropic Workspace billing API pública para usage download — sem endpoint confirmado; Console UI apenas. UNVERIFIED
  • +
  • Gemini Interactions cache implícito > 0 sob store=false — o guia atual afirma "= 0" empiricamente; doc oficial não diz literalmente. UNVERIFIED
  • +
+ +

Fontes (todas verificadas 2026-06-10)

+ +
+ OpenAI + +
+ +
+ Google (Gemini Developer + Interactions + Vertex) + +
+ +
+ Anthropic + +
+ +
+ Verificação periódica. Os fatos perecíveis deste capítulo (pricing, model lists, TTL bounds, ZDR semantics, beta header names) devem ser re-verificados a cada 90 dias. Em refresh, bump da data 2026-06-10 nos blocos verbatim e diff contra as fontes oficiais — atualizar células divergentes, marcar inconclusivos como UNVERIFIED com URL+data, e propagar para o JSON-LD em §Sumário para IA. +
+ + +

10.13 Cross-provider failover — impacto no cache

+ +

SaaS sério tipicamente roteia entre providers em fallback (latency-based, error-based, ou capacity-based). Cada hop invalida cache no destino — pricing model precisa contar isso.

+ +
+ + + + + + + + + +
Custo de invalidação por hop (assumindo prefixo 50k tokens, tarifa de cada provider em USD/1M)
OrigemDestinoPor que invalidaWrite fee típico
OpenAI gpt-5.5Anthropic claude-opus-4-8Tokenização diferente; cache_control não existe no payload OpenAI50k × $6.25/1M (5m) ou $10/1M (1h) ≈ $0.31–$0.50
OpenAI gpt-5.5Vertex gemini-3.5-flashSDK/shape diferente, Cache não atravessa50k × $1.50/1M ≈ $0.075 (sem cache desconto na 1ª chamada)
Anthropic claude-opus-4-8OpenAI gpt-5.5Idem; prompt_cache_key precisa ser re-warmed50k × $5/1M (input) ≈ $0.25
Vertex gemini-3.5-flashAnthropic claude-opus-4-8Implicit pin (project × region × model × bytes) não atravessa borda; SDK/tokenizer diferentes50k × $6.25/1M (5m) ≈ $0.31
+
+ +

Estratégias de mitigação

+
    +
  • Pre-warm secondary em steady-state: envie ~1% do tráfego ao provider secundário continuamente para manter caches quentes; quando primary cai, failover não paga write fee da 1ª chamada de cada sessão. Custo extra: 1% do total — barato vs. $0.30/sessão em incident.
  • +
  • CostEvent track explícito do fallback factor: adicione campo was_failover: bool e fallback_from: Optional[str] ao schema; alertas de "fallback rate > X%" indicam degradação do primary e custo inflado.
  • +
  • Não faça failover para reduzir custo por chamada — apenas para indisponibilidade. Routing por preço cross-provider quase sempre perde para cache hit no primary.
  • +
  • Pin de prompt template idêntico cross-provider é tentador mas raramente otimiza: tokenização e contagem diferem entre Cl100k (OpenAI) / SentencePiece (Gemini) / Claude tokenizer (Anthropic). Mesmo template = 3 caches independentes. Não tente unificar — aceite N caches paralelos e meça custo total agregado.
  • +
+ +

Padrão de implementação

+
from dataclasses import replace
+
+PROVIDER_ORDER = ["openai", "gemini-vertex", "anthropic"]
+
+def call_with_failover(payload, *, tenant, session) -> CostEvent:
+    last_err = None
+    for idx, prov in enumerate(PROVIDER_ORDER):
+        try:
+            ev = call_provider(prov, payload, tenant=tenant, session=session)
+            # Marca failover ANTES de emit — analytics tracking
+            if idx > 0:
+                ev = replace(ev, surface=f"{ev.surface}__failover_from_{PROVIDER_ORDER[0]}")
+                logging.warning("failover %s → %s tenant=%s", PROVIDER_ORDER[0], prov, tenant)
+            emit_cost_event(ev)
+            return ev
+        except Exception as e:
+            last_err = e
+            continue
+    raise last_err
+
+ + +
+

Receitas práticas — copy & paste

+

Padrões recorrentes resolvidos nos 3 providers. Cada cartão mostra o cenário, o atalho recomendado, e a armadilha que evitar.

+ +
+
+

R1 · Gate de orçamento antes de chamar

+

Cenário: rejeitar requests acima de um teto antes de gastar.

+
    +
  • Conte com o endpoint pré-flight.
  • +
  • Compare contra budget = preço × tokens.
  • +
  • Some uma margem de 5–10 % para reasoning/system-added.
  • +
+
+
+

R2 · Roteamento por tamanho

+

Cenário: mandar prompts < 8k tokens para Flash, > 8k para Pro.

+
    +
  • Gemini: count_tokens e ramifique.
  • +
  • OpenAI/Anthropic: idem com seus endpoints.
  • +
  • Cache o resultado por hash do payload — count é determinístico.
  • +
+
+
+

R3 · Auditoria de cache

+

Cenário: medir cache hit rate e custo real.

+
    +
  • OpenAI: cached_tokens / input_tokens.
  • +
  • Gemini: cached_content_token_count / prompt_token_count.
  • +
  • Anthropic: cache_read_input_tokens / input_tokens.
  • +
+
+
+

R4 · Estimar PDF antes de subir

+

Cenário: usuário envia um PDF de 80 páginas — quantos tokens vai consumir?

+
    +
  • Suba para Files API, depois count_tokens com o file_id.
  • +
  • Gemini cobra menos por página texto-pesada; Anthropic mais (page-image sempre roda).
  • +
  • Mostre uma barra de progresso baseada no input_tokens estimado.
  • +
+
+
+

R5 · Logar reasoning em produção

+

Cenário: entender por que a chamada custou 5× o esperado.

+
    +
  • Sempre logue reasoning_tokens (OpenAI) / thoughts_token_count (Gemini).
  • +
  • Em Anthropic, log output_tokens com thinking.enabled: pico de output indica raciocínio longo.
  • +
  • Configure alertas para razão reasoning/output_visible > 5.
  • +
+
+
+

R6 · Truncar histórico ao se aproximar do limite

+

Cenário: conversação longa estourando o context window.

+
    +
  • Antes de cada turno, recount com o histórico + nova mensagem.
  • +
  • Se tokens > 0.85 · context_limit, drop ou sumarize os turnos mais antigos.
  • +
  • Lembre: Anthropic NÃO conta thinking de turnos anteriores; OpenAI/Gemini contam.
  • +
+
+
+
+ +
+

Cookbook — implementações end-to-end

+

Três scripts curtos, autônomos e production-ready cobrindo os usos mais comuns em conjunto.

+ +

6.1 Budget gate cross-provider

+

Um helper que recebe um payload e o provider, devolve (tokens, estimated_cost_usd, allow). Útil em filas de jobs e endpoints de RAG.

+
+
+ + +
+
from openai import OpenAI
+from google import genai
+import anthropic
+
+# preços de input por 1M tokens (referência 2026-06-10; valide no dashboard)
+PRICING = {
+    "openai:gpt-5.5": 5.00,
+    "gemini:gemini-3.1-pro-preview": 2.00,  # ≤200k ctx
+    "anthropic:claude-opus-4-8": 5.00,
+}
+LIMIT_USD = 0.05  # gate por chamada
+
+def budget_gate(provider, model, payload):
+    if provider == "openai":
+        client = OpenAI()
+        r = client.responses.input_tokens.count(model=model, **payload)
+        tokens = r.input_tokens
+    elif provider == "gemini":
+        client = genai.Client()
+        r = client.models.count_tokens(model=model, contents=payload["contents"])
+        tokens = r.total_tokens
+    else:
+        client = anthropic.Anthropic()
+        r = client.messages.count_tokens(model=model, **payload)
+        tokens = r.input_tokens
+
+    cost = (tokens / 1_000_000) * PRICING[f"{provider}:{model}"]
+    return tokens, cost, cost <= LIMIT_USD
+
+
import OpenAI from "openai";
+import { GoogleGenAI } from "@google/genai";
+import Anthropic from "@anthropic-ai/sdk";
+
+const PRICING: Record<string, number> = {
+  "openai:gpt-5.5": 5.00,
+  "gemini:gemini-3.1-pro-preview": 2.00,  // ≤200k ctx
+  "anthropic:claude-opus-4-8": 5.0,
+};
+const LIMIT_USD = 0.05;
+
+export async function budgetGate(
+  provider: "openai" | "gemini" | "anthropic",
+  model: string,
+  payload: any,
+) {
+  let tokens = 0;
+  if (provider === "openai") {
+    const r = await new OpenAI().responses.inputTokens.count({ model, ...payload });
+    tokens = r.input_tokens;
+  } else if (provider === "gemini") {
+    const r = await new GoogleGenAI({}).models.countTokens({ model, contents: payload.contents });
+    tokens = r.totalTokens;
+  } else {
+    const r = await new Anthropic().messages.countTokens({ model, ...payload });
+    tokens = r.input_tokens;
+  }
+  const cost = (tokens / 1_000_000) * PRICING[`${provider}:${model}`];
+  return { tokens, cost, allow: cost <= LIMIT_USD };
+}
+
+
+ +

6.2 Roteamento por tamanho

+

Mandar prompts pequenos para o modelo barato/rápido (Flash/Haiku/mini) e os grandes para o frontier. Padrão idêntico nos 3 — só muda o cliente.

+
+
+ + +
+
from google import genai
+
+client = genai.Client()
+contents = ["…seu prompt longo aqui…"]
+
+# Pré-flight
+n = client.models.count_tokens(model="gemini-3.5-flash", contents=contents).total_tokens
+
+model = "gemini-3.5-flash" if n < 8000 else "gemini-3.1-pro-preview"
+resp = client.models.generate_content(model=model, contents=contents)
+print(resp.usage_metadata)
+
+
import { GoogleGenAI } from "@google/genai";
+
+const ai = new GoogleGenAI({});
+const contents = ["…seu prompt longo aqui…"];
+
+const n = (await ai.models.countTokens({ model: "gemini-3.5-flash", contents })).totalTokens;
+const model = n < 8000 ? "gemini-3.5-flash" : "gemini-3.1-pro-preview";
+const resp = await ai.models.generateContent({ model, contents });
+console.log(resp.usageMetadata);
+
+
+ +

6.3 Auditoria de gastos pós-call

+

Estrutura para logar e agregar cache + reasoning + output em um único registro por chamada — útil para painéis de FinOps.

+
+
+ + +
+
def audit_openai(resp):
+    u = resp.usage
+    return {
+        "in": u.input_tokens,
+        "out": u.output_tokens,
+        "cached": getattr(u.input_tokens_details, "cached_tokens", 0),
+        "reasoning": getattr(u.output_tokens_details, "reasoning_tokens", 0),
+    }
+
+def audit_gemini(resp):
+    u = resp.usage_metadata
+    return {
+        "in": u.prompt_token_count,
+        "out": u.candidates_token_count,
+        "cached": getattr(u, "cached_content_token_count", 0) or 0,
+        "thoughts": getattr(u, "thoughts_token_count", 0) or 0,
+    }
+
+def audit_anthropic(resp):
+    u = resp.usage
+    return {
+        "in": u.input_tokens,
+        "out": u.output_tokens,
+        "cache_read": getattr(u, "cache_read_input_tokens", 0),
+        "cache_create": getattr(u, "cache_creation_input_tokens", 0),
+    }
+
+
function auditOpenAI(resp: any) {
+  const u = resp.usage;
+  return {
+    in: u.input_tokens,
+    out: u.output_tokens,
+    cached: u.input_tokens_details?.cached_tokens ?? 0,
+    reasoning: u.output_tokens_details?.reasoning_tokens ?? 0,
+  };
+}
+function auditGemini(resp: any) {
+  const u = resp.usageMetadata;
+  return {
+    in: u.promptTokenCount,
+    out: u.candidatesTokenCount,
+    cached: u.cachedContentTokenCount ?? 0,
+    thoughts: u.thoughtsTokenCount ?? 0,
+  };
+}
+function auditAnthropic(resp: any) {
+  const u = resp.usage;
+  return {
+    in: u.input_tokens,
+    out: u.output_tokens,
+    cacheRead: u.cache_read_input_tokens ?? 0,
+    cacheCreate: u.cache_creation_input_tokens ?? 0,
+  };
+}
+
+
+
+ +
+

Armadilhas comuns

+
    +
  • Estimar imagem como chars/4. Erro típico: 50–500 %. Use o endpoint.
  • +
  • Esquecer dos tools no count. Um schema de 10 funções pesa centenas de tokens em qualquer provider.
  • +
  • Confiar em tiktoken para gpt-5.x com mídia. Tokenizer offline não conhece patches/tiles nem reasoning.
  • +
  • Anthropic: passar cache_control e achar que conta como cache hit. O endpoint de count NÃO usa cache; o ganho aparece só na chamada real.
  • +
  • Anthropic: contar thinking blocks anteriores. Eles são descartados pelo endpoint; só o thinking do turno atual conta.
  • +
  • Gemini: esquecer de anexar o próximo turno antes de recontar. chat.get_history() mostra só o que já passou; some sua próxima UserContent ao histórico antes de chamar count_tokens.
  • +
  • OpenAI: ignorar reasoning_tokens no painel de custo. Em xhigh, eles podem ser 80 % da fatura.
  • +
  • Imagens geradas no endpoint de count. Não passa por lá — use o billing do produto (Images API, Sora 2, Nano Banana).
  • +
  • System-added tokens (Anthropic). O endpoint pode listar tokens que NÃO são cobrados (system optimizations). Não trate o número como contrato exato.
  • +
+
+ +
+

Fontes & verificação

+

Cada fato no guia tem origem em uma das fontes abaixo, consultadas em 2026-06-10. Itens marcados UNVERIFIED não puderam ser confirmados na fonte oficial naquela data.

+
+ + + + + + + + + + + + + + + + +
ProviderRecursoURL
OpenAIToken counting guidehttps://developers.openai.com/api/docs/guides/token-counting
OpenAICount input tokens (API ref)/api/reference/python/resources/responses/subresources/input_tokens/methods/count
OpenAIReasoning & usagehttps://developers.openai.com/api/docs/guides/reasoning
OpenAItiktokenhttps://github.com/openai/tiktoken
GeminiUnderstanding tokenshttps://ai.google.dev/gemini-api/docs/tokens
Geminimodels.countTokens APIhttps://ai.google.dev/api/tokens
GeminiMedia resolutionhttps://ai.google.dev/gemini-api/docs/media-resolution
GeminiContext cachinghttps://ai.google.dev/gemini-api/docs/caching
AnthropicToken countinghttps://docs.claude.com/en/build-with-claude/token-counting
AnthropicCount tokens APIhttps://docs.claude.com/en/api/messages-count-tokens
AnthropicExtended thinkinghttps://docs.claude.com/en/build-with-claude/extended-thinking
AnthropicPrompt cachinghttps://docs.claude.com/en/build-with-claude/prompt-caching
+
+
+ +
+

Sumário para IA (JSON-LD)

+

Este bloco existe para que outro agente (RAG, scraper, indexador) possa extrair o resumo factual deste guia sem precisar parsear o HTML inteiro. Os propertyID seguem o padrão <provider>.<capability>.

+ +
+ Como usar este bloco: um agente / scraper pode pular direto para script[type="application/ld+json"] e tratar additionalProperty como uma matriz provider × capability. Os propertyID seguem o padrão <provider>.<capability> (com cross.* para fatos cross-provider) para facilitar mapping a YAML/JSONSchema downstream. +
+
+ +
+
+ +
+
+
+
Guia de Contagem de Tokens OpenAI · Gemini · Anthropic
+

+ Referência técnica comparativa construída a partir das docs oficiais públicas dos três providers (developers.openai.com, ai.google.dev, docs.claude.com) em 2026-06-10. Itens marcados UNVERIFIED precisam re-verificação antes de citar publicamente. +

+
+
+
Fontes
+
Docs oficiais dos três providers
+
developers.openai.com · ai.google.dev · docs.claude.com · 2026-06-10
+
+ OpenAI + Gemini + Claude +
+
+
+
Navegação rápida
+ + + + +
+
+
+ + + diff --git a/references/agents_tools_best_guides/index.html b/references/agents_tools_best_guides/index.html new file mode 100644 index 0000000..cc9e2f6 --- /dev/null +++ b/references/agents_tools_best_guides/index.html @@ -0,0 +1,903 @@ + + + + + +Guia Completo de Agentes — Portal + + + + + + + + +
+
+
Guia Completo de Agentes Portal mestre · orquestração de agentes de IA
+
+ Verificado em 2026-06-25 + 23 guias + multi-provedor + +
+
+
+ +
+ + +
+ +
+

Guia Completo de Agentes — Portal

+

+ Porta de entrada única para construir sistemas de agentes de IA de forma + portável entre provedores. O portal organiza um núcleo de orquestração agnóstico + (arquitetura, estado, ferramentas, providers, operação), os guias de framework + (OpenAI Agents SDK, LangGraph, Google ADK), as referências de provedor + (OpenAI, Anthropic, Google) e os temas transversais — contexto, tokens, multimodal, paralelismo e + Agent Skills. Para IA e humanos: prosa em PT-BR, identificadores e código em inglês. +

+
+ 23 guias + OpenAI · Anthropic · Google + SOTA · verificado 2026-06-25 +
+
+ +
+

Sobre o portal

+

+ Este portal não repete o conteúdo dos guias: ele os relaciona. Cada tema profundo + (modelos, streaming, thinking, multimodal, paralelismo, tokens, skills) tem um guia dedicado; o + núcleo de orquestração define o vocabulário agnóstico (estado durável, projeções, + capability registry, handoff vs agent-as-tool) e aponta para esses guias em vez de duplicá-los. +

+
+ Como ler: comece por Por onde começar para escolher + uma trilha pelo seu perfil; use a Biblioteca (com busca) para localizar um + guia específico; e consulte a Matriz de navegação para ir direto do + tópico ao guia que o cobre. +
+
+ +
+

Por onde começar

+

Trilhas de leitura por perfil. Cada uma encadeia guias na ordem recomendada.

+ +

Iniciante em agentes

+
    +
  1. Entenda a tese operacional e os 4 planos aqui no portal.
  2. +
  3. Leia o futuro guia de arquitetura & orquestração (núcleo) para o vocabulário comum.
  4. +
  5. Escolha um provedor: Modelos OpenAI, Claude API ou Gemini Interactions API.
  6. +
  7. Aprenda a contar custo desde cedo: Contagem de tokens.
  8. +
+ +

Arquiteto de sistemas de agentes

+
    +
  1. Núcleo completo: arquitetura, estado/contexto/memória, ferramentas/MCP/RAG, providers/adapters, operação/segurança/evals.
  2. +
  3. Aprofunde estado longo: Contexto & compactação.
  4. +
  5. Decida a base de framework no comparativo e leia o guia de orquestração correspondente.
  6. +
+ +

Implementador por framework

+
    +
  1. OpenAI Agents SDK: referência da API + guia de orquestração no SDK.
  2. +
  3. LangGraph: referência (StateGraph/checkpointers/HITL) + guia de orquestração.
  4. +
  5. Google ADK: referência (1.x/2.0) + guia de orquestração.
  6. +
  7. Deep agents / long-horizon: DeepAgents.
  8. +
+ +

Operação & segurança

+
    +
  1. Futuro guia de operação, segurança & evals (núcleo): guardrails, tracing, ZDR, runbooks, threat model.
  2. +
  3. Padronize automações reutilizáveis com o futuro guia de Agent Skills.
  4. +
  5. Use a matriz para localizar a seção de segurança de cada framework.
  6. +
+
+ +
+

Mapa conceitual do super-guia

+

Três ideias atravessam todos os guias do núcleo. Entendê-las aqui torna o resto previsível.

+ +

Tese operacional: estado durável vs projeção vs execução

+

+ O segredo de um sistema de agentes portável é separar três coisas que os SDKs tendem a misturar: +

+
    +
  • Estado durável — um ledger canônico de itens tipados que você controla (mensagens, tool calls, resultados, reasoning, assets, decisões). É a fonte da verdade.
  • +
  • Projeção — o payload que cada provedor exige é uma visão derivada do ledger, não a verdade. Trocar de provedor = trocar a projeção, não perder o estado.
  • +
  • Execução — o loop de runtime (registrar → reduzir → projetar → chamar modelo/tool → reduzir de novo) é separado de ambos.
  • +
+
+ Por que importa: com essa separação, previous_response_id (OpenAI), + thread/checkpointer (LangGraph) ou session/state (ADK) viram projeções intercambiáveis do + mesmo ledger — e não três arquiteturas incompatíveis. O núcleo de estado detalha o contrato. +
+
+ +
+

Os 4 planos que não devem ser misturados

+

Toda decisão de design cai em um destes planos. Misturá-los é a causa mais comum de acoplamento.

+
+ + + + + + + +
PlanoPergunta que respondeOnde ler
1. ProtocoloComo o agente fala com tools/outros agentes? (MCP, A2A, function calling)Núcleo de ferramentas/MCP · paralelismo
2. AdapterComo o ledger vira o payload de cada provedor?Núcleo de providers · OpenAI · Claude · Gemini
3. CapabilitiesO que o agente sabe fazer? (tools, skills, RAG, multimodal)Núcleo de ferramentas · multimodal · guia de skills
4. Estado + observabilidadeO que aconteceu e como auditar/repetir?Núcleo de estado · tokens · contexto · operação
+
+ +
+

Qual base usar: Agents SDK, Responses, LangGraph, ADK ou Pydantic AI

+

+ Não há base única vencedora — há critérios. As três bases de framework são legítimas; o núcleo é + agnóstico e cada guia de orquestração mostra como mapear o blueprint comum à base escolhida. +

+
+ + + + + + + + +
BaseEscolha quando…Guia
OpenAI Agents SDKecossistema OpenAI; quer handoffs/guardrails/sessions/tracing prontos sobre a Responses API.guia_agents_sdk
OpenAI Responses API (direta)controle máximo do loop e do estado, sem framework por cima.guia_openai_modelos
LangGraphorquestração explícita em grafo, persistência durável (checkpointers) e HITL fino.guia_langgraph
Google ADKecossistema Google/Vertex; workflow agents e, no ADK 2.0, execução em grafo.guia_google_adk
Pydantic AIcamada de tipagem/evals/observabilidade complementar a qualquer base.Núcleo de providers
+
+ Sem bala de prata: o Agents SDK é uma base recomendada (forte no + ecossistema OpenAI), não a única. LangGraph e ADK são alternativas de primeira classe — use o + critério acima, não a moda. +
+
+ +
+

Mapa de decisões rápidas

+

Pergunta de projeto → resposta curta + onde ler em profundidade.

+
+ + + + + + + + + + + + +
PerguntaResposta curtaOnde ler
Onde guardo o histórico?No seu ledger canônico; o estado do provedor é projeção.Núcleo de estado · contexto
Como reduzo custo de prompt longo?Prompt caching + compactação rastreável + contar tokens.tokens · contexto · caching (Claude)
Várias tools ao mesmo tempo?Paralelize functions; cuidado com built-ins.paralelismo de tools
Conectar tools externas com segurança?MCP como fronteira formal (host/client/server).Núcleo de ferramentas/MCP
Ler PDF/imagem/planilha?Trate como asset com provenance; use o guia dedicado.multimodal
Crop/zoom/validação visual fina?Gating no runtime + code tool como lupa (visão nativa primeiro).agentic vision & code tools
Delegar para subagente?Handoff (transfere o turno) vs agent-as-tool (delega e retorna).Núcleo de arquitetura · guias de framework
Humano no loop (aprovação)?Contrato HITL agnóstico; cada framework tem o seu.Núcleo de ferramentas · LangGraph interrupt · ADK confirmations
Trocar de provedor sem reescrever tudo?Provider-switching contract + loss declaration.Núcleo de providers
+
+ +
+

Biblioteca de guias

+

+ Todos os guias, agrupados por trilha. Use a busca para filtrar por título ou escopo. Os guias do + núcleo de orquestração são novos e complementam os guias dedicados já existentes. +

+
+ + +
+

Nenhum guia corresponde à busca. Limpe o filtro para ver todos.

+
+ + + +
+

Núcleo de orquestração novo

+

Camada agnóstica e complementar: o vocabulário comum a todos os frameworks.

+ +
+ +
+

Frameworks de agentes

+

Referências de API publicadas, mais os guias de orquestração que mapeiam o blueprint do núcleo a cada base.

+
+ +
OpenAI Agents SDK
+

openai-agents: agentes, handoffs, guardrails (tripwire), sessions, tracing e integração com a Responses API.

+
FrameworkPythonopenai-agents 0.17.7
+ Abrir +
+ +
LangGraph
+

Orquestração baseada em grafo: StateGraph e reducers, checkpointers, human-in-the-loop (interrupt/Command), streaming tipado.

+
FrameworkPythonlanggraph 1.2.6 GA
+ Abrir +
+ +
Google ADK 1.x/2.0
+

Agent Development Kit: LlmAgent e workflow agents, tools/MCP/A2A, e o Workflow Runtime em grafo do ADK 2.0.

+
FrameworkPythonADK 2.0 GA · 2.3.0
+ Abrir +
+ +
DeepAgents
+

Harness de agentes profundos para tarefas long-horizon: planejamento, subagentes e ferramentas de longo alcance sobre LangGraph.

+
FrameworkPythondeepagents 0.6.12
+ Abrir +
+ +
Orquestração no Agents SDK
+

Como aplicar o blueprint do núcleo (capability registry, microcontexto, handoff vs delegação, ledger externo) usando o OpenAI Agents SDK como base. Complementa o guia do Agents SDK.

+
FrameworkOrquestraçãoPublicado
+ Abrir +
+ +
Orquestração em LangGraph
+

StateGraph/reducers como ledger tipado, checkpointers como estado durável, interrupt/Command como HITL, e supervisor/swarm vs handoff do núcleo. Complementa o guia do LangGraph.

+
FrameworkOrquestraçãoPublicado
+ Abrir +
+ +
Orquestração no Google ADK
+

Aplicar o blueprint do núcleo no ADK 1.x e 2.0: workflow agents, graph-based workflows, sessions/state como ledger, callbacks como guardrails, migração 1.x→2.0. Complementa o guia do Google ADK.

+
FrameworkOrquestraçãoPublicado
+ Abrir +
+
+
+ +
+

Providers & modelos

+

Referências de API por provedor de modelo.

+ +
+ +
+

Contexto & tokens

+

Temas transversais de janela de contexto, custo e estratégias de compactação.

+ +
+ +
+

Multimodal & paralelismo

+

Entrada multimodal, visão agentic com code tools e execução paralela de ferramentas entre provedores.

+ +
+ +
+

Skills

+

Padrão de Agent Skills portável (autoria, ativação, governança).

+ +
+ +
+

Operação & segurança

+

Camada de operação agnóstica (consolidada no núcleo). Veja também a seção do núcleo acima.

+ +
+ +
+

Matriz de navegação — tópico → guia

+

Vá direto do que você precisa ao guia que cobre. Cada tópico aponta para o guia dedicado e, quando aplicável, para o capítulo do núcleo agnóstico.

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
TópicoGuia(s)
Seleção de modelo & reasoningOpenAI · Claude · Gemini
StreamingOpenAI · Claude · Gemini · LangGraph
Tool / function callingparalelismo · Agents SDK · núcleo de ferramentas
MCP (Model Context Protocol)núcleo de ferramentas · Claude · ADK · DeepAgents
Thinking / reasoning preservationClaude · Gemini · OpenAI · núcleo de estado
Prompt cachingClaude · OpenAI · contexto
Contexto longo & compactaçãocontexto · núcleo de estado
Contagem de tokens / custotokens · operação
Multimodal (imagem/PDF)multimodal · núcleo de ferramentas
Agentic vision (crop/zoom/render) & code/shell toolsagentic vision & code tools · multimodal
Tool Search / defer_loading / seleção dinâmica de toolsagentic vision & code tools · Agents SDK · Claude
Schemas de custom functions (descriptions, strict)agentic vision & code tools · núcleo de ferramentas
File inputs sem provider storage / ZDR · hosted executionfile inputs (ZDR) · multimodal · operação
Handoff / multi-agentenúcleo de arquitetura · Agents SDK · LangGraph · ADK
HITL (human-in-the-loop)LangGraph · ADK · DeepAgents · núcleo de ferramentas
Persistência / checkpointsLangGraph · núcleo de estado · operação
Guardrails / segurançaAgents SDK · ADK · operação
Tracing / observabilidadeAgents SDK · ADK · operação
Agent Skills (autoria)guia de skills
RAGnúcleo de ferramentas (conteúdo novo)
Deep research / long-horizonDeepAgents · Gemini · OpenAI
+
+ +
+

As 6 garantias do super-guia

+
    +
  • ☑ Fonte oficial: todo fato perecível (modelos, parâmetros, versões) é verificado contra a doc oficial e consolidado numa folha de fatos única.
  • +
  • ☑ SOTA: modelos e SDKs sempre na versão mais recente — nunca IDs antigos ou deprecados.
  • +
  • ☑ Agnóstico por padrão: o núcleo não hardcoda provedor; o específico de framework vive em guias próprios.
  • +
  • ☑ Sem duplicação: cada tema tem um dono; os demais guias fazem cross-link em vez de repetir.
  • +
  • ☑ Para IA e humanos: prosa PT-BR + referência consultável; identificadores e código em inglês.
  • +
  • ☑ Acessível e portável: tema claro/escuro, navegação por teclado, HTML auto-contido sem dependências externas.
  • +
+
+ +
+

Fontes oficiais & verificação

+

+ Os fatos perecíveis citados nos cards (versões de SDK, IDs de modelo, status GA) vêm da folha de + fatos verificada do super-guia (2026-06-10), conferida contra as docs oficiais de cada provedor. +

+
+ + + + + + + + + + +
Provedor / projetoDoc oficial
OpenAIdevelopers.openai.com
Anthropic (Claude)platform.claude.com/docs
Google (Gemini)ai.google.dev/gemini-api/docs
OpenAI Agents SDKopenai.github.io/openai-agents-python
LangGraphdocs.langchain.com
Google ADKadk.dev
Model Context Protocolmodelcontextprotocol.io
+

+ Legenda dos selos dos cards: Núcleo/Framework/Provider/Transversal/Skills trilha · + versão/GA · Publicado fato verificado 2026-06-10. +

+
+ +
+
+ +
+
+
+
Guia Completo de Agentes Portal mestre
+

+ Portal de navegação para os guias de orquestração de agentes de IA, verificado contra as docs + oficiais em 2026-06-11 (versões de libs reconferidas em 2026-06-19). Os guias são auto-contidos e podem ser lidos isoladamente. +

+
+
+
Crédito de produção
+
Construído por time de subagentes Claude Opus 4.7 (xhigh)
+
revisão e montagem pelo orquestrador · 2026-05-25
+
varredura de atualização (versões, breaking changes, novo guia) · 2026-06-10
+
delta sweep (changelogs OpenAI/Anthropic/Google, MCP draft, agentes Gemini, versões PyPI/npm) · 2026-06-11
+
micro-sweep de versões (anthropic 0.109.2, langgraph 1.2.5, deepagents 0.6.10 — só patches) · 2026-06-16
+
SOTA sweep — versões (openai-agents 0.17.6, langgraph 1.2.6, deepagents 0.6.11, google-adk 2.3.0, google-genai 2.9.0, anthropic 0.111.0) + caveat Vertex/Interactions no agentic-vision e no guia de Interactions · 2026-06-19
+
freshness sweep — Gemini Interactions API GA (jun/2026); versões (openai-agents 0.17.7, deepagents 0.6.12, anthropic 0.112.0, google-genai 2.10.0, pydantic-ai 2.0.0, ADK 1.x→1.36.0); correção Sonnet 4.6 saída 128k; Fable 5 GA porém indisponível no momento · 2026-06-25
+
+ 23 guias + multi-provedor +
+
+
+
Navegação rápida
+ + +
+
+
+ + + + + + + From f1e8e694717812f9936303e49242400b92c2748f Mon Sep 17 00:00:00 2001 From: Rafael Bittencourt Date: Mon, 29 Jun 2026 20:58:31 -0300 Subject: [PATCH 03/16] docs(guias-agentes): varredura SOTA 2026-06-29 (changelogs oficiais reverificados) - Versoes para latest: anthropic 0.113.0, pydantic-ai 2.1.0, openai 2.44.0/6.45.0, langchain-core 1.4.8, langchain-google-genai 4.2.6 - Calendario de sunsets por provedor: gpt-image-1-mini/1.5 2026-12-01, Assistants API 2026-08-26, Veo 2/3 2026-06-30, Imagen 4 2026-08-17, Opus 4.1 2026-08-05 - Breaking changes: sampling 400 em Opus 4.7+/Fable 5, tokenizer ~30%, Interactions Beta->GA, default model gpt-5.4-mini (Agents SDK) e gemini-3-flash-preview (ADK) - Correcoes: mito "pydantic-ai sem 1.x" (existiu 1.0.0->1.99.0), escopo do tokenizer - Datas de verificacao -> 2026-06-29 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../guia_claude_api.html | 28 +++++++++++++------ .../guia_deepagents.html | 14 +++++----- .../guia_ferramentas_mcp_rag.html | 6 ++-- .../guia_gemini_interactions_api.html | 14 +++++----- .../guia_langgraph.html | 15 ++++++---- .../guia_langgraph_orquestracao.html | 6 ++-- .../guia_multimodal.html | 2 +- .../guia_openai_modelos.html | 15 +++++----- .../guia_operacao_seguranca_evals.html | 6 +++- ...lelismo_tools_openai_gemini_anthropic.html | 12 ++++---- .../guia_providers_adapters.html | 17 +++++------ .../agents_tools_best_guides/guia_skills.html | 6 ++-- .../guia_token_counting.html | 8 +++--- .../agents_tools_best_guides/index.html | 9 +++--- 14 files changed, 91 insertions(+), 67 deletions(-) diff --git a/references/agents_tools_best_guides/guia_claude_api.html b/references/agents_tools_best_guides/guia_claude_api.html index 544bed8..cf9bf85 100644 --- a/references/agents_tools_best_guides/guia_claude_api.html +++ b/references/agents_tools_best_guides/guia_claude_api.html @@ -4,8 +4,8 @@ Guia Claude API (Anthropic) — Referência completa · Opus 4.8 · Sonnet 4.6 · Haiku 4.5 - - + + + + + + +
+
+
Streaming Durável & Resumível arquitetura transversal · super-guia de agentes
+
+ Verificado em 2026-07-09 + Arquitetura · v1 + OpenAI · Anthropic · Gemini + Resume = camada 2 + +
+
+
+ +
+ + +
+ +
+

Streaming Durável & Resumível

+

+ Como construir a resposta agêntica que sobrevive a fechar a aba — o padrão + ChatGPT/Claude/Gemini: o usuário manda o prompt, vê eventos internos streamando; fecha e volta; e + reencontra o estado exato (ainda processando → status ao vivo; 500 chars já streamados → + carrega os 500 e continua o streaming; respondido → tudo carregado + data/hora do + primeiro token real). A tese central: isso é um problema da camada backend↔frontend + (event store + replay por cursor + execução desacoplada) — não do WebSocket com o + provider. O guia cobre as duas camadas, HTTP vs WS, o modelo de entidades/FSM, idempotência com tool + ledger, failover cross-provider e os padrões de maturidade M0–M3. Não é taxativo: mostra os caminhos + SOTA e quando cada um vale. +

+
+ Arquitetura · v1 + OpenAI · Anthropic · Gemini + SOTA · verificado 2026-07-09 + 3 rodadas adversariais +
+
+ +
+

Sobre este guia

+

+ Este é um guia para IA e humanos, transversal aos três providers e às duas pontas + (backend e frontend). Ele responde à pergunta que os guias de capacidade não respondem: como garantir + que uma geração agêntica em andamento não se perde quando o cliente desconecta — e como retomá-la + exatamente de onde parou. A superfície de API de cada provider tem dono próprio na coleção e é + cross-linkada, não duplicada: o WebSocket Mode e a Responses API em detalhe são do + guia OpenAI · §12.2; a matriz de + capacidades por provider é do guia Providers & + Adapters; compaction de contexto é do + guia de Compactação; ZDR e ingestão sem + provider storage são do guia File Inputs; + envelope local como fonte de verdade é do + guia Estado, Contexto & Memória. +

+
+ Tese: a durabilidade que o usuário percebe vive inteiramente na camada 2 + (backend↔frontend): execução desacoplada do socket + event log durável com seq + replay por + cursor + snapshot. A escolha de transporte com o provider (camada 1: SSE ou WebSocket) muda + latência, não muda se o usuário consegue voltar. Nenhum transporte fornece durabilidade, + idempotência ou exactly-once — isso é sempre trabalho seu. +
+
+ Como este guia foi validado: fatos perecíveis conferidos na documentação oficial em + 2026-07-09 e o desenho submetido a três rodadas adversariais (dois + modelos frontier externos + reconciliação na fonte primária). As correções que sobreviveram estão + incorporadas; o que não pôde ser confirmado está marcado UNVERIFIED. +
+
+ +
+

Fontes & verificação

+
+ + + + + + + + + + + + + + + +
TemaRecurso oficial
OpenAI — WebSocket Mode (Responses)developers.openai.com/api/docs/guides/websocket-mode
OpenAI — Streaming de Responses (SSE)developers.openai.com/api/docs/guides/streaming-responses
OpenAI — Background modedevelopers.openai.com/api/docs/guides/background
OpenAI — Deployment checklist (HTTP vs WS)developers.openai.com/api/docs/guides/deployment-checklist
OpenAI — phase e reasoningdevelopers.openai.com/api/docs/guides/reasoning
OpenAI — Compactiondevelopers.openai.com/api/docs/guides/compaction
OpenAI — Data controls / ZDRdevelopers.openai.com/api/docs/guides/your-data
Anthropic — Streaming Messages (SSE)platform.claude.com/docs/en/build-with-claude/streaming
Gemini — generateContent streamingai.google.dev/gemini-api/docs/text-generation
Gemini — Live API (WebSocket)ai.google.dev/api/live
Web — Server-Sent Events / Last-Event-IDdeveloper.mozilla.org · Server-sent events
Redis — Streams (XADD/XREAD)redis.io/docs · Streams
+

+ Legenda: Verificado confirmado na doc oficial em 2026-07-09 · + Novo recurso recente · + UNVERIFIED não confirmado em URL oficial direta · + Evitar antipadrão. +

+
+ + +
+

Parte 1 — O problema e as duas camadas

+
+ +
+

1. O contrato de UX — os três estados do retorno

+

+ O usuário envia um prompt e a plataforma mostra o trabalho interno (tool calls, status de raciocínio, + deltas de texto). Ele fecha a aba, perde a rede ou troca de dispositivo. Ao voltar, o produto precisa + honrar um contrato de três estados: +

+
+ + + + + + +
Estado ao voltarO que o usuário vêMecanismo
Ainda processandoO status de trabalho interno atual, como se nunca tivesse saídoExecução desacoplada do socket + state record (running) + reattach ao stream
Parcialmente respondido (ex.: 500 chars streamados)Os 500 chars instantaneamente + o streaming continua do ponto exatoReplay do event log a partir do cursor + tail ao vivo (sem janela de perda — §8)
Respondido por completoA resposta inteira + data/hora do primeiro token real da respostaMaterialização durável + first_answer_text_delta_at (§9)
+
+ O que quebra o contrato: streaming preso ao request HTTP do cliente (a geração morre com a + conexão); histórico só persistido no fim (parcial se perde); "resume" que na verdade recomeça a geração + (custo dobrado + resposta diferente); e marcar completed um stream que foi truncado + quando o provider caiu — truncamento é incomplete, nunca completed. +
+
+ +
+

2. As duas camadas de transporte — a distinção que organiza tudo

+

+ Misturar as duas camadas é a fonte número um de decisões erradas ("vou usar WebSocket para ter resume"). + Elas são independentes e têm papéis diferentes: +

+
┌─────────────┐   CAMADA 1: backend ↔ PROVIDER          ┌──────────────┐
+│  FRONTEND   │   OpenAI: HTTP/SSE ou WS mode (opt-in)   │   PROVIDER   │
+│  (browser)  │   Anthropic: SSE · Gemini: SSE           │ OpenAI/Anthr/│
+└──────┬──────┘   (Gemini Live WS = realtime, Preview)   │   Gemini     │
+       │                                                 └──────▲───────┘
+       │ CAMADA 2: backend ↔ FRONTEND                           │
+       │ NOSSO SSE, resumível: replay por cursor                │
+       ▼ (Last-Event-ID) + tail ao vivo                         │
+┌───────────────────────────────────────────────────────────────────┐
+│                            BACKEND                                │
+│  ┌────────────┐   ┌───────────────────┐   ┌────────────────────┐  │
+│  │ Envelope   │   │ EXECUÇÃO           │   │ EVENT STORE        │  │
+│  │ LOCAL de   │──▶│ desacoplada do     │──▶│ durável: seq       │  │
+│  │ contexto   │   │ socket do cliente  │   │ monotônico + state │  │
+│  │ (store=off)│   │ (worker/fila)      │   │ + snapshot         │  │
+│  └────────────┘   └───────────────────┘   └────────────────────┘  │
+└───────────────────────────────────────────────────────────────────┘
+
    +
  • Camada 1 (backend↔provider): decide latência e custo de conexão. SSE ou + WebSocket, tanto faz para o resume do usuário. A responsabilidade que ela carrega para a durabilidade é uma + só: integridade — detectar truncamento quando o provider cai e nunca promover stream cortado + a completed.
  • +
  • Camada 2 (backend↔frontend): é onde vive TODO o contrato da §1. Event log com + seq, replay por cursor, execução desacoplada, snapshot, timestamps.
  • +
+
+ Regra de ouro: trocar WS↔SSE com o provider não muda se o usuário consegue retomar. + Se o seu plano de "resume" começa por "adotar o WebSocket mode", ele está atacando a camada errada. +
+
+ +
+

3. Transporte por provider (camada 1)

+
+ + + + + + + + + +
Provider / modoTransporteInput incrementalEstado server-sideResume nativoStatus
OpenAI Responses (SSE)HTTP + SSE (stream:true)Nãoprevious_response_id (só com store=true)nova requestGA
OpenAI Responses (WS mode)WebSocket wss://api.openai.com/v1/responsesSim — novos itens completos + previous_response_id via response.create (não deltas em voo)cache in-memory connection-local (compatível store=false/ZDR)não entre conexões: caiu/60 min → novo socket; sob store=false a cadeia se perde (prev_id=null + contexto completo ou compactado)público, sem rótulo beta
OpenAI backgroundHTTP (background:true + stream:true)Nãosim — cursor sequence_numbersim (starting_after), mas exige store=true (não-ZDR, ~10 min)GA
Anthropic MessagesHTTP + SSE puroNãonenhum (cliente reenvia histórico)—GA
Gemini generateContentHTTP + SSE (?alt=sse)Nãonenhum—GA
Gemini LiveWebSocket bidirecionalSim (texto, áudio e vídeo)sessão + handleSessionResumption (handle ~2h), GoAwayPreview · realtime
+
+ Leituras que importam: (1) o fallback cross-provider de texto é obrigatoriamente + HTTP/SSE — Anthropic e Gemini não têm WebSocket de texto em produção; (2) o Gemini Live + aceita texto, mas é Preview e orientado a realtime/native-audio — não é substituto do + generateContent para chat textual; (3) o WS mode da OpenAI é ZDR-ok justamente porque o cache é + in-memory da conexão — e por isso mesmo a reconexão não retoma nada: novo socket = nova + cadeia sob store=false. Detalhes de frames, erros e limites: guia OpenAI §12.2. +
+ +
+ +
+

4. HTTP(S) vs WebSocket — quando cada um é melhor

+

+ O ponto que o hype esconde: o caminho "normal" da Responses API é request/response e SSE sobre + HTTPS; o WS mode é wss:// (também TLS) e opt-in. A recomendação + oficial da OpenAI é condicional: "uma request/uma resposta → mantenha HTTP; agente longo/tool-heavy → + experimente WebSocket". A escolha não é segurança nem "moderno vs antigo" — é modelo de conexão: + request independente (+SSE) vs socket persistente. Em muitos cenários, HTTP(S)/SSE é a + escolha melhor — não um fallback de consolação: +

+
+ + + + + + + + + + + +
CenárioVencePor quê
Conversa curta/média (poucos tool round trips) — a maioria do tráfego de chatHTTP(S)/SSEO ganho do socket persistente não amortiza; 1 request = 1 resposta
Serverless / autoscaling (Cloud Run, Lambda, scale-to-zero)HTTP(S)/SSESocket persistente prende a instância e atrapalha scale-down/balanceamento
Atrás de proxies corporativos / LBs / API gatewaysHTTP(S)/SSETende a ser mais compatível com egress corporativo (upgrade WS às vezes bloqueado) — mas SSE também pode sofrer buffering/idle-timeout de proxy
Retry e observabilidade por requestHTTP(S)/SSECada request é independente (status code, trace, retry com backoff). Idempotência continua sendo sua responsabilidade nos dois
Simetria cross-provider (fallback Anthropic/Gemini)HTTP(S)/SSEAnthropic/Gemini texto são SSE-only — HTTP-first mantém um caminho de transporte (os adapters semânticos continuam distintos)
Execuções longas sem teto de conexãoHTTP(S)/SSEWS mode tem limite de 60 min/conexão (exige rollover); HTTP não herda esse teto — mas segue sujeito a timeouts de cliente/runtime/proxy/provider
Loop agêntico tool-heavy (muitos round trips) em worker de vida longaWS modeHTTP/2 + keep-alive já amortizam TCP/TLS; o ganho real do WS é o request state quente connection-local + envio só dos itens novos
Latência agregada em rollouts longosWS mode (a medir)"Até ~40%" citado pela OpenAI vale para 20+ tool calls — dado observado, não limiar; medir p95/p99 no seu workload
+
+ Framing recomendado: HTTP streaming é o baseline portátil da camada + backend→provider. WebSocket é uma capability opt-in quando conexão aquecida, continuação + incremental ou bidirecionalidade produz ganho medido. Nenhum dos dois fornece durabilidade, + idempotência ou execução exactly-once. Os números da tabela são pontos de partida para benchmark local, não + regras. +
+ +
+ + +
+

Parte 2 — Camada 2: durabilidade e resume

+

É aqui que o contrato da §1 é cumprido. Tudo desta parte independe do provider e do transporte da camada 1.

+
+ +
+

5. Os quatro pilares (todos necessários)

+
+ + + + + + + +
#PilarO que garanteSem ele
1Execução desacoplada do socket — a geração roda como trabalho de backend (worker/fila), nunca dentro do request HTTP do clienteCliente cai → geração continua e segue persistindoFechar a aba mata a geração
2Event log durável append-only — cada evento (delta, tool, status) gravado com seq monotônico e append atômicoFonte de verdade replayávelGaps, índice órfão, replay impossível (§7)
3Replay por cursor + tail — reconexão envia Last-Event-ID; backend reenvia de lá e emenda o ao-vivo sem janela de perdaResume real no meio do streamPoll-on-return (recarrega tudo, sem continuidade)
4Snapshot + materialização durável — texto acumulado com snapshot_seq + resultado final em storage durável (TTL do log ≠ retenção do resultado)"Voltar no dia seguinte" e carga instantâneaTTL expira e o resume vira 404
+
+ Invariante que amarra os pilares — commit-before-emit: nenhum evento é enviado ao browser + antes de estar commitado no event log. Se o cliente recebeu algo que não foi persistido, a promessa + de resume já quebrou (ele viu um delta que o replay não vai reproduzir). Corolários: buffers limitados e + backpressure/cancelamento quando o store não progride. +
+
+ +
+

6. Modelo de entidades e máquina de estados

+

+ Sem um modelo explícito, "resume" vira gambiarra sobre a tabela de mensagens. O modelo mínimo que + sustenta o contrato: +

+
conversation ── 1:N ── turn (comando do usuário; carrega idempotency_key)
+turn ────────── 1:N ── attempt (tentativa de geração; SÓ UMA ativa por vez)
+attempt ─────── 1:1 ── execution (o trabalho no worker; lease + fencing epoch)
+attempt ─────── 1:N ── subscription (conexões SSE de leitura; cursor É POR CONEXÃO)
+attempt ─────── 1:N ── event (append-only, seq monotônico, terminal_seq no fim)
+
    +
  • Estados do attempt: pending → running → {completed | failed | cancelled | timed_out | incomplete}. Estados terminais são imutáveis.
  • +
  • Transição terminal com CAS (compare-and-set por state_version): cancelled, timed_out e completed podem disputar a última escrita — só um vence, os demais falham o CAS e desistem.
  • +
  • cancel_requested ≠ cancelado: o pedido de cancelamento é uma flag; o estado cancelled só é gravado quando o executor confirma que parou (tools inclusive). Cancelamento de produto é end-to-end seu (UI→backend→executor→provider) — não dependa de evento de cancel do provider.
  • +
  • Completion barrier: o resultado materializado é gravado antes do evento terminal ser emitido. Quem vê completed no stream pode confiar que o GET da mensagem final já responde.
  • +
  • Truncamento é incomplete: se a conexão com o provider caiu no meio e não há como continuar, o attempt fecha como incomplete com o parcial preservado — nunca completed.
  • +
+
+ +
+

7. Event log: seq, atomicidade e Redis Streams

+

+ O evento normalizado é provider-neutro desde o dia 1 (mesmo com um provider só) — senão o + frontend fossiliza em eventos idiossincráticos e o replayer vira um "tradutor histórico" impossível quando + entrar o segundo provider. Campos comuns + payload específico versionado: +

+
{
+  "event_id": "evt_01J...",          // id único (dedupe)
+  "attempt_id": "att_01J...",
+  "seq": 142,                         // monotônico POR ATTEMPT — o cursor do replay
+  "type": "answer.delta",             // status.* | reasoning.* | tool.* | answer.* | terminal.*
+  "item_id": "msg_abc",               // correlaciona deltas ao item/mensagem de origem
+  "channel": "answer",                // answer | reasoning | tool | status
+  "delta_index": 17,                  // ordem dentro do item
+  "schema_version": 3,
+  "provider_event_received_at": "2026-07-09T18:22:31.114Z",
+  "committed_at": "2026-07-09T18:22:31.118Z",
+  "payload": { "text": "…" }          // shape específico do provider/versão fica AQUI
+}
+

7.1 Atomicidade — onde o desenho ingênuo quebra

+
    +
  • Append em múltiplos comandos soltos (ex.: grava índice, depois o evento) cria: índice apontando para evento inexistente; seq duplicado/fora de ordem com 2+ publishers; completed gravado antes do último delta.
  • +
  • Exigências: append atômico (Lua/Redis Function ou MULTI/EXEC — pipeline sozinho NÃO é atômico), INCR atômico do seq, e single-writer por attempt com lease + fencing epoch (§16) validado em cada append.
  • +
  • Dedupe no ingresso, não só no cliente: provider/SDK pode reenviar um delta e cada cópia ganharia um seq novo. Chave de dedupe: id do provider quando existir, senão (attempt, item, tipo, delta_index) + hash do payload.
  • +
+

7.2 Redis Streams é o primitive certo — com limites declarados

+

+ XADD dá append atômico com ID monotônico; XRANGE/XREAD dão replay + + tail nativos; MAXLEN/MINID dão trimming controlado. É o upgrade natural sobre + estruturas HASH+ZSET artesanais. Mas ele não: deduplica produtor, atomiza + Redis+Postgres numa transação só (use outbox/projetor quando houver dois stores), nem + impede perda por trimming/failover (declare o RPO). E consumer groups distribuem trabalho entre + workers — não são broadcast para browsers; para leitores SSE use XREAD simples por + conexão, cada um com seu cursor. +

+
# Append atômico (produtor único por attempt, fencing via epoch)
+# XADD já retorna o ID monotônico — use-o como seq do evento
+event_id = await redis.xadd(
+    f"attempt:{attempt_id}:events",
+    {"json": event_json, "epoch": str(fencing_epoch)},
+    maxlen=50_000, approximate=True,
+)
+
+ +
+

8. Replay, tail e o protocolo do cursor

+

8.1 Fechando a janela replay→tail

+

+ O bug clássico do resume: o backend faz replay do histórico e depois assina o pub/sub — e o evento + seq=106 gravado entre as duas operações se perde para sempre naquela conexão. Duas soluções + corretas: +

+
    +
  • XREAD BLOCK desde o cursor (Redis Streams): replay e tail são a MESMA + operação — leia de last_id em diante; quando o histórico acaba, a leitura bloqueia esperando o + próximo XADD. Não há janela.
  • +
  • Subscribe-before-replay (se pub/sub separado): assine o live primeiro, bufferize, + faça o replay até o high-watermark e então drene o buffer com dedupe por seq.
  • +
+
# FastAPI — endpoint SSE com replay + tail SEM janela (Redis Streams)
+@router.get("/attempts/{attempt_id}/stream")
+async def stream(attempt_id: str, request: Request):
+    cursor = request.headers.get("Last-Event-ID") or "0-0"
+    # autorização REAL aqui: o cursor não é credencial (§17)
+    async def gen():
+        cur = cursor
+        while True:
+            batch = await redis.xread({f"attempt:{attempt_id}:events": cur},
+                                      block=15_000, count=128)
+            if not batch:
+                yield ": keepalive\n\n"            # heartbeat p/ proxies
+                continue
+            for _, entries in batch:
+                for entry_id, fields in entries:
+                    cur = entry_id
+                    yield f"id: {entry_id}\nevent: message\ndata: {fields['json']}\n\n"
+                    if is_terminal(fields):        # terminal_seq encerra o stream
+                        return
+    return StreamingResponse(gen(), media_type="text/event-stream",
+        headers={"Cache-Control": "no-store", "X-Accel-Buffering": "no"})
+

8.2 Protocolo do cursor (o que o backend responde)

+
+ + + + + + + +
Cursor recebidoResposta
Válido e dentro do logReplay de > cursor + tail
Anterior ao trimming/TTL (expirado)410 Gone → cliente descarta estado, pega o snapshot (com snapshot_seq) e reconecta com Last-Event-ID = snapshot_seq
Futuro/impossível (bug ou attempt trocado)409 Conflict → reset igual ao 410
Sem cursor (primeira conexão)Snapshot + tail de > snapshot_seq
+
    +
  • Semântica de entrega é at-least-once: o cliente salva o cursor só depois de aplicar o evento, e o reducer é idempotente por seq (reaplicar o mesmo evento é no-op).
  • +
  • Snapshot com watermark: todo snapshot carrega snapshot_seq, attempt_id e reducer_version — sem isso não há como saber onde o tail começa. Tail começa estritamente em > snapshot_seq.
  • +
  • Cursor é por conexão, não por conversa: duas abas abertas têm cursores independentes. Nunca guarde "último seq entregue" global server-side — isso fura um dos clientes.
  • +
  • TTL: estenda o TTL do log ao completar e materialize o resultado final em storage durável — o contrato "voltar no dia seguinte" não pode depender do TTL do log de deltas.
  • +
+
+ +
+

9. Timestamps — "primeiro token real" são DOIS carimbos

+

+ Com modelos reasoning-first, o primeiro evento visível costuma ser um resumo de raciocínio ou o início de + um tool — não o texto da resposta. Um único timestamp mistura dois conceitos: +

+
+ + + + + + + +
CarimboO que marcaUso
first_presentable_event_committed_at1º evento apresentável commitado (reasoning summary, tool start…)"O agente começou a trabalhar às…" · TTFB percebido
first_answer_text_delta_at1º delta do texto final (answer channel)"Respondido às…" — o carimbo do contrato da §1
provider_event_received_at / committed_atRecebido do provider vs commitado no log (por evento)Latência interna, debugging de replay
first_rendered_at (telemetria do cliente)1º render REAL na telaMétricas de UX (um evento persistido sem cliente conectado não foi "visto")
+
    +
  • Autoridade do carimbo: o backend, no momento do commit (quando o evento recebe seq). Nunca o clock do frontend; nunca o response.created do provider (é ACK — mediria latência falsamente baixa). Derive os agregados como min(committed_at) filtrado por tipo. UTC para instantes; clock monotônico para durações.
  • +
  • Classificar "answer" na OpenAI (semântica correta): phase (commentary/final_answer) rotula mensagens do assistente — não vem nos eventos de delta. response.output_text.delta traz item_id + índices; o normalizador correlaciona item_id → mensagem dona para saber a phase. Um delta de texto pode ser commentary (preâmbulo de tool). E no replay manual de histórico (envelope local), preserve o phase original de cada mensagem — a doc oficial avisa que perder o phase faz preâmbulo virar "resposta final" e induz early-stopping.
  • +
+ +
+ +
+

10. Idempotência, retry e tool ledger

+
    +
  • Idempotency key no comando que cria o turno: o POST inicial pode sofrer timeout com o turno já criado — sem a key, o retry do cliente cria um turno duplicado (e paga duas gerações).
  • +
  • Fencing por attempt: um attempt ativo por conversa; criar o segundo exige finalizar o primeiro (CAS).
  • +
  • Critério de retry silencioso — as TRÊS condições: (a) zero side-effects (nenhum tool com efeito externo executado ou em estado ambíguo), (b) zero conteúdo user-visible (inclui reasoning summary, se exibido), (c) zero tool call disparado. Um tool call pode ocorrer antes do primeiro delta de texto — o critério ingênuo "zero deltas visíveis" reexecutaria o tool e duplicaria o side-effect.
  • +
  • Se qualquer condição falhou: finalize o attempt como failed/incomplete com o parcial preservado e crie nova tentativa explícita (nova bolha, retry_of apontando para a anterior) — não uma "continuação" invisível.
  • +
+

10.1 Tool ledger — o caso outcome_unknown

+

+ Todo tool com side-effect externo passa por um ledger por invocação: + prepared → running → {succeeded | failed | outcome_unknown}. O estado que separa produção + de protótipo é o outcome_unknown: o efeito externo pode ter ocorrido + e o ACK se perdeu (timeout, crash entre o side-effect e a persistência). Nunca re-execute um + outcome_unknown automaticamente — reconcilie (consulte o sistema alvo) ou compense, e use + idempotency key na própria chamada externa sempre que o alvo suportar. +

+
+ +
+

11. Edge cases que quebram o replay ingênuo

+
+ + + + + + + + + + + +
#Edge caseCorreção
1UTF-8/grapheme: fatiar "500 chars" por byte offset corta surrogate pair/combining mark → �Resume é pelo event log, nunca por offset de bytes; preview fatiado por grapheme no cliente (Intl.Segmenter) ou snapshot já segmentado
2Tool-call em deltas de JSON: reconectar no meio exige TODOS os deltas do mesmo tool_call_id para o JSON fecharSnapshot dos args acumulados por tool antes do tail, ou replay desde o início do item
3Interleaving reasoning↔answer: fases não são blocos rígidosCada delta carrega (item_id, channel, delta_index); o reducer reaplica por item
4Gaps/out-of-order no seq (100, 101, 103…)Append atômico + single-writer com fencing (§7); cliente trata gap como reset (§8.2)
5Duplicatas na reconexãoReducer idempotente por seq no cliente + dedupe no ingresso no backend
6TTL expira no meio410 Gone + snapshot/reset; materialização durável do final; TTL estendido ao completar
7Schema de ontem ≠ parser de hojeschema_version por evento + upcasters; versione também o reducer/snapshot (reducer_version)
8Duas abas/dispositivos simultâneosCursor por conexão (§8.2); ambos os leitores são independentes
+
+ + +
+

Parte 3 — Camada 1: transporte com o provider

+
+ +
+

12. OpenAI Responses — SSE, WS mode, background e compaction

+

+ A superfície detalhada (frames, erros, exemplos) é do + guia OpenAI §12.2. O que importa para a + arquitetura de durabilidade: +

+
    +
  • SSE (stream:true) é o caminho default. Eventos tipados (response.output_text.delta, tool events, response.completed) — normalize e persista cada um com seq próprio.
  • +
  • WS mode (wss://api.openai.com/v1/responses): público, sem rótulo beta. Compatível com store=false/ZDR — o cache do último response é in-memory da conexão. Sem multiplexação (1 response em voo por conexão; use pool para paralelismo). Limite de 60 min/conexão. Continuação entre turnos: novo response.create com itens novos completos + previous_response_id. Reconexão = novo socket + nova cadeia sob store=false (prev_id=null + contexto completo, ou a janela compactada do /responses/compact). Erros a tratar: previous_response_not_found, websocket_connection_limit_reached. Não há evento de cancel — cancelar = fechar o socket (e o SEU cancelamento end-to-end cuida do resto). Verificado
  • +
  • Requisito de SDK: o WS mode não exige versão específica — o exemplo oficial usa websocket-client puro e o helper responses.connect() existe no SDK Python desde antes da série 2.45 (2.45.x é sobre os types do GPT-5.6, não sobre o transporte). Verificado
  • +
  • Background mode (background:true + stream:true): resumível por starting_after=<sequence_number>, mas exige store=true (retém ~10 min; não-ZDR). Sob ZDR/store=false, a durabilidade vem do SEU event store — cuidado com o "compliance drift" de alguém ligar background "porque resolve resume". Verificado
  • +
  • Compaction — dois mecanismos, ambos ZDR-friendly: o endpoint standalone /responses/compact (stateless) e context_management.compact_threshold dentro do /responses. Use a janela compactada como base do input após reset de cadeia no WS. Deep dive: guia de Compactação.
  • +
+
+ WebSocket Mode não fornece resume de UX. Ele otimiza a conversa backend↔OpenAI dentro de + uma conexão. O usuário que fechou a aba é atendido pela camada 2 (§5–§11) — com WS ou sem WS. +
+ +
+ +
+

13. Anthropic & Gemini — SSE-only no texto

+
    +
  • Anthropic Messages: SSE puro, sem WebSocket, sem estado server-side — o cliente reenvia o histórico completo a cada turno (o que casa naturalmente com envelope local). Eventos: message_start, content_block_start/delta/stop, message_delta, message_stop, ping, error. Deltas de tool input chegam como input_json_delta (JSON parcial — edge case §11.2).
  • +
  • Gemini generateContent: HTTP + SSE (?alt=sse), sem estado server-side. É o caminho de produção para chat de texto.
  • +
  • Gemini Live: WebSocket bidirecional com session resumption (handle ~2h) e GoAway — aceita texto, áudio e vídeo, mas é Preview, orientado a realtime/native-audio. Não é o substituto do generateContent para chat textual, e não entra na cadeia de fallback de texto.
  • +
+
+ Consequência arquitetural: como o fallback de texto é SSE/HTTP em todos os providers, o + seu TransportSelector (§14) tem exatamente um transporte especial (OpenAI WS) e um baseline + universal (HTTP/SSE). Isso é um argumento a favor de construir o baseline primeiro e plugar o WS depois. +
+ +
+ +
+

14. Failover cross-provider = nova tentativa

+
    +
  • Separe dois papéis que costumam ser misturados: o TransportSelector escolhe COMO falar com o MESMO provider (WS→SSE dentro da OpenAI: decisão de transporte, invisível ao produto). O ProviderRouter troca DE provider (OpenAI→Anthropic: mudança de semântica, compliance e tentativa). Interfaces distintas, políticas distintas.
  • +
  • Reasoning não é portável: blobs de raciocínio (ex.: reasoning.encrypted_content) são do provider de origem. No failover, descarte-os; texto e resultados de tools confirmados atravessam.
  • +
  • Failover mid-flight nunca é continuidade invisível: mesmo com o mesmo texto+tools, o novo modelo responde diferente. Feche o attempt como incomplete, preserve o parcial e abra nova tentativa marcada (retry_of/supersedes) — o usuário vê uma nova bolha, não um Frankenstein "texto A + continuação B".
  • +
  • Input do failover: o input imutável da tentativa original (envelope local) + tool results confirmados no ledger — nunca tools em outcome_unknown.
  • +
  • Capability/compliance matrix por provider (o que suporta store=false, quais tools built-in existem, limites) mora no guia Providers & Adapters — o router lê essa matriz para decidir se o failover é elegível.
  • +
+
+ + +
+

Parte 4 — Frontend

+
+ +
+

15. EventSource vs fetch-stream, reconexão e render

+
+ + + + + + + + + +
EventSourcefetch + ReadableStream
Método/corpoSó GET, sem bodyQualquer método, com body (POST do prompt no mesmo request)
Headers/authSem headers custom (cookie/URL apenas)Headers livres (Authorization, etc.)
Last-Event-IDAutomático na reconexãoManual — você guarda o cursor e envia no header
ReconexãoAutomática (com retry:)Manual — backoff exponencial + jitter por sua conta
Cancelamentoclose()AbortController (cancela o request de verdade)
Parser SSENativoSeu — e precisa estar correto (abaixo)
+
    +
  • Parser SSE correto (se for fetch): chunks chegam em fronteiras arbitrárias — bufferize até \n\n; decodifique com TextDecoder(..., {stream:true}) (UTF-8 incremental — nunca decodifique chunk isolado); suporte múltiplas linhas data: por evento; trate id:, event: e os keepalives :.
  • +
  • Ciclo do cursor: aplica evento → salva cursor (nessa ordem: at-least-once, §8.2). Reconexão em visibilitychange/online/erro com backoff + jitter.
  • +
  • Preview por grapheme: qualquer corte de texto para exibição usa Intl.Segmenter — nunca slice() de bytes/UTF-16 no meio de emoji/acento.
  • +
+
// Reducer idempotente + cursor pós-aplicação (esqueleto)
+const state = { cursor: localStorage.getItem(k) ?? "0-0", items: new Map() };
+function apply(ev: NormalizedEvent) {
+  if (ev.seq <= state.lastSeqApplied?.get(ev.item_id + ev.channel)) return; // no-op em duplicata
+  reduce(state, ev);                       // por (item_id, channel, delta_index)
+  state.cursor = ev.seq_id;                // só DEPOIS de aplicar
+  localStorage.setItem(k, state.cursor);
+}
+
+ + +
+

Parte 5 — Operação

+
+ +
+

16. Executor durável — sobreviver a crash e deploy

+

+ Uma task assíncrona em memória (asyncio/goroutine) desacopla a geração do socket do cliente — resolve o + "fechei a aba". Mas ela morre com o processo: crash, OOM, deploy/rollout. Para o contrato + completo, a execução precisa ser retomável por outro worker: +

+
    +
  • Enqueue transacional: criar o attempt e enfileirar o job na mesma transação (outbox se fila externa).
  • +
  • Lease + heartbeat: o worker renova a lease do attempt; lease expirada = attempt órfão.
  • +
  • Fencing epoch monotônico: a cada takeover, o epoch incrementa; TODO append/tool-claim/transição terminal valida o epoch — o worker-zumbi da lease anterior escreve e falha (attempt_id sozinho não o barra).
  • +
  • Recovery scan / orphan reaper: processo que encontra attempts órfãos e decide: retomar (se o modelo de execução permitir re-drive), ou fechar como incomplete com o parcial (mais comum com LLM streaming, já que o stream do provider morreu com o worker).
  • +
  • Quando usar um engine pronto: Temporal/DBOS valem quando há tools com side-effects reais, retries idempotentes e fluxos longos que DEVEM sobreviver a deploy. Para chat sem side-effects críticos, fila + leases + fencing caseiros bastam. Deep dive de engines: guia Arquitetura & Orquestração.
  • +
+
+ +
+

17. Segurança & privacidade

+
    +
  • Cursor não é autorização. Cada subscribe/replay/cancel revalida: o attempt pertence ao usuário/tenant? (BOLA/IDOR clássico em endpoints de stream, que costumam escapar do middleware padrão.)
  • +
  • Isolamento de tenant nas chaves do event store (prefixo/tenant) e nos canais.
  • +
  • O event store local NÃO é "ZDR". store=false no provider tira a retenção DE LÁ; o seu Redis/Postgres agora retém deltas, tool args e reasoning summaries — que podem conter PHI/segredos. Política própria: redaction no ingresso, criptografia, TTLs separados (log de deltas ≠ resultado materializado), erasure a pedido. Ver File Inputs sem Provider Storage e Operação, Segurança & Evals.
  • +
  • Rate limit de reconexão (um cliente em loop de reconnect é um DoS barato) + limite de replay por request (paginação).
  • +
  • Backpressure: coalescing de deltas (agregue deltas minúsculos antes de emitir), buffers limitados por conexão, quotas por attempt (eventos/bytes/tokens/custo).
  • +
+
+ +
+

18. Observabilidade & SLOs

+
    +
  • Latência por fase: TTFT dos dois carimbos (§9), persist latency (provider_event_received_at → committed_at), replay lag na reconexão.
  • +
  • Saúde do log: gaps de seq detectados, taxa de dedupe no ingresso, attempts órfãos, tools em outcome_unknown, taxa de 410 Gone (cursores expirados = TTL curto demais).
  • +
  • Property tests que valem ouro: (1) replay == live view — reconstruir do log dá exatamente o que o cliente ao vivo viu; (2) terminal único e imutável; (3) writer com epoch obsoleto é rejeitado; (4) reconexão em ponto arbitrário nunca perde nem duplica evento.
  • +
  • Benchmark HTTP vs WS honesto: conexão fria vs quente, RTT, concorrência, bytes reenviados por turno, custo de FDs/memória — antes de adotar o WS mode por causa do "até ~40%".
  • +
+
+ +
+

19. Alternativas SOTA — quando cada uma é melhor

+
+ + + + + + + + +
PadrãoQuando é MELHORTrade-off / limite
Redis Streams (XADD/XREAD)O primitive certo para o event log da camada 2: append atômico, IDs monotônicos, replay+tail nativos (XREAD BLOCK fecha a janela §8.1), trimming controladoNão deduplica produtor; não atomiza Redis+SQL (outbox); trimming/failover = declarar RPO; consumer groups ≠ broadcast
Temporal / DBOS (durable execution)Execução que DEVE sobreviver a crash/deploy; tools com side-effects e retry idempotente; cancel/pause robustosPeso operacional; overkill para chat curto sem side-effects. Não substitui o SSE da camada 2
LangGraph checkpointerRetomar o ESTADO do agente (grafo, memória, tool state) entre turnos/crashesCheckpointa execução — não entrega stream resumível ao browser; complementa, não substitui
Vercel AI SDK resumable streamsStack Next.js/Edge — resume de UX "80% pronto" no ecossistemaFora de Next/Edge vira reimplementação; use como referência conceitual
WebTransport / HTTP3Altíssima interatividade, multiplex real, cliente customTroca o cano, não cria durabilidade; suporte/infra ainda irregulares — SSE/HTTP2 segue o confiável para texto
+
+ +
+

20. Padrões de maturidade M0–M3 (avalie o seu sistema)

+
+ + + + + + + +
NívelComportamento ao fechar/voltarComponentes presentesGap para subir
M0 — stream preso ao requestFechar a aba mata a geração; parcial se perdeSSE direto do handler do requestDesacoplar a execução do socket; persistir parcial no erro
M1 — poll-on-returnGeração continua; ao voltar, o cliente faz poll do status ("gerando…") e recarrega o histórico no fim — sem deltas ao vivo na voltaExecução desacoplada + status/heartbeat no banco + parcial persistidoEvent log com seq + replay por cursor (vira M2)
M2 — resume realAo voltar: replay instantâneo do que perdeu + tail ao vivo do restante — o contrato da §1 completoM1 + event store atômico + Last-Event-ID + snapshot + dois timestampsExecutor durável + tool ledger + fencing (vira M3)
M3 — durável completoM2 + a geração sobrevive a crash/deploy do backend; side-effects nunca duplicamM2 + fila/lease/fencing epoch + tool ledger com outcome_unknown + outbox + property tests—
+
+ Caminho recomendado: M0→M1 é um dia de trabalho e elimina a pior falha (perder a geração). + M1→M2 é o salto de UX (o que ChatGPT/Claude fazem). M2→M3 é disciplina de produção — priorize quando houver + tools com side-effects reais ou SLA. Não pule direto para engines pesados sem medir onde você está. +
+
+ +
+

21. Checklist final

+
    +
  • [ ] Execução desacoplada do socket (fechar a aba não mata a geração)
  • +
  • [ ] Evento normalizado provider-neutro com schema_version (payload cru vai dentro, versionado)
  • +
  • [ ] Append atômico (Lua/MULTI/XADD) + seq monotônico + dedupe no ingresso
  • +
  • [ ] Commit-before-emit (nada chega ao browser sem estar no log)
  • +
  • [ ] Replay+tail sem janela (XREAD BLOCK ou subscribe-before-replay)
  • +
  • [ ] Protocolo de cursor: 410/409 + snapshot com snapshot_seq; cursor por conexão
  • +
  • [ ] Reducer idempotente; cursor salvo após aplicar (at-least-once)
  • +
  • [ ] Dois timestamps carimbados no commit (apresentável vs primeiro delta de answer)
  • +
  • [ ] phase correlacionado por item_id; phase preservado no replay manual de histórico
  • +
  • [ ] Idempotency key no turno; retry silencioso só com zero side-effect/visível/tool
  • +
  • [ ] Tool ledger com outcome_unknown (nunca re-executar automaticamente)
  • +
  • [ ] FSM com terminais imutáveis (CAS), cancel_requested ≠ cancelled, completion barrier, truncamento = incomplete
  • +
  • [ ] Failover = nova tentativa marcada; reasoning descartado; só tools confirmados atravessam
  • +
  • [ ] TransportSelector ≠ ProviderRouter; WS mode como capability opt-in com ganho medido
  • +
  • [ ] Autorização em subscribe/replay/cancel (cursor não é credencial); tenant isolado; redaction/TTLs no event store local
  • +
  • [ ] Executor com lease+fencing epoch e orphan reaper (M3) quando houver side-effects/SLA
  • +
  • [ ] Property test: replay == live view
  • +
+
+ + +
+

Cheat sheet

+
    +
  • Resume do usuário = camada 2. WS com o provider não participa dessa conta.
  • +
  • HTTP/SSE = baseline portátil; WS mode = capability opt-in com ganho medido ("até ~40%" oficial vale para 20+ tool calls).
  • +
  • WS + store=false: reconectar = novo socket + reenviar contexto (o cache era da conexão).
  • +
  • Background mode: resume nativo, mas store=true (não-ZDR, ~10 min) — sob ZDR a durabilidade é SUA.
  • +
  • "Primeiro token real" = first_answer_text_delta_at, carimbado no commit do backend; phase vem da mensagem (via item_id), não do delta.
  • +
  • Replay seguro: XREAD BLOCK desde o cursor; 410 → snapshot(snapshot_seq)+tail; reducer idempotente; cursor por conexão.
  • +
  • Retry silencioso só com: zero side-effect + zero user-visible + zero tool call. Senão: incomplete + nova tentativa explícita.
  • +
  • Failover cross-provider: nova bolha (retry_of), descarta reasoning, leva texto + tools confirmados.
  • +
+
+ +
+

Notas de verificação

+
    +
  • Verificado WS mode: reconexão e recuperação. A doc oficial (websocket-mode, seção Reconnect and recover) confirma: após queda ou limite de 60 min, abre-se novo socket; com store=true continua-se por previous_response_id; com store=false/ZDR inicia-se nova resposta com previous_response_id=null e contexto completo (ou janela do /responses/compact). Conferido em 2026-07-09.
  • +
  • Verificado Semântica de phase. A doc oficial (reasoning, seção phase parameter) confirma: phase é campo de mensagens do assistente (commentary/final_answer), recomendado para evitar early-stopping; ao replay manual de histórico deve-se preservar o valor original. Não existe phase no evento de delta — a correlação é por item_id. Conferido em 2026-07-09.
  • +
  • Verificado WS mode não exige SDK específico. O exemplo oficial usa websocket-client diretamente; responses.connect() existe no SDK Python antes da série 2.45 (verificado no código-fonte do SDK). Conferido em 2026-07-09.
  • +
  • Verificado Background mode. Requer background:true (+ stream:true para streaming), retomada por starting_after=<sequence_number>, exige estado armazenado (~10 min de retenção; incompatível com ZDR). Helper de retomada no SDK anotado como "coming soon" na doc. Conferido em 2026-07-09.
  • +
  • Verificado "Até ~40% em 20+ tool calls" é o enunciado oficial de desempenho do WS mode — é dado observado, não limiar de break-even; este guia não converte isso em regra.
  • +
  • UNVERIFIED (menor) Gemini Live com texto em produção de chat: o protocolo aceita texto (referência oficial da Live API), mas o posicionamento continua realtime/native-audio em Preview; este guia o mantém fora da cadeia de fallback de texto por posicionamento, não por incapacidade técnica.
  • +
  • Método Três rodadas adversariais (2026-07-09): o desenho da camada 2 foi desafiado por dois modelos frontier externos em rodadas independentes; as objeções que sobreviveram à reconciliação com a doc oficial estão incorporadas (janela replay→tail, fencing epoch, tool ledger/outcome_unknown, commit-before-emit, dedupe no ingresso, dois timestamps, cursor por conexão, snapshot com watermark, limites do Redis Streams, separação TransportSelector/ProviderRouter).
  • +
+
+ +
+
+ +
+
+
+
Streaming Durável & Resumível arquitetura transversal · super-guia de agentes
+

+ Referência técnica construída a partir da documentação oficial pública em 2026-07-09. + Resume do usuário na camada 2; transporte com o provider como decisão independente e medida. Para + informação sempre atualizada, consulte as fontes oficiais. +

+
+
+
Crédito de produção
+
Pesquisa multi-agente + 3 rodadas adversariais (frontier externos, fontes oficiais)
+
montagem e reconciliação pelo orquestrador Fable 5 / Opus 4.8 · 2026-07-09
+
+ Arquitetura · v1 + Resume = camada 2 +
+
+ +
+
+ + + + diff --git a/references/agents_tools_best_guides/index.html b/references/agents_tools_best_guides/index.html index 5e7812d..aeecc3a 100644 --- a/references/agents_tools_best_guides/index.html +++ b/references/agents_tools_best_guides/index.html @@ -304,7 +304,7 @@
Guia Completo de Agentes Portal mestre · orquestração de agentes de IA
Verificado em 2026-07-09 - 23 guias + 24 guias multi-provedor
@@ -360,7 +360,7 @@

Guia Completo de Agentes — Portal

Agent Skills. Para IA e humanos: prosa em PT-BR, identificadores e código em inglês.

- 23 guias + 24 guias OpenAI · Anthropic · Google SOTA · verificado 2026-06-29
@@ -666,6 +666,12 @@

Multimodal & paralelismo

TransversalOpenAI · Gemini · Anthropic
Abrir + +
Streaming durável & resumível
+

A resposta agêntica que sobrevive a fechar a aba: as duas camadas de transporte (provider vs frontend), HTTP/SSE vs WebSocket mode, event store com seq + replay Last-Event-ID, execução desacoplada, timestamps do 1º token, idempotência/tool ledger e failover cross-provider como nova tentativa. Padrões de maturidade M0–M3.

+
TransversalOpenAI · Gemini · AnthropicNovo · 2026-07-09
+ Abrir +
@@ -718,6 +724,7 @@

Matriz de navegação — tópico → guia

Handoff / multi-agentenúcleo de arquitetura · Agents SDK · LangGraph · ADK HITL (human-in-the-loop)LangGraph · ADK · DeepAgents · núcleo de ferramentas Persistência / checkpointsLangGraph · núcleo de estado · operação + Streaming durável / resume / SSE · WebSocket · Last-Event-IDstreaming durável & resumível · OpenAI §12.2 · providers & adapters Guardrails / segurançaAgents SDK · ADK · operação Tracing / observabilidadeAgents SDK · ADK · operação Agent Skills (autoria)guia de skills @@ -787,8 +794,9 @@

Fontes oficiais & verificação

deep freshness sweep (6 agentes Sonnet 4.6 + verificação manual contra changelogs oficiais) — versões para latest (anthropic 0.113.0, pydantic-ai 2.1.0, openai 2.44.0/6.45.0, @openai/agents 0.12.0, langchain-core 1.4.8, langchain-google-genai 4.2.6); calendário de sunsets por provedor (gpt-image-1-mini/1.5 01/12, Assistants API 08/26, Veo 2/3 30/06, Imagen 4 17/08, Opus 4.1 05/08); breaking: sampling 400 em Opus 4.7+/Fable 5, tokenizer ~30%, Interactions Beta→GA, default model gpt-5.4-mini (Agents SDK) e gemini-3-flash-preview (ADK); correções (mito "pydantic-ai sem 1.x", gpt-image-1-mini data) · 2026-06-29
freshness sweep (4 agentes Sonnet 5 + verificação/edição manual pelo Opus contra fontes oficiais) — Claude Sonnet 5 GA (30/06; Sonnet 4.6 → Legacy; intro $2/$10 até 31/08); Fable 5 reimplantado (01/07, pós-suspensão por export controls); MCP spec 2026-07-28 = Release Candidate travada (21/05) + alerta de auto-upgrade do pacote mcp→v2 (pinar mcp<2); versões (langgraph 1.2.7, mcp 1.28.1, anthropic 0.116.0/@anthropic-ai/sdk 0.110.0, openai-agents 0.17.7); Nano Banana Lite (gemini-3.1-flash-lite-image) GA 30/06. 10 guias atualizados · 2026-07-05
freshness sweep (8 agentes Sonnet 5 + validação adversarial e edição pelo Opus contra fontes oficiais) — OpenAI GPT-5.6 (Sol/Terra/Luna) lançado 09/07 via API em preview limitado (sol $5/$30, terra $2,50/$15, luna $1/$6; effort max, Programmatic Tool Calling, multi-agente beta) + caching explícito (prompt_cache_breakpoint, ttl 30m, escrita 1,25×) que modelos ≤5.5 rejeitam; gpt-realtime-2.1/-mini (06/07, novo default de voz); Fable 5 — acesso incluído estendido a 12/07, usage credits a partir de 13/07; EU AI Act — enforcement/multas GPAI em 02/08/2026; versões (langgraph 1.2.8, google-genai 2.11.0, google-adk 2.4.0/ADK Go 2.0, MCP TS SDK v2 beta.3). Confirmado que Gemini 3.5 Flash já constava correto; MCP RC 2026-07-28 segue RC. 6 guias atualizados · 2026-07-09
+
NOVO GUIA: Streaming Durável & Resumível (estudo aprofundado + 3 rodadas adversariais com modelos frontier externos e reconferência na fonte oficial) — as duas camadas de transporte (backend↔provider vs backend↔frontend), HTTP/SSE como baseline vs WebSocket mode da Responses como capability opt-in (reconexão = novo socket; sob store=false a cadeia se perde), background mode não-ZDR, event store com seq + replay Last-Event-ID sem janela (XREAD BLOCK), dois timestamps do "1º token", semântica correta de phase (mensagem, não delta), idempotência com tool ledger/outcome_unknown, failover cross-provider como nova tentativa e padrões de maturidade M0–M3. Cross-links adicionados em OpenAI §12.2, Providers & Adapters, Arquitetura §13 e File Inputs · 2026-07-09
- 23 guias + 24 guias multi-provedor
@@ -821,6 +829,7 @@

Fontes oficiais & verificação

{ "@type": "TechArticle", "name": "Contagem de tokens", "url": "guia_token_counting.html" }, { "@type": "TechArticle", "name": "Multimodal", "url": "guia_multimodal.html" }, { "@type": "TechArticle", "name": "File inputs sem provider storage + Hosted execution", "url": "guia_file_inputs_no_storage.html" }, + { "@type": "TechArticle", "name": "Streaming durável e resumível", "url": "guia_streaming_durabilidade_resume.html" }, { "@type": "TechArticle", "name": "Paralelismo de tools", "url": "guia_paralelismo_tools_openai_gemini_anthropic.html" }, { "@type": "TechArticle", "name": "Agentic vision e code tools", "url": "guia_agentic_vision_code_tools.html" }, { "@type": "TechArticle", "name": "Arquitetura e orquestracao", "url": "guia_arquitetura_orquestracao.html" }, From 53c539e2be45c0901941582565d13156182eec8f Mon Sep 17 00:00:00 2001 From: Rafael Bittencourt Date: Thu, 9 Jul 2026 18:46:22 -0300 Subject: [PATCH 08/16] chore(skills): resync project-level skills do Skills-Manager (freshness 2026-07-09) Propaga updates de modelos (GPT-5.6, Claude Sonnet 5/Fable 5, Gemini 3.5/Live), versoes de library e correcoes da revisao completa para as skills project_level gerenciadas pelo Skills-Manager. Somente skills catalogadas; custom preservadas. Co-Authored-By: Claude Opus 4.8 (1M context) --- .agents/skills/langgraph-deep-agents/SKILL.md | 12 ++++++++---- .../references/IMPLEMENTATION_SNIPPETS.md | 6 ++++-- .../LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md | 5 +++-- .../references/VERSIONING_FRESHNESS.md | 13 +++++++------ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/.agents/skills/langgraph-deep-agents/SKILL.md b/.agents/skills/langgraph-deep-agents/SKILL.md index 9d77989..c554d2d 100644 --- a/.agents/skills/langgraph-deep-agents/SKILL.md +++ b/.agents/skills/langgraph-deep-agents/SKILL.md @@ -5,7 +5,7 @@ description: |- license: Apache-2.0 metadata: author: coding-agent - version: 1.0.5 + version: 1.0.8 category: ai-agents subcategory: orchestration vendor: universal @@ -65,10 +65,10 @@ Implementation playbook for building stateful, graph-based AI agent systems usin Five steps, each with copy-paste code in `references/IMPLEMENTATION_SNIPPETS.md`. Work through them in order; skip steps that do not apply (e.g. single-agent graphs skip Step 4). 1. **State Schema and Graph Structure** — define the state that flows through the graph (TypedDict / Pydantic / dataclass) with the right reducers (no annotation = overwrite; `add_messages` = append + dedup by ID; custom `(old, new) -> merged`), then wire nodes as pure functions returning partial updates and edges (static or conditional via `add_conditional_edges`). -2. **Persistence, Checkpointing, and Streaming** — compile with a `checkpointer` (snapshot per super-step → resume, time-travel, HITL), inspect via `get_state` / `get_state_history`, and stream in one of 7 modes (`values`, `updates`, `messages`, `custom`, `checkpoint`, `tasks`, `debug`). Opt into `version="v2"` for typed `StreamPart` dicts, `GraphOutput` (`.value` / `.interrupts`), and Pydantic/dataclass coercion. +2. **Persistence, Checkpointing, and Streaming** — compile with a `checkpointer` (snapshot per super-step → resume, time-travel, HITL), inspect via `get_state` / `get_state_history`, and stream in one of 7 modes (`values`, `updates`, `messages`, `custom`, `checkpoint`, `tasks`, `debug`). Opt into `version="v2"` for typed `StreamPart` dicts, `GraphOutput` (`.value` / `.interrupts`), and Pydantic/dataclass coercion. For **new code, prefer `stream_events(version="v3")`** (`graph.stream_events(..., version="v3")`): provides typed projections per channel — `stream.messages`, `stream.values`, `stream.output`, `stream.subgraphs`, `stream.interrupts`, `stream.interrupted`, `stream.tool_calls`, `stream.extensions` — iterable directly without parsing raw event dicts. Do not confuse `stream_events` `version="v3"` with `invoke`/`stream` `version="v2"` (those remain valid for `GraphOutput` and interrupt resume). Use `stream.interleave("values", "messages")` to consume multiple projections in arrival order. 3. **Human-in-the-Loop and Memory** — add approval gates via 3 interrupt mechanisms (`interrupt_before`, `interrupt_after`, dynamic `interrupt()` inside nodes), resume with `Command(resume=...)` or `update_state`; use thread checkpoints for short-term memory and a cross-thread `Store` (namespaced by user_id) for long-term memory. 4. **Multi-Agent Patterns** — pick supervisor (`langgraph-supervisor-py`, central routing), swarm (`langgraph-swarm-py`, peer handoff via `Command(goto=...)`, ~40% lower latency vs supervisor), hierarchical teams (nested subgraphs), or Deep Agents (`create_deep_agent`). Define clear agent boundaries. -5. **Tool Integration, Deep Agents, and Deployment** — wire tools via `ToolNode` + `tools_condition` or `create_react_agent`; configure Deep Agents middleware (write_todos, filesystem, subagent task tool) and a filesystem backend (`StateBackend`, `FilesystemBackend`, `StoreBackend`, `ContextHubBackend`, `LocalShellBackend`, `CompositeBackend`, sandboxes); deploy to LangSmith Deployment (managed/lite/enterprise/BYOC), standalone server, or embedded, with LangSmith tracing. +5. **Tool Integration, Deep Agents, and Deployment** — wire tools via `ToolNode` + `tools_condition`; **avoid `create_react_agent` from `langgraph.prebuilt`** (deprecated in LangGraph v1, emits `@deprecated` warning; use `from langchain.agents import create_agent` with `system_prompt=` instead of `prompt=`). Configure Deep Agents middleware (write_todos, filesystem, subagent task tool) and a filesystem backend (`StateBackend`, `FilesystemBackend`, `StoreBackend`, `ContextHubBackend`, `LocalShellBackend`, `CompositeBackend`, sandboxes); deploy to LangSmith Deployment (managed/lite/enterprise/BYOC), standalone server, or embedded, with LangSmith tracing. Deep Agents 0.6.x middleware additions: **`RubricMiddleware`** (auto-eval loop, added 0.6.5); **`CodeInterpreterMiddleware`** (QuickJS JS/TS sandbox, `pip install "deepagents[quickjs]"`, adds `eval` tool, experimental); **`BedrockPromptCachingMiddleware`** (0.6.12). **Breaking 0.6.8:** `SubagentRunStream`, `AsyncSubagentRunStream`, `SubagentTransformer` removed from public exports (were internal beta). HITL via `interrupt_on={"tool_name": True | {"allowed_decisions": [...]}}` (requires `checkpointer`, `version="v2"` in invoke). **PTC security gotcha:** when `CodeInterpreterMiddleware(ptc=["tool"])` is used, tools invoked from inside JS code bypass `interrupt_on` approval workflows — never include HITL-gated tools in the PTC allowlist. **Read `references/IMPLEMENTATION_SNIPPETS.md`** for the full code for every step. **Read `references/LANGGRAPH_CORE_PATTERNS.md`** (Steps 1-2), **`references/LANGGRAPH_HITL_MEMORY.md`** (Step 3), and **`references/LANGGRAPH_MULTI_AGENT.md`** (Step 4) for conceptual depth. @@ -100,6 +100,8 @@ Five steps, each with copy-paste code in `references/IMPLEMENTATION_SNIPPETS.md` 9. **In-memory storage in production** -- MemorySaver is ephemeral and local; use PostgresSaver/DynamoDB for production (fault tolerance, multi-worker). 10. **Cross-user memory leakage** -- Always namespace Store memories by user_id to prevent cross-user data leaks. 11. **Middleware + custom state_schema** -- Currently mutually exclusive in `create_agent()`; workaround by attaching state to message metadata. +12. **`create_react_agent` from `langgraph.prebuilt` is deprecated** -- LangGraph v1 moved these prebuilts to `langchain.agents`. Use `from langchain.agents import create_agent(model, tools, system_prompt=...)`. `langgraph-supervisor` / `langgraph-swarm` packages may still use it internally; check the package version before switching. +13. **PTC bypasses HITL** -- `CodeInterpreterMiddleware` PTC calls go through the interpreter bridge, not the normal tool calling path. `interrupt_on` approval workflows are NOT enforced for PTC-invoked tools. Never put HITL-gated tools in the PTC allowlist. ## Example Prompts @@ -119,7 +121,9 @@ Use the langgraph-deep-agents skill to [describe your graph-based agent need]. ## Versioning and Freshness -As-of 2026-06-04. Current lines: **`langgraph 1.2.4`** (1.0 GA: durable state, built-in persistence, first-class HITL; `langgraph.prebuilt` deprecated → `langchain.agents`) and **`deepagents 0.6.8`** (released 2026-06-03; standalone library on the LangGraph runtime — write_todos planning, task-tool subagents, filesystem backends, async subagents, multi-modal `read_file`, `dcode` CLI, ACP). LangGraph Platform renamed to **LangSmith Deployment** (Oct 2025). Checkpointers: MemorySaver (dev), SqliteSaver, PostgresSaver (prod), DynamoDBSaver, MongoDB, Redis. Known limit: `middleware` + custom `state_schema` mutually exclusive in `create_agent()`. LangGraph APIs evolve frequently — verify import paths, class names, and signatures against the latest docs; do not hardcode minor versions in user code. Comparison: LangGraph = production-grade stateful (best observability via LangSmith); CrewAI = fastest time-to-production; AutoGen = maintenance mode; Deep Agents = complex multi-step tasks with context isolation. +As-of 2026-07-09. Current lines: **`langgraph 1.2.8`** (2026-07-06 bugfix over 1.2.7 -- fixes a delta-channel bug where `updateState` on a fresh thread forced a stub checkpoint instead of a full snapshot; 1.0 GA: durable state, built-in persistence, first-class HITL; `langgraph.prebuilt` deprecated → `langchain.agents`) and **`deepagents 0.6.12`** (stable, released 2026-06-25; standalone library on the LangGraph runtime — write_todos planning, task-tool subagents, filesystem backends, async subagents, multi-modal `read_file`, `dcode` CLI, ACP; compatibility `langchain-core >=1.4,<2`, `langchain >=1.3.4,<2`, `langchain-anthropic >=1.4.3,<2`, `langchain-google-genai >=4.2.2,<5`). A **preview-only** `deepagents 0.7.0a3` alpha (2026-07-01) adds middleware override by name, sandbox round-trip optimization, Bedrock prompt-caching (`deepagents[aws]`), plus (0.7.x line) `CodeInterpreterMiddleware`, `DeltaChannel` history, Harness profiles, and `ContextHubBackend` (LangSmith Hub) — do not use in production, keep pinned to `0.6.12`. **Event streaming:** `stream_events(version="v3")` is the recommended API for new code — exposes typed projections (`stream.messages`, `stream.values`, `stream.output`, `stream.subgraphs`, `stream.interrupts`, `stream.tool_calls`, `stream.extensions`) without parsing raw event dicts; `version="v3"` also available on `RemoteGraph` (1.2.3+). Separate from `invoke`/`stream` `version="v2"` which controls `GraphOutput` and `StreamPart` typing. The 7 `stream_mode` values (`values`, `updates`, `messages`, `custom`, `checkpoint`, `tasks`, `debug`) remain available under all event versions. **Deep Agents 0.6.x highlights:** `RubricMiddleware` (0.6.5), `CodeInterpreterMiddleware` QuickJS (0.6.0 experimental), `BedrockPromptCachingMiddleware` (0.6.12); breaking 0.6.8 removed `SubagentRunStream`/`AsyncSubagentRunStream`/`SubagentTransformer` from public API. LangGraph Platform renamed to **LangSmith Deployment** (Oct 2025). Checkpointers: MemorySaver (dev), SqliteSaver, PostgresSaver (prod), DynamoDBSaver, MongoDB, Redis. **Model examples now use `model="anthropic:claude-sonnet-5"`** — `langchain-anthropic` accepts it via passthrough (no enum validation), but the last published connector (`1.4.8`, 2026-06-26) predates Sonnet 5 GA (2026-06-30); validate with a real call before production. Known limit: `middleware` + custom `state_schema` mutually exclusive in `create_agent()`. LangGraph APIs evolve frequently — verify import paths, class names, and signatures against the latest docs; do not hardcode minor versions in user code. Comparison: LangGraph = production-grade stateful (best observability via LangSmith); CrewAI = fastest time-to-production; AutoGen = maintenance mode; Deep Agents = complex multi-step tasks with context isolation. + +**Freshness (2026-07-09):** refreshed pins to `langgraph 1.2.8` and `deepagents 0.6.12` (stable), flagged the `deepagents 0.7.0a3` preview line as not for production, and switched code examples to `model="anthropic:claude-sonnet-5"` with the `langchain-anthropic` passthrough validation caveat. Verified against `guia_completo_agentes/guia_deepagents.html` and `guia_completo_agentes/guia_langgraph.html`. **Read `references/VERSIONING_FRESHNESS.md`** for the full source list (official docs, GitHub, PyPI, supervisor/swarm libs), all version deltas, OpenTelemetry/OWASP relevance, runtime defaults, and the model-family reference. diff --git a/.agents/skills/langgraph-deep-agents/references/IMPLEMENTATION_SNIPPETS.md b/.agents/skills/langgraph-deep-agents/references/IMPLEMENTATION_SNIPPETS.md index a21b36a..46fce22 100644 --- a/.agents/skills/langgraph-deep-agents/references/IMPLEMENTATION_SNIPPETS.md +++ b/.agents/skills/langgraph-deep-agents/references/IMPLEMENTATION_SNIPPETS.md @@ -188,7 +188,7 @@ graph.add_conditional_edges("agent", tools_condition) app = create_react_agent(model, tools=tools, checkpointer=checkpointer) ``` -- **Deep Agents** (`pip install deepagents`, MIT license, current line `deepagents == 0.6.8` released 2026-06-03; Python `>=3.11,<4.0` — 3.11 through 3.14; verify at https://pypi.org/project/deepagents/): +- **Deep Agents** (`pip install deepagents`, MIT license, current stable line `deepagents == 0.6.12` released 2026-06-25; Python `>=3.11,<4.0` — 3.11 through 3.14; verify at https://pypi.org/project/deepagents/). A preview-only `0.7.0a3` alpha (2026-07-01) exists with middleware override by name, sandbox round-trip optimization, and Bedrock prompt-caching (`deepagents[aws]`) — do not use the alpha line in production: ```python from deepagents import create_deep_agent @@ -200,12 +200,14 @@ result = agent.invoke({"messages": [{"role": "user", "content": "Research and su # Custom configuration agent = create_deep_agent( - model=init_chat_model("openai:gpt-5.4-mini"), + model=init_chat_model("anthropic:claude-sonnet-5"), tools=[my_custom_tool], system_prompt="You are a research assistant.", ) ``` +**Model-selection caveat:** `langchain-anthropic` accepts any model string via passthrough (no enum validation), so `"anthropic:claude-sonnet-5"` works as shown above -- but the last published connector (`1.4.8`, 2026-06-26) predates Sonnet 5's GA (2026-06-30), and no changelog confirms tested support for Sonnet-5-specific beta features (new tokenizer, beta headers). Run a real validation call before production and track `langchain-anthropic` releases newer than `1.4.8`. + Deep Agents middleware (auto-attached): 1. **write_todos middleware**: Adds `write_todos` tool + instructions for explicit planning and todo tracking. 2. **Filesystem middleware**: Adds `ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep` for context offloading. diff --git a/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md index d231549..b872523 100644 --- a/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md +++ b/.agents/skills/langgraph-deep-agents/references/LANGGRAPH_1_2_DEEPAGENTS_0_6_NOTES.md @@ -1,7 +1,7 @@ # LangGraph 1.2.x + Deep Agents 0.6.x — SOTA notes > Scope: deltas vs the previous LangGraph 1.1.x / Deep Agents 0.5.x lines. -> Verified 2026-06-04 against the local SOTA guides +> Verified 2026-07-05 against the local SOTA guides > (`guia_completo_agentes/guia_langgraph_orquestracao.html` and > `guia_completo_agentes/guia_deepagents.html`, at the repo root) > and live docs. @@ -17,7 +17,8 @@ ## SOTA delta -- **Versions:** `langgraph == 1.2.4` and `deepagents == 0.6.8` (released 2026-06-03). Python `>=3.11,<4.0` for Deep Agents. +- **Versions:** `langgraph == 1.2.8` (2026-07-06 bugfix over 1.2.7) and `deepagents == 0.6.12` (stable, released 2026-06-25). Python `>=3.11,<4.0` for Deep Agents. Compatibility: `langchain-core >=1.4,<2`, `langchain >=1.3.4,<2`, `langchain-anthropic >=1.4.3,<2`, `langchain-google-genai >=4.2.2,<5`. +- **Preview-only, not for production:** `deepagents == 0.7.0a3` (alpha, 2026-07-01) previews middleware override by name in `create_deep_agent`, sandbox round-trip optimization, and Bedrock prompt-caching under `deepagents[aws]`. The wider 0.7.x line also previews `CodeInterpreterMiddleware` (stabilized), a `DeltaChannel` for history, Harness profiles, and a `ContextHubBackend` backed by LangSmith Hub. Keep production pinned to `0.6.12`; do not recommend the alpha line for production use. - **LangGraph 1.x stable surface:** durable state, built-in persistence, first-class HITL (interrupt before/after, dynamic `interrupt()`, `Command(resume=)`). v2 typed streaming with Pydantic/dataclass coercion and time-travel fixes for RESUME values and subgraph parent checkpoints. `langgraph.prebuilt` deprecated — use `langchain.agents` (`create_agent`, middleware framework). - **Deep Agents 0.6 pillars unchanged:** `BASE_AGENT_PROMPT` + feature prompts (TASK / FILESYSTEM / SKILLS / MEMORY / SUMMARIZATION); `write_todos` planning tool; `task(...)` subagent spawning; virtual filesystem (`ls`, `read_file`, `write_file`, `edit_file`, `glob`, `grep`). - **New tooling extras to know:** diff --git a/.agents/skills/langgraph-deep-agents/references/VERSIONING_FRESHNESS.md b/.agents/skills/langgraph-deep-agents/references/VERSIONING_FRESHNESS.md index 0b46e0f..63ea041 100644 --- a/.agents/skills/langgraph-deep-agents/references/VERSIONING_FRESHNESS.md +++ b/.agents/skills/langgraph-deep-agents/references/VERSIONING_FRESHNESS.md @@ -26,8 +26,9 @@ long-term memory, HITL, and auto-summarization. CLI available separately. ## Key recent additions - **LangGraph 1.0 GA**: durable state + built-in persistence + first-class HITL as stable primitives; only notable breaking change is the deprecation of `langgraph.prebuilt` — enhanced functionality moved to `langchain.agents`. -- **LangGraph v1.2.4** (current as of 2026-06-04): builds on v1.1.x Deep Agent templates and distributed runtime support in the CLI; v2 type-safe streaming/invoke with Pydantic/dataclass coercion and time-travel fixes for RESUME values and subgraph parent checkpoints; model retry middleware, content moderation middleware (OpenAI), `SystemMessage` support in `create_agent`, summarization middleware, HITL middleware; pluggable sandbox integrations (Modal, Daytona, Runloop). -- **Deep Agents `0.6.8`** (2026-06-03): async subagents, multi-modal `read_file`, backend protocol update for binary files, `dcode` CLI, and ACP integration. +- **LangGraph v1.2.7** (current as of 2026-06-30, bugfix release over 1.2.6): builds on v1.1.x Deep Agent templates and distributed runtime support in the CLI; v2 type-safe streaming/invoke with Pydantic/dataclass coercion and time-travel fixes for RESUME values and subgraph parent checkpoints; model retry middleware, content moderation middleware (OpenAI), `SystemMessage` support in `create_agent`, summarization middleware, HITL middleware; pluggable sandbox integrations (Modal, Daytona, Runloop). +- **Deep Agents `0.6.12`** (stable, 2026-06-25): adds `BedrockPromptCachingMiddleware`. Prior 0.6.x history: 0.6.9 configurable subagent response format; 0.6.7 exported `DeepAgentState` + `Command` propagates `goto`/graph; 0.6.5 `RubricMiddleware`; 0.6.0 `DeltaChannel` + event streaming v2. Also carries async subagents, multi-modal `read_file`, backend protocol update for binary files, `dcode` CLI, and ACP integration. +- **Deep Agents `0.7.0a3`** (alpha/preview only, 2026-07-01): middleware override by name in `create_deep_agent`, sandbox round-trip optimization, Bedrock prompt-caching via `deepagents[aws]`; the 0.7.x line also previews `CodeInterpreterMiddleware`, a `DeltaChannel` for history, Harness profiles, and `ContextHubBackend` (LangSmith Hub). Preview only -- keep production pinned to `0.6.12`. - **Functional API** (`@entrypoint`, `@task`) available alongside the graph API for imperative-style durable workflows — verify the current surface against the LangGraph changelog. - LangGraph `version="v2"` streaming returns typed `StreamPart` dicts; invoke returns `GraphOutput` with `.value` and `.interrupts`. Default remains v1 for backwards compatibility. Incremental adoption supported. - LangGraph Platform renamed to LangSmith Deployment (October 2025). Self-hosted options: lite (free), enterprise (in-VPC), hybrid BYOC. @@ -35,17 +36,17 @@ long-term memory, HITL, and auto-summarization. CLI available separately. - Known limitation: `middleware` and custom `state_schema` mutually exclusive in `create_agent()`. - Comparison: LangGraph = production-grade stateful (best observability via LangSmith). CrewAI = fastest time-to-production. AutoGen = maintenance mode. Deep Agents = complex multi-step tasks with context isolation. -## Freshness (as-of 2026-06-04) +## Freshness (as-of 2026-07-05) Verified against the local SOTA guides `guia_completo_agentes/guia_langgraph_orquestracao.html` and `guia_completo_agentes/guia_deepagents.html`. -- **LangGraph docs (Python)**: https://docs.langchain.com/oss/python/langgraph/overview — **LangGraph 1.0 is GA** (durable state, built-in persistence, first-class HITL; `langgraph.prebuilt` deprecated in favor of `langchain.agents`). Current line: **`langgraph 1.2.4`**. Checkpointers: MemorySaver, SqliteSaver, PostgresSaver, DynamoDBSaver, MongoDB, Redis. +- **LangGraph docs (Python)**: https://docs.langchain.com/oss/python/langgraph/overview — **LangGraph 1.0 is GA** (durable state, built-in persistence, first-class HITL; `langgraph.prebuilt` deprecated in favor of `langchain.agents`). Current line: **`langgraph 1.2.8`** (2026-07-06 bugfix over 1.2.7). Checkpointers: MemorySaver, SqliteSaver, PostgresSaver, DynamoDBSaver, MongoDB, Redis. - **LangGraph GitHub + releases**: https://github.com/langchain-ai/langgraph/releases and https://changelog.langchain.com/announcements/langgraph-1-0-is-now-generally-available (verify latest minor version at release time; do not hardcode in user code). -- **Deep Agents**: https://docs.langchain.com/oss/python/deepagents/overview and https://reference.langchain.com/python/deepagents/ ; releases: https://github.com/langchain-ai/deepagents/releases ; PyPI: https://pypi.org/project/deepagents/ (standalone library built on LangGraph runtime; **current line `deepagents == 0.6.8` released 2026-06-03**, Python `>=3.11,<4.0`). Extras: `deepagents[quickjs]` (Code Interpreter), `deepagents-acp` (IDE/ACP integration), `deepagents-code` (`dcode` CLI). April–May 2026 updates: async subagents (needs LangSmith Deployment), multi-modal `read_file` (PDF/audio/video), backend protocol update for binary files. +- **Deep Agents**: https://docs.langchain.com/oss/python/deepagents/overview and https://reference.langchain.com/python/deepagents/ ; releases: https://github.com/langchain-ai/deepagents/releases ; PyPI: https://pypi.org/project/deepagents/ (standalone library built on LangGraph runtime; **current stable line `deepagents == 0.6.12` released 2026-06-25**, Python `>=3.11,<4.0`). Compatibility: `langchain-core >=1.4,<2`, `langchain >=1.3.4,<2`, `langchain-anthropic >=1.4.3,<2`, `langchain-google-genai >=4.2.2,<5`. A **preview-only** `0.7.0a3` alpha (2026-07-01) adds middleware override by name, sandbox round-trip optimization, Bedrock prompt-caching (`deepagents[aws]`), and (0.7.x line) `CodeInterpreterMiddleware`, `DeltaChannel` history, Harness profiles, `ContextHubBackend` (LangSmith Hub) -- not for production. Extras: `deepagents[quickjs]` (Code Interpreter), `deepagents-acp` (IDE/ACP integration), `deepagents-code` (`dcode` CLI). April–May 2026 updates: async subagents (needs LangSmith Deployment), multi-modal `read_file` (PDF/audio/video), backend protocol update for binary files. - **Supervisor**: https://github.com/langchain-ai/langgraph-supervisor-py ; **Swarm**: https://github.com/langchain-ai/langgraph-swarm-py - **LangSmith Deployment** (was LangGraph Platform, rename Oct 2025): https://www.langchain.com/langsmith/deployment - **MCP tools adapter** for LangChain/LangGraph: https://github.com/langchain-ai/langchain-mcp-adapters - **OpenTelemetry GenAI semconv** (Development/Experimental) for tracing nodes/tools: https://opentelemetry.io/docs/specs/semconv/gen-ai/ - **OWASP LLM Top 10 2025 relevance** (LLM06 Excessive Agency, LLM10 Unbounded Consumption): enforce interrupt_before on destructive nodes, cap iteration counts, scope cross-thread Store namespaces. https://genai.owasp.org/llm-top-10/ - **Runtime defaults** (repo policy): Python 3.13 via `uv` / `.python-version` (Python 3.14 only if project explicitly opts in). Deep Agents CLI tested under this runtime. -- **Model reference** in example (`init_chat_model("openai:gpt-5.4-mini")`) aligns with repo CLAUDE.md model family (gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano; also Opus 4.8, Sonnet 4.6, Haiku 4.5; gemini-3.1-pro-preview, gemini-3.5-flash). +- **Model reference** in example (`init_chat_model("openai:gpt-5.4-mini")`) aligns with repo CLAUDE.md model family (gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano; also Opus 4.8, **Sonnet 5 (recommended)** / Sonnet 4.6 (legacy), Haiku 4.5; gemini-3.1-pro-preview, gemini-3.5-flash). All Deep Agents code examples in the guide now pass `model="anthropic:claude-sonnet-5"` explicitly (model default resolves via `HarnessProfile`/`init_chat_model`, but pin the ID explicitly in code). **Passthrough caveat:** `langchain-anthropic` accepts any model string via passthrough (no enum validation), so `"anthropic:claude-sonnet-5"` works -- but the last published connector (`1.4.8`, 2026-06-26) predates Sonnet 5's GA (2026-06-30), and no changelog confirms tested support for Sonnet-5-specific beta features (new tokenizer, beta headers). Validate with a real call before production; track `langchain-anthropic` releases newer than `1.4.8`. From 4920ff84e878db4d8f5174acca65a26981585f27 Mon Sep 17 00:00:00 2001 From: Rafael Bittencourt Date: Thu, 9 Jul 2026 20:54:18 -0300 Subject: [PATCH 09/16] docs: rodada mega-relatorio GPT-5.6 (long context 1,5x output, PTC 11.9, multi-agente/ultra, caching politica+breakeven, specs mini/nano, custo-por-sucesso) + contabilidade reasoning (Anthropic thinking_tokens 27/05, OpenAI incluso, Gemini separado) - verificado 2026-07-09 --- .../guia_openai_modelos.html | 37 ++++++++++++++++--- .../guia_operacao_seguranca_evals.html | 8 ++++ ...lelismo_tools_openai_gemini_anthropic.html | 1 + .../guia_providers_adapters.html | 1 + .../guia_token_counting.html | 27 ++++++++++---- .../agents_tools_best_guides/index.html | 1 + 6 files changed, 62 insertions(+), 13 deletions(-) diff --git a/references/agents_tools_best_guides/guia_openai_modelos.html b/references/agents_tools_best_guides/guia_openai_modelos.html index 3392eaf..d5085a9 100644 --- a/references/agents_tools_best_guides/guia_openai_modelos.html +++ b/references/agents_tools_best_guides/guia_openai_modelos.html @@ -446,10 +446,12 @@

1. Catálogo de modelos

A família GPT-5 é composta por modelos de raciocínio: eles geram reasoning tokens internos antes de produzir a resposta, o que melhora planejamento, uso de ferramentas, recuperação de ambiguidade e tarefas multi-etapa. O modelo de uso geral recomendado para a maioria das cargas é o gpt-5.5; quando latência ou custo pesam mais, considere as variantes menores gpt-5.4-mini e gpt-5.4-nano. Todos funcionam melhor pela Responses API.

O que é atual (linhagem GPT-5.x): os flagships evoluíram gpt-5.1 → gpt-5.2 → gpt-5.3 (com variante gpt-5.3-codex) → gpt-5.4 (com -mini/-nano/-pro) → gpt-5.5 + gpt-5.5-pro → família gpt-5.6 (Sol/Terra/Luna), lançada 2026-07-09. Ou seja, gpt-5.5 não sucede o 5.4 diretamente — há releases intermediários (5.2, 5.3) que são GA e podem estar em uso/pinned. A família gpt-5.6 já está disponível via API (endpoints responses/chat/completions/batch e Codex) em preview limitado, com GA anunciada "nas próximas semanas"; ainda não está no ChatGPT. São três tiers duráveis: gpt-5.6-sol (frontier/flagship), gpt-5.6-terra (equilíbrio inteligência/custo, ~2× mais barato que o 5.5 com desempenho competitivo) e gpt-5.6-luna (mais rápido e econômico). O alias gpt-5.6 roteia para gpt-5.6-sol. O gpt-5.5 não foi depreciado e continua opção estável/madura. Para código novo, prefira gpt-5.6-sol (ou -terra/-luna por custo); ao pinar, use o snapshot exato retornado pela pág. de modelos oficial. Verificado 2026-07-09 em developers.openai.com/api/docs/changelog e /pricing.
-
Novidades da família gpt-5.6 (2026-07-09): Programmatic Tool Calling, persisted reasoning, novo nível de reasoning effort max, Pro mode, orquestração multi-agente em beta na Responses API, e aceite de imagens em dimensões originais (image detail original/auto). Traz ainda caching explícito (ver Parte de tokens/custos): prompt_cache_breakpoint, prompt_cache_options.mode (implicit/explicit) e ttl mínimo de 30m — recursos que os modelos gpt-5.5 e anteriores não aceitam.
+
Novidades da família gpt-5.6 (2026-07-09): Programmatic Tool Calling (§11.9), persisted reasoning, novo nível de reasoning effort max, Pro mode, orquestração multi-agente em beta na Responses API, e aceite de imagens em dimensões originais (image detail original/auto). Traz ainda caching explícito (§15.3): prompt_cache_breakpoint, prompt_cache_options.mode (implicit/explicit) e ttl mínimo de 30m — recursos que os modelos gpt-5.5 e anteriores não aceitam.
+ +
Multi-agente beta ≠ effort. A orquestração multi-agente (beta) roda subagentes no lado do provider e cobra a soma de todos os agentes — o custo não é o de "uma chamada". Vale para trabalho paralelizável (exploração, verificação independente); não vale para tarefa curta/sequencial. Não confunda com reasoning.effort: o teto da API é max (mais tempo de raciocínio em um agente); em superfícies de produto (ex.: Codex CLI) o modo multi-agente aparece rotulado como effort ultra, que não é um valor aceito pela API. Evite estado mutável compartilhado entre subagentes. beta Fonte: changelog oficial; detalhes finos ainda em rollout.
- + @@ -459,10 +461,14 @@

1. Catálogo de modelos

Preços da família GPT-5.6 (USD por 1M tokens, short context ≤272K; long context >272K = 2× input/output). Verificado 2026-07-09.Preços da família GPT-5.6 (USD por 1M tokens, short context ≤272K). Long context >272K de input: 2× no input e 1,5× no output, aplicados ao request inteiro (nota oficial da página do modelo). Verificado 2026-07-09.
ModeloInputCached input (−90%)Cache write (1,25×)Output
gpt-5.6-sol$5,00$0,50$6,25$30,00
+
Long context e tiers de processamento (5.6): acima de 272K de input, o request inteiro é cobrado a 2× no lado do input (input, cached, write) e 1,5× no output — Sol long: $10 / $1 / $12,50 / $45; Terra: $5 / $0,50 / $6,25 / $22,50; Luna: $2 / $0,20 / $2,50 / $9. Batch e Flex = 50% do Standard (Sol $2,50/$15); Priority = 2× (Sol $10/$60) — o cache write escala junto com o tier. Regional/data residency: +10% para modelos lançados a partir de 05/03/2026 elegíveis a residência de dados (critério oficial — inclui a família 5.6 e os 5.4-mini/nano). Fonte: /pricing · página do modelo.
+
Nota: raciocínio mais alto não é automaticamente melhor. Com critérios de parada fracos ou acesso aberto a ferramentas, esforço alto pode levar a overthinking, buscas desnecessárias ou regressão de qualidade. Aumente o esforço só quando seus evals mostrarem ganho mensurável.
Dica: o gpt-5.5 oferece janela de contexto de 1.050.000 tokens e até 128.000 tokens de saída, com knowledge cutoff em 1 de dezembro de 2025. Aceita entrada de texto e imagem (saída só texto) e roda tanto pela Responses API quanto por Chat Completions — prefira a Responses API. Confirme limites por modelo na página oficial.
+
Specs verificadas (páginas de modelo, 2026-07-09): gpt-5.6-sol — contexto 1.050.000, max input 922K, max output 128K, cutoff 2026-02-16, endpoints responses/chat_completions/batch. gpt-5.4-mini e gpt-5.4-nano — contexto 400.000, max input 272K, max output 128K, cutoff 2025-08-31, reasoning.effort default none (suporta none/low/medium/high/xhigh). Diferença que importa ao escolher: o mini tem computer_use e tool_search; o nano não tem nenhum dos dois (classificação/extração/ranking/subagentes simples).
+

1.1 Tabela-mestra (modelos de texto/raciocínio)

@@ -1594,7 +1600,18 @@

11.8 Local shell & Shell

O runtime hospedado é baseado em Debian 12, com diretório de trabalho /mnt/data (caminho suportado para artefatos baixáveis) e linguagens pré-instaladas (Python 3.11, Node.js 22, Java 17, PHP 8.2, Ruby 3.1, Go 1.23). Não há TTY interativo nem sudo. Para fluxos iterativos, crie um container reutilizável e referencie-o entre chamadas.

Cuidado: executar comandos arbitrários é perigoso. Sempre faça sandbox, aplique allowlists/denylists e registre a atividade da ferramenta para auditoria.
-

11.9 Receitas e exemplos oficiais (Cookbook)

+

11.9 Programmatic Tool Calling (PTC) gpt-5.6 · 2026-07-09

+

O Programmatic Tool Calling deixa o modelo escrever e executar JavaScript que coordena as tools de um request da Responses API: chamadas em paralelo, loops, condições e resultados intermediários mantidos no runtime hospedado — em vez de um round trip modelo↔tool por chamada. Vale quando uma etapa tem fluxo de controle previsível e o código pode devolver um resultado estruturado menor (filtrar/juntar/agregar N resultados antes de voltar ao contexto do modelo).

+
    +
  • Runtime: cada programa roda em um V8 isolado e efêmero (JS com top-level await). Não há Node.js, instalação de pacotes, rede direta, filesystem geral, subprocessos, console nem estado persistente entre execuções. O programa só interage com o mundo via tools habilitadas no request e emite saída com text(...)/image(...).
  • +
  • Config: adicione a hosted tool {"type":"programmatic_tool_calling"} e marque cada tool elegível com allowed_callers: ["direct"] (só o modelo), ["programmatic"] (só código) ou ambos. Defina output_schema nas functions para o JS usar os campos com segurança. Suportadas em programa: function/custom, mcp (com require_approval pausando o programa), apply_patch, shell local/hosted e code_interpreter. tool_search roda só top-level — deferred tools precisam ser carregadas antes do programa começar.
  • +
  • Quem executa o quê: a OpenAI executa o JS gerado; sua aplicação continua executando as function calls client-owned que o programa dispara (itens function_call com caller.caller_id apontando para o program). Devolva cada resultado como function_call_output copiando o campo caller sem alterar — é ele que retoma o programa certo. O resultado final chega num item program_output (status completed/incomplete).
  • +
  • ZDR/store=false: PTC suporta ZDR sem container persistente de execução. Sob store:false, replaye todos os itens (program, reasoning, function calls/outputs, program_output) + include: ["reasoning.encrypted_content"].
  • +
  • Quando NÃO usar: uma única chamada; quando cada resultado precisa de julgamento fresco do modelo; ações com side-effect/aprovação (mantenha direct para preservar a fronteira de autorização); validação final de citações/artefatos nativos. Cheque as permissões de cada chamada na sua aplicação, mesmo vindo de programa hospedado — e meça contra baseline direct (tokens, latência, corretude) antes de adotar.
  • +
+ + +

11.10 Receitas e exemplos oficiais (Cookbook)

O OpenAI Cookbook traz receitas executáveis para os padrões desta parte. As abaixo estão alinhadas à Responses API e aos modelos atuais; use-as como ponto de partida e adapte os IDs de modelo para gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano.

@@ -2103,15 +2120,17 @@

15.2 prompt_cache_key e retenção

O parâmetro prompt_cache_retention aceita in_memory (cache em memória volátil, 5–10 min de inatividade até ~1h) e 24h (retenção estendida, até 24h, descarregando tensores key/value para storage GPU-local). Atual (confirmado no changelog oficial): o padrão é 24h para organizações sem ZDR (Zero Data Retention) em todos os modelos elegíveis de v1/responses, v1/chat/completions e v1/batch — antes, a maioria dos modelos usava in_memory por padrão. Para gpt-5.5, gpt-5.5-pro e modelos futuros, o padrão é 24h e in_memory não é mais suportado (retorna erro de request). Data UNVERIFIED A mudança consta na seção "May 2026" do changelog; o dia exato (citado antes como 2026-05-29) não foi confirmável linha a linha na fonte — o fato em si está confirmado.

Nota: caches não são compartilhados entre organizações; o caching não altera a saída gerada (só o prefixo é cacheado, a resposta é recalculada) nem isenta tokens dos limites de TPM. Não há limpeza manual de cache.
-

15.1 Caching explícito (família gpt-5.6 e posteriores) 2026-07-09

+

15.3 Caching explícito (família gpt-5.6 e posteriores) 2026-07-09

A partir de gpt-5.6, o caching ficou mais previsível e controlável. Além do caching implícito (que detecta prefixos automaticamente), você pode marcar breakpoints explícitos no fim de um prefixo reutilizável:

  • prompt_cache_breakpoint: {"mode":"explicit"} em blocos de conteúdo suportados (input_text, input_image, input_file) na Responses API — marca onde termina o prefixo reaproveitável.
  • prompt_cache_options.mode: implicit (padrão — coloca um breakpoint automático na última mensagem, além dos explícitos que você adicionar) ou explicit (desativa o automático; só os breakpoints explícitos são usados para leitura/escrita de cache).
  • prompt_cache_options.ttl: define uma vida mínima do cache (piso, não teto). O único valor suportado é "30m" — o prefixo fica reutilizável por ao menos 30 minutos (a OpenAI pode mantê-lo ativo por mais).
  • prompt_cache_key passa a ser obrigatório para matching confiável (tanto no modo implícito quanto no explícito).
  • -
  • Limites: até 4 escritas de cache por request; a leitura considera os últimos 50 breakpoints da conversa.
  • +
  • Limites: até 4 escritas de cache por request — no modo implicit, o breakpoint automático da última mensagem consome 1 dos 4 slots (sobram até 3 explícitos); no modo explicit, até 4 explícitos. Breakpoints de turnos anteriores são read-only (dão hit, mas não são re-escritos). A leitura considera os últimos 50 breakpoints da conversa; havendo vários matches, lê-se o prefixo mais longo.
  • +
  • prompt_cache_retention está deprecated para gpt-5.6+ — as semânticas são diferentes: retention (≤5.5) escolhe uma política de retenção máxima; ttl (5.6+) define uma vida mínima. Não misture os dois.
+
Política por workflow (a camada de decisão): chat comum → implicit puro; prefixo grande e estável (sistema+tools+KB) reusado por muitos requests → implicit + 1–3 breakpoints explícitos após os blocos estáveis; pipeline com prefixos controlados e tráfego previsível → mode:"explicit" (só cacheia o que você marcou — sem breakpoint, sem cobrança de write); upload one-shot / prompt que não repete → não marque breakpoint (write de 1,25× sem reuso é só +25% de custo perdido). Breakeven: o write custa 0,25× extra e cada read economiza 0,9× — um único reuso já paga a escrita (derivação na contagem de tokens). Sinais para revisar a política: cache_write_tokens alto com cached_tokens baixo (está pagando write sem colher read) ou hit rate caindo com >15 req/min por prompt_cache_key (particione as keys).
Mudança de custo: em gpt-5.6+, a escrita de cache passa a custar 1,25× a taxa de input não-cacheado (rastreada no campo cache_write_tokens) — antes as escritas eram gratuitas. A leitura de cache mantém o desconto de 90% (input cacheado = 10% do input padrão). Modelos gpt-5.5 e anteriores usam apenas o caching implícito com prompt_cache_retention e rejeitam prompt_cache_options / prompt_cache_breakpoint se enviados.
@@ -5038,6 +5057,9 @@

31.1 Modelos de texto / reasoning (Standard)

+ + + @@ -5046,7 +5068,7 @@

31.1 Modelos de texto / reasoning (Standard)

ModeloEntradaEntrada em cacheSaída
gpt-5.6-sol (≤272K; long: 2× in / 1,5× out)$5,00$0,50$30,00
gpt-5.6-terra$2,50$0,25$15,00
gpt-5.6-luna$1,00$0,10$6,00
gpt-5.5 (<272K contexto)$5,00$0,50$30,00
gpt-5.5-pro (<272K contexto)$30,00—$180,00
gpt-5.4-mini$0,75$0,075$4,50
-
Nota: endpoints de processamento regional (residência de dados) têm acréscimo de 10% para a família gpt-5.5/gpt-5.4. Tarifas de Batch e Flex equivalem a ~50% da tarifa Standard.
+
Nota: endpoints de processamento regional (residência de dados) têm acréscimo de 10% para modelos lançados a partir de 05/03/2026 elegíveis a data residency (critério oficial do rodapé de pricing — inclui a família gpt-5.6 e os gpt-5.4-mini/-nano, cujas páginas de modelo citam o uplift explicitamente). Tarifas de Batch e Flex equivalem a 50% da tarifa Standard — inclusive para a família 5.6 (Sol $2,50/$15 · Terra $1,25/$7,50 · Luna $0,50/$3).

31.2 Priority processing

O tier Priority oferece latência mais baixa e consistente, cobrado com prêmio sobre o Standard (descontos de cache continuam valendo).

@@ -5054,6 +5076,9 @@

31.2 Priority processing

+ + + diff --git a/references/agents_tools_best_guides/guia_operacao_seguranca_evals.html b/references/agents_tools_best_guides/guia_operacao_seguranca_evals.html index d13f032..0c0ed40 100644 --- a/references/agents_tools_best_guides/guia_operacao_seguranca_evals.html +++ b/references/agents_tools_best_guides/guia_operacao_seguranca_evals.html @@ -629,6 +629,14 @@

4. Tracing, replay e cost ledger

known:false / estimado — jamais como 0. Custo "zero" silencioso é a causa número um de cost spike não detectado. +
+ KPI que decide upgrade/downgrade de modelo: custo por sucesso. + custo_por_sucesso = custo_total_da_carga / tarefas_APROVADAS_no_eval — não compare modelos por + preço de tabela nem por custo médio por chamada. Um modelo 2× mais caro por token que resolve em 1 tentativa + e menos tool calls costuma vencer um "barato" que exige retries e reparo. Meça junto: pass rate no golden + set, taxa de retry/reparo, tool calls por tarefa e refusals. Isso vale também para decidir reasoning + effort e paralelismo multi-agente (onde o custo é a soma de todos os subagentes). +

O que um span precisa permitir

  • Replay sem dados sensíveis: hashes e ponteiros em vez do conteúdo bruto quando a classe de dado exigir.
  • diff --git a/references/agents_tools_best_guides/guia_paralelismo_tools_openai_gemini_anthropic.html b/references/agents_tools_best_guides/guia_paralelismo_tools_openai_gemini_anthropic.html index e4fc210..ded9a88 100644 --- a/references/agents_tools_best_guides/guia_paralelismo_tools_openai_gemini_anthropic.html +++ b/references/agents_tools_best_guides/guia_paralelismo_tools_openai_gemini_anthropic.html @@ -442,6 +442,7 @@

    1.3 Taxonomia de tools

    2. Matriz comparativa multi-provider

    +
    Novo (2026-07-09) — dois mecanismos de paralelismo server-side no GPT-5.6: (1) Programmatic Tool Calling — o modelo escreve JavaScript num runtime V8 isolado hospedado que chama tools em paralelo (Promise.all), com loops/condições, devolvendo um resultado agregado menor ao contexto; as function calls client-owned continuam executadas pela SUA aplicação (análogo funcional ao programmatic tool calling da Anthropic via code_execution_20260120, mas em V8 efêmero sem filesystem, ZDR-ok). (2) Orquestração multi-agente (beta) na Responses API — subagentes paralelos no provider; atenção: o custo é a soma de todos os subagentes. Detalhe e configuração: guia OpenAI §11.9.
ModeloEntradaEntrada em cacheSaída
gpt-5.6-sol$10,00$1,00$60,00
gpt-5.6-terra$5,00$0,50$30,00
gpt-5.6-luna$2,00$0,20$12,00
gpt-5.5$12,50$1,25$75,00
gpt-5.4-mini$1,50$0,15$9,00
diff --git a/references/agents_tools_best_guides/guia_providers_adapters.html b/references/agents_tools_best_guides/guia_providers_adapters.html index 7042d4d..e4e7521 100644 --- a/references/agents_tools_best_guides/guia_providers_adapters.html +++ b/references/agents_tools_best_guides/guia_providers_adapters.html @@ -706,6 +706,7 @@

11. Matriz de parâmetros por intenção

+
Evitar truncation perigosaMedir tokens, compactar antes, truncation: disabled quando falha explícita é melhor.
Reduzir custoModelo menor para triagem (mini/nano/flash-lite/haiku), caps, early exit e cache permitido pela política.
Minimizar latência em loop longo de toolsOpenAI: WebSocket mode da Responses API (conexão persistente, só itens novos + previous_response_id; ~40% em 20+ tool calls). Anthropic/Gemini: HTTP+SSE com stream, preâmbulo curto e prompt/context caching — não há WebSocket de inferência nesses dois. Ver linha Transporte na §8.
Fallback cross-vendor por classe (2026-07)Pares de equivalência aproximada de classe/custo: gpt-5.6-sol ↔ claude-opus-4-8 (frontier) · gpt-5.6-terra ↔ claude-sonnet-5/gemini-3.1-pro (workhorse) · gpt-5.6-luna/gpt-5.4-nano ↔ gemini-3.5-flash/-lite/haiku-4.5 (volume). Ressalvas: tokenizers diferentes (~±30% na contagem), reasoning/thinking não portável, tools built-in distintas — reveja caps e evals ao trocar, não só o preço.
diff --git a/references/agents_tools_best_guides/guia_token_counting.html b/references/agents_tools_best_guides/guia_token_counting.html index 0ca9b77..ffd06ee 100644 --- a/references/agents_tools_best_guides/guia_token_counting.html +++ b/references/agents_tools_best_guides/guia_token_counting.html @@ -544,7 +544,7 @@

Decisão rápida — qual ferramenta usar quando Sem tokenizer offlineSem tokenizer offline - Saber tokens de "raciocínio" (reasoning/thinking)output_tokens_details.reasoning_tokens (pós)thoughts_token_count (pós)usage da chamada com extended thinking + Saber tokens de "raciocínio" (reasoning/thinking)output_tokens_details.reasoning_tokens (pós)thoughts_token_count (pós)output_tokens_details.thinking_tokens (pós; desde 27/05/2026) Saber quanto foi servido do cacheinput_tokens_details.cached_tokenscached_content_token_countcache_read_input_tokens Contar tokens de tools/function schemasSim, em input_tokens.countSim, em count_tokensSim, em messages.count_tokens Imagens geradas (saída)Imagem & vídeo cobrados por API/duração, não via input_tokensImagem cobrada por imagem em Nano Banana; não via count_tokensNão gera imagens @@ -584,13 +584,21 @@

5.2 Campos no response (o que aparece onde) 27/05/2026 (já DENTRO de output_tokens; no streaming, só no message_delta final) Quebra por modalidadeSó agregadopromptTokensDetails[] com ModalityTokenCountSó agregado Tokens system-added (não cobrados)——Podem estar somados; explicitado nas docs +
A REGRA que evita custo errado (verificada nas 3 fontes, 2026-07-09): quem inclui o quê no output. +
    +
  • OpenAI: usage.output_tokens JÁ INCLUI reasoning (ex. oficial: output_tokens: 1186 com reasoning_tokens: 1024 dentro do details → 162 visíveis). Custo de output = output_tokens × preço. Somar reasoning_tokens por fora = contar 2× (superfatura).
  • +
  • Anthropic: usage.output_tokens JÁ INCLUI o thinking — e é o thinking FULL, mesmo com display: "summarized" ou "omitted" ("the billed output token count will not match the count of tokens you see"). Desde 27/05/2026 o breakdown vem em usage.output_tokens_details.thinking_tokens (streaming: só no message_delta final; sem beta header). Mesmo aviso: é breakdown, não parcela extra.
  • +
  • Gemini (generateContent): o inverso — candidatesTokenCount NÃO inclui os thoughts; thoughtsTokenCount é campo separado e totalTokenCount = prompt + thoughts + candidates (descrição oficial). Custo de output = (candidates + thoughts) × preço. Esquecer os thoughts = SUBfaturar (e a fatura do console não vai bater). Na Interactions API idem: total_thought_tokens separado de total_output_tokens.
  • +
+ Assimetria a memorizar: OpenAI/Anthropic = incluído (risco de dobrar); Gemini = separado (risco de faltar). Fontes: guia oficial de reasoning (OpenAI), release notes 27/05/2026 + extended thinking (Anthropic), referência UsageMetadata (Gemini).
+

5.3 Texto puro

@@ -5293,9 +5301,11 @@

10.1 Visão geral & decisão — qual mecanismo us
  • Pin de shard / cache resource. OpenAI: prompt_cache_key=hash(tenant+session) (cap ~15 RPM/key). Gemini/Vertex (implícito-only neste projeto): não há pin user-facing — o backend faz prefix-match oportunístico e cobra com desconto se bater. Anthropic: cache é determinístico por (workspace × prefix bytes × model). Detalhe em §10.8.
  • Serialização determinística. JSON com sort_keys=True para tools/schemas. Go map default e Swift Dictionary reorderam — quebra o hash silenciosamente.
  • Bytes idênticos em mídia. Imagens, áudio, vídeo, PDFs precisam ser byte-a-byte iguais. Re-encode, EXIF strip, recompressão JPEG = miss. OpenAI exige também input_image.detail constante entre requests. Detalhe em §10.9.
  • -
  • Model promotion = cache reset. Cache é por-modelo. gpt-5.5 → gpt-5.6 (família Sol/Terra/Luna, lançada 2026-07-09) = miss total. Pinar snapshot exato (ex.: gpt-5.5-2026-04-23, claude-opus-4-8) em produção sensível. Obs.: gpt-5.6+ traz caching explícito (prompt_cache_breakpoint, prompt_cache_options.mode, ttl mínimo 30m) e cobra escrita de cache a 1,25× o input — ver o guia de modelos OpenAI, §15.1.
  • +
  • Model promotion = cache reset. Cache é por-modelo. gpt-5.5 → gpt-5.6 (família Sol/Terra/Luna, lançada 2026-07-09) = miss total. Pinar snapshot exato (ex.: gpt-5.5-2026-04-23, claude-opus-4-8) em produção sensível. Obs.: gpt-5.6+ traz caching explícito (prompt_cache_breakpoint, prompt_cache_options.mode, ttl mínimo 30m) e cobra escrita de cache a 1,25× o input — ver o guia de modelos OpenAI, §15.3.
  • +
    Breakeven do write 1,25× (gpt-5.6+): a escrita custa +0,25× sobre o input do bloco cacheado; cada leitura posterior economiza 0,9× (paga 0,1× em vez de 1×). Logo, com R reusos do prefixo: custo com cache = 1,25 + 0,1·R vs sem cache = 1 + R → 1 único reuso já paga a escrita (2,0 > 1,35). O caso ruim é write sem nenhum reuso: +25% sobre aquele bloco (prêmio de 25%, não "+125%" — o 1,25× substitui o 1× do input, não soma). Regra prática: não marque breakpoint em prompt one-shot; monitore cache_write_tokens alto com cached_tokens baixo como sinal de writes desperdiçados.
    +
    Veja também. As subseções pré-existentes do guia cobrem mecânica básica de cada provider; este §10 consolida o que é cross-provider e o que é específico do modo stateless. Cross-links: §5.7 OpenAI cache (mecânica básica) · §Gemini context caching · §GTI cache implícito · §GTI Vertex/ZDR · §A.10 Anthropic cache (no count) · §A.17 Anthropic Bedrock/Vertex.
    @@ -6511,8 +6521,11 @@

    Emitter Python — cobre os 3 providers

    input_tokens_cached_read=read, input_tokens_cached_write_5m=write_5m, input_tokens_cached_write_1h=write_1h, - output_tokens_visible=out_tok, # Anthropic não separa thinking aqui - output_tokens_reasoning=0, # thinking somado em output_tokens com thinking.enabled + # Desde 27/05/2026 a Messages API SEPARA o breakdown: usage.output_tokens_details.thinking_tokens + # (no streaming, o breakdown vem SÓ no message_delta final; sem beta header). + # thinking_tok JÁ ESTÁ DENTRO de out_tok — é breakdown, NUNCA some de novo no custo. + output_tokens_visible=out_tok - thinking_tok, + output_tokens_reasoning=thinking_tok, # thinking_tok = getattr(u.output_tokens_details, "thinking_tokens", 0) or 0 output_tokens_rejected_pred=0, cost_usd=cost, provider_response_id=resp.id, ) @@ -6942,7 +6955,7 @@

    R5 · Logar reasoning em produção

    Cenário: entender por que a chamada custou 5× o esperado.

    • Sempre logue reasoning_tokens (OpenAI) / thoughts_token_count (Gemini).
    • -
    • Em Anthropic, log output_tokens com thinking.enabled: pico de output indica raciocínio longo.
    • +
    • Em Anthropic, log output_tokens E o breakdown output_tokens_details.thinking_tokens (desde 27/05/2026): pico de thinking_tokens indica raciocínio longo sem precisar inferir pelo total.
    • Configure alertas para razão reasoning/output_visible > 5.
    @@ -7211,7 +7224,7 @@

    Sumário para IA (JSON-LD) Fontes oficiais & verificação

    +
    rodada mega-relatório GPT-5.6 (curadoria Fable 5 + verificação na fonte oficial) — correção de preço: long context 5.6 (>272K) = 2× input e 1,5× output (Sol long $45, não $60) + tiers Batch/Flex 50% e Priority 2× (Sol $10/$60) e critério oficial do regional +10% (lançados ≥ 05/03/2026); nova §11.9 Programmatic Tool Calling (runtime V8 isolado, allowed_callers, output_schema, itens program/program_output, ZDR-ok) e callout multi-agente beta/"ultra" (custo = soma dos subagentes; ultra não é valor da API); §15.3 caching explícito enriquecido (slots de write no implicit, prompt_cache_retention deprecated em 5.6+, política por workflow) + breakeven do write 1,25× no token_counting (1 reuso paga a escrita); specs mini/nano (400K/128K, effort default none; nano sem computer_use/tool_search); pares de fallback cross-vendor; KPI custo por sucesso no guia de operação. E correção de contabilidade de reasoning (verificada nas 3 fontes): Anthropic passou a expor usage.output_tokens_details.thinking_tokens em 27/05/2026 (já DENTRO de output_tokens, que cobra o thinking FULL mesmo summarized/omitted; streaming: só no message_delta final) — guia dizia "não separa thinking"; OpenAI reasoning_tokens também é breakdown DENTRO de output_tokens (somar de novo = superfaturar); Gemini thoughtsTokenCount é SEPARADO de candidates (não somar = subfaturar) · 2026-07-09
    24 guias multi-provedor From a7712890e1127151276d707133deae0b16c40c10 Mon Sep 17 00:00:00 2001 From: Rafael Bittencourt Date: Thu, 9 Jul 2026 22:53:21 -0300 Subject: [PATCH 10/16] docs(openai-modelos): precisa nota long-context 5.6 (2x input/1.5x output for full session, texto oficial) + marca rateio cached/write por coluna como interpretacao - verificado 2026-07-09 --- references/agents_tools_best_guides/guia_openai_modelos.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/references/agents_tools_best_guides/guia_openai_modelos.html b/references/agents_tools_best_guides/guia_openai_modelos.html index d5085a9..a710f2e 100644 --- a/references/agents_tools_best_guides/guia_openai_modelos.html +++ b/references/agents_tools_best_guides/guia_openai_modelos.html @@ -451,7 +451,7 @@

    1. Catálogo de modelos

    - + @@ -461,7 +461,7 @@

    1. Catálogo de modelos

    Preços da família GPT-5.6 (USD por 1M tokens, short context ≤272K). Long context >272K de input: 2× no input e 1,5× no output, aplicados ao request inteiro (nota oficial da página do modelo). Verificado 2026-07-09.Preços da família GPT-5.6 (USD por 1M tokens, short context ≤272K). Long context >272K de input: 2× no input e 1,5× no output, aplicados à sessão inteira (texto oficial: 2x input and 1.5x output for the full session for standard, batch, and flex). Verificado 2026-07-09.
    ModeloInputCached input (−90%)Cache write (1,25×)Output
    gpt-5.6-sol$5,00$0,50$6,25$30,00
    -
    Long context e tiers de processamento (5.6): acima de 272K de input, o request inteiro é cobrado a 2× no lado do input (input, cached, write) e 1,5× no output — Sol long: $10 / $1 / $12,50 / $45; Terra: $5 / $0,50 / $6,25 / $22,50; Luna: $2 / $0,20 / $2,50 / $9. Batch e Flex = 50% do Standard (Sol $2,50/$15); Priority = 2× (Sol $10/$60) — o cache write escala junto com o tier. Regional/data residency: +10% para modelos lançados a partir de 05/03/2026 elegíveis a residência de dados (critério oficial — inclui a família 5.6 e os 5.4-mini/nano). Fonte: /pricing · página do modelo.
    +
    Long context e tiers de processamento (5.6): acima de 272K de input, a sessão inteira é cobrada a 2× no input e 1,5× no output — este é o texto literal da nota oficial (2x input and 1.5x output for the full session). Aplicando esse 2× a todo o lado do input, o Sol long fica: input $10 / cached $1 / write $12,50 / output $45; Terra: $5 / $0,50 / $6,25 / $22,50; Luna: $2 / $0,20 / $2,50 / $9. Ressalva: a nota oficial só especifica input e output; o rateio das colunas cached-input e cache-write pelo mesmo 2× é interpretação nossa (não está escrito por coluna) — confirme na fatura para cargas long-context intensivas em cache. Batch e Flex = 50% do Standard (Sol $2,50/$15); Priority = 2× (Sol $10/$60). Regional/data residency: +10% para modelos lançados a partir de 05/03/2026 elegíveis a residência de dados (critério oficial — inclui a família 5.6 e os 5.4-mini/nano). Fonte: /pricing · página do modelo.
    Nota: raciocínio mais alto não é automaticamente melhor. Com critérios de parada fracos ou acesso aberto a ferramentas, esforço alto pode levar a overthinking, buscas desnecessárias ou regressão de qualidade. Aumente o esforço só quando seus evals mostrarem ganho mensurável.
    From 606e2d31c29e37deb401acb19cf00d6705c61eba Mon Sep 17 00:00:00 2001 From: Rafael Bittencourt Date: Sun, 12 Jul 2026 18:43:18 -0300 Subject: [PATCH 11/16] docs(guias): freshness 2026-07-12 + 21 novas secoes SOTA (memory tool, context editing, skills API/plugins, evaluator-optimizer, parallelization, deepagents stream/delete, gemini live, mcp roots, compaction) --- .../guia_arquitetura_orquestracao.html | 161 +- .../guia_claude_api.html | 13555 ++++++++-------- ...guia_contexto_compactacao_estrategias.html | 196 + .../guia_deepagents.html | 358 +- .../guia_estado_contexto_memoria.html | 246 +- .../guia_ferramentas_mcp_rag.html | 14 +- .../guia_gemini_interactions_api.html | 9070 +++++------ .../guia_langgraph.html | 7984 ++++----- .../guia_langgraph_orquestracao.html | 1822 +-- .../guia_multimodal.html | 208 +- .../guia_openai_modelos.html | 12269 +++++++------- .../guia_providers_adapters.html | 1828 +-- .../agents_tools_best_guides/guia_skills.html | 260 +- 13 files changed, 25050 insertions(+), 22921 deletions(-) diff --git a/references/agents_tools_best_guides/guia_arquitetura_orquestracao.html b/references/agents_tools_best_guides/guia_arquitetura_orquestracao.html index 5e90475..3cbf4bd 100644 --- a/references/agents_tools_best_guides/guia_arquitetura_orquestracao.html +++ b/references/agents_tools_best_guides/guia_arquitetura_orquestracao.html @@ -5,7 +5,7 @@ Arquitetura & Orquestração de Agentes — Núcleo agnóstico - + + + + + + + LLM gerador + produz / refina a solução + + + LLM avaliador + avalia contra critério de aceite + + + Saída final + aceita pelo avaliador + + + + + aceito + rejeitado + feedback → nova rodada + +
    + O gerador produz; o avaliador decide aceitar ou pedir nova rodada com feedback específico; o + loop repete até o aceite ou até um teto de iterações imposto pelo runtime. +
    +
    + +
    + + + + + + +
    ElementoPapel no loop
    LLM geradorProduz a resposta inicial e cada refinamento subsequente, incorporando o feedback recebido na rodada anterior.
    LLM avaliadorExamina a resposta contra critérios de aceite explícitos e retorna aceite ou crítica específica e acionável.
    Critério de paradaAceite do avaliador — o runtime deve impor também um teto de iterações para evitar loop sem convergência.
    + +
    + Quando usar. A Anthropic aponta que o padrão é particularmente eficaz quando há + critérios de avaliação claros e quando o refinamento iterativo agrega valor + mensurável. O bom encaixe aparece quando as respostas do LLM melhoram de forma demonstrável + com feedback articulado e o próprio LLM consegue gerar esse feedback. Exemplos citados: + tradução literária, em que "there are nuances that the translator LLM might not capture + initially, but where an evaluator LLM can provide useful critiques"; e tarefas de busca + complexa que exigem múltiplas rodadas de pesquisa e análise, em que o avaliador decide se + novas buscas são necessárias. +
    +
    + Onde não vale a pena. Sem critério de aceite objetivo, o avaliador apenas + introduz latência e custo (duas chamadas por rodada) sem convergência garantida. Trate o + evaluator-optimizer como caso especial de separação generator-verifier: mantenha + os dois papéis com prompts/instruções distintos (idealmente modelos ou temperaturas diferentes) + para reduzir o viés de um único LLM validar o próprio output, e imponha o mesmo teto de iterações + e budget que qualquer outro loop do runtime (ver §7 e + §10). +
    + +

    4A.3.1 Parallelization: sectioning versus voting/consensus

    +

    + Parallelization é o padrão de workflow em que múltiplas chamadas de LLM trabalham + simultaneamente sobre uma tarefa e têm suas saídas agregadas de forma programática + (não por "mais uma chamada de LLM" solta). Ele tem duas variações com propósitos + distintos — confundi-las é o erro mais comum ao desenhar o padrão: sectioning quebra + a tarefa em subtarefas independentes executadas em paralelo; voting (consenso) + roda a mesma tarefa várias vezes para obter saídas diversas e agregá-las. +

    +
    + Não confundir com paralelismo de tool-calls. Esta seção trata do padrão + arquitetural de workflow (fan-out de chamadas de LLM + fan-in programático). O paralelismo de + ferramentas dentro de um único turno — protocolo por provider, scheduler, quais tools são + paralelas ou seriais — é assunto do + guia Paralelismo & tools. +
    +
    + + + + + + + + + + + + + + + +
    VarianteDefinição (Anthropic)Quando usarExemplos oficiais
    SectioningQuebrar uma tarefa em subtarefas independentes, cada uma rodando em paralelo numa chamada de LLM separada ("Breaking a task into independent subtasks run in parallel").A tarefa tem considerações distintas que ganham foco quando isoladas — LLMs geralmente performam melhor quando cada consideração é tratada por uma chamada de LLM separada — ou quando velocidade é o objetivo e as subtarefas podem rodar simultaneamente.Guardrails: uma instância de modelo processa a consulta do usuário enquanto outra, em paralelo, faz a triagem de conteúdo inadequado — separar as duas funções tende a performar melhor do que uma única chamada acumulando guardrail e resposta principal. Automatizar evals: cada chamada de LLM avalia um aspecto diferente do desempenho do modelo para um dado prompt.
    Voting / consensusRodar a mesma tarefa múltiplas vezes para obter saídas diversas ("Running the same task multiple times to get diverse outputs"), depois agregar por maioria, threshold ou síntese.A tarefa se beneficia de múltiplas perspectivas independentes para aumentar a confiança no resultado, ou quando é preciso equilibrar falsos positivos e negativos ajustando o threshold de votos.Revisão de código em busca de vulnerabilidades: vários prompts diferentes revisam e sinalizam o código quando encontram um problema. Moderação de conteúdo: avaliar se um conteúdo é inadequado usando múltiplos prompts que checam aspectos distintos ou exigem thresholds de votação diferentes, equilibrando falsos positivos e negativos.
    +

    + A escolha entre as duas não é estética: sectioning otimiza cobertura e latência + (subtarefas diferentes, sem redundância de trabalho); voting otimiza confiança e + robustez (mesma tarefa repetida, com redundância deliberada para reduzir variância e + capturar divergências entre execuções). Ambas exigem um passo de agregação determinístico e + auditável no orquestrador — nunca delegado a "mais uma chamada de LLM" sem critério explícito + de combinação (maioria simples, threshold configurável, união de achados, ou síntese com política + definida). +

    +
    + Antipadrão relacionado — "Paralelismo sem fase" (§10): + misturar sectioning e voting no mesmo boundary, ou paralelizar sem separar claramente a fase de + fan-out (disparo das chamadas) da fase de fan-in (agregação), gera resultados + inconsistentes e dificulta a auditoria — especialmente em voting, onde o critério de combinação dos + votos precisa ser registrado no ledger para permitir replay. +
    + + +

    Parte 2 — Contratos do runtime

    diff --git a/references/agents_tools_best_guides/guia_claude_api.html b/references/agents_tools_best_guides/guia_claude_api.html index 387fb8a..c358d85 100644 --- a/references/agents_tools_best_guides/guia_claude_api.html +++ b/references/agents_tools_best_guides/guia_claude_api.html @@ -1,6530 +1,7025 @@ - - - - - -Guia Claude API (Anthropic) — Referência completa · Opus 4.8 · Sonnet 5 · Haiku 4.5 - - - - - - - - -
    -
    -
    Guia Claude API Anthropic · PT-BR · Referência completa
    -
    - Verificado em 2026-07-05 - anthropic · @anthropic-ai/sdk - Opus 4.8 · Sonnet 5 · Haiku 4.5 - -
    -
    -
    - -
    - - -
    - -
    -

    Guia Claude API (Anthropic) — Referência completa

    -

    - Documentação técnica exaustiva, em português brasileiro, da API da Anthropic (Claude), - focada nos modelos gerais mais recentes — Claude Opus 4.8, Claude Sonnet 5 - e Claude Haiku 4.5 (com Sonnet 4.6 como legado ainda suportado). Cobre a Messages API, streaming (SSE), raciocínio - (adaptive & extended thinking), tool use (todas as ferramentas client- e server-side), - multimodal (visão, PDF, Files), prompt caching, context editing, batch, structured outputs, - citations, embeddings, Agent Skills, MCP, Managed Agents, a referência REST/SDK completa, - governança (Admin, WIF, rate limits, compliance) e execução nas plataformas de nuvem - (Amazon Bedrock, Google Vertex AI, Microsoft Foundry). -

    -
    - anthropic · Python ≥ 3.9 - @anthropic-ai/sdk · Node ≥ 20 - Opus 4.8 · Sonnet 5 · Haiku 4.5 - anthropic-version: 2023-06-01 - Verificado em 2026-07-05 -
    -
    - -
    -

    Sobre este guia

    -

    - Este é um guia técnico exaustivo, em português brasileiro, da API da Anthropic — - a interface para construir aplicações sobre os modelos Claude. O guia é deliberadamente restrito - aos modelos gerais mais recentes (Opus 4.8, Sonnet 5 e Haiku 4.5; Sonnet 4.6 consta como legado); modelos de - gerações anteriores foram omitidos por design. Para fatos perecíveis — IDs de modelo, preços, - limites, datas e headers beta — a documentação oficial em platform.claude.com é - sempre a fonte autoritativa. -

    -

    O conteúdo está organizado em seis partes e um apêndice:

    -
      -
    • Parte A — Fundamentos, Modelos & Mensagens: primeira chamada, autenticação, - SDKs, a tabela de modelos, a Messages API, streaming, stop_reason, structured outputs, - effort, janelas de contexto, embeddings e batch.
    • -
    • Parte B — Raciocínio, Caching, Contexto & Multimodal: adaptive e extended thinking, - prompt caching, context editing, compaction, visão, PDF, Files, citations e search results.
    • -
    • Parte C — Ferramentas, Skills & MCP: tool use ponta a ponta, todas as ferramentas - (bash, computer use, code execution, text editor, memory, web search/fetch, tool search), - recursos avançados, Agent Skills e Model Context Protocol (MCP).
    • -
    • Parte D — Referência REST/SDK, Agentes Gerenciados, Governança & Nuvem: - SDKs oficiais, o schema REST completo, Message Batches, Models/Files API, Managed Agents, - Admin/Compliance/WIF e execução em Bedrock/Vertex/Foundry.
    • -
    • Parte E — SDK Python (anthropic) em profundidade: clientes - síncrono/assíncrono e todas as opções de construtor, streaming, ferramentas como funções - (@beta_tool/tool_runner), batches, paginação, hierarquia de erros, - retries/timeouts, respostas cruas, tipos, logging, namespace beta e clientes de plataforma.
    • -
    • Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk) em profundidade: - runtimes suportados (Node, Deno, Bun, Workers, navegador), opções do cliente, streaming por - event handlers, helpers de ferramentas (Zod/JSON + ToolError) e de MCP, batches, - toFile, paginação, erros, retries/timeouts, respostas cruas, logging, proxies, namespace - beta e pacotes de plataforma.
    • -
    • Apêndice: cookbook (notebooks oficiais), glossário e histórico do guia.
    • -
    -
    - Como ler: cada capítulo expõe Python (anthropic), TypeScript - (@anthropic-ai/sdk) e REST/cURL em paralelo, preservando os exemplos oficiais. - Use o botão Tema no topo para alternar claro/escuro; o sumário à esquerda acompanha sua leitura. -
    -
    - Legível por humanos e por IA: o documento é um único HTML autossuficiente, com - âncoras estáveis por seção, tabelas semânticas e blocos de código rotulados por linguagem, - para ser facilmente indexado, citado e consumido por assistentes. -
    - -
    - Escopo e cobertura — o que é exaustivo vs. resumido (explícito): -
      -
    • Cobertura exaustiva: a Messages API e todos os recursos da API - (streaming, adaptive/extended thinking, prompt caching, context editing, multimodal, citations, - structured outputs, batch, embeddings, tool use e todas as ferramentas, Agent Skills, MCP), - mais o SDK Python (anthropic) e o - SDK JavaScript/TypeScript (@anthropic-ai/sdk) em profundidade — - tudo restrito aos modelos atuais (Opus 4.8, Sonnet 5, Haiku 4.5; Sonnet 4.6 legado).
    • -
    • Resumido (não detalhado página a página, com link canônico para aprofundar): - as subpáginas individuais de Managed Agents (cobertas em nível de - visão geral e superfície REST/governança, não uma a uma — veja a lista completa em - Fontes oficiais) e a integração legada do Amazon Bedrock - (InvokeModel/Converse; este guia foca a integração atual via Messages API) — - ver claude-on-amazon-bedrock-legacy.
    • -
    • Apenas referência (citados, não detalhados): os SDKs oficiais de - Java, Go, C#, Ruby e PHP — o foco deste guia é Python e JS/TS.
    • -
    • Fatos perecíveis: IDs de modelo, preços, limites e headers beta foram verificados - em 2026-06-10 contra platform.claude.com; para qualquer um deles a - documentação oficial ao vivo é sempre a fonte autoritativa.
    • -
    -
    -
    - -
    -

    TL;DR · Cartão de referência rápida

    - -

    Setup em 4 passos (do zero à primeira resposta)

    -
      -
    1. Obtenha uma chave de API: crie/entre numa conta e gere uma chave em - platform.claude.com/settings/keys - (Claude Console). Garanta que há crédito/billing ativo na organização.
    2. -
    3. Exporte a chave como variável de ambiente (os SDKs a leem automaticamente): -
      export ANTHROPIC_API_KEY="sua-chave-aqui" (Linux/macOS) · - setx ANTHROPIC_API_KEY "sua-chave-aqui" (Windows).
    4. -
    5. Instale o SDK: pip install anthropic (Python ≥ 3.9) ou - npm install @anthropic-ai/sdk (Node ≥ 20).
    6. -
    7. Faça a primeira chamada (código abaixo) e siga para - escolher o modelo e o SDK em profundidade: - Python ou JavaScript/TypeScript.
    8. -
    - -

    Referência rápida dos valores essenciais:

    -
    - - - - - - - - - - - -
    ItemValor
    Base URLhttps://api.anthropic.com
    Endpoint principalPOST /v1/messages
    AutenticaçãoHeader x-api-key: $ANTHROPIC_API_KEY
    Versão da APIHeader anthropic-version: 2023-06-01 (obrigatório)
    Features betaHeader anthropic-beta: <flag> (quando aplicável)
    SDK Pythonpip install anthropic · anthropic.Anthropic()
    SDK TypeScriptnpm install @anthropic-ai/sdk · new Anthropic()
    -
    -

    Modelos gerais atuais (detalhes e preços em A3. Modelos Claude):

    -
    - - - - - - - - -
    ModeloID de APIContextoSaída máx.RaciocínioMelhor para
    Claude Opus 4.8claude-opus-4-81M tokens128KAdaptive thinking + effortTarefas complexas, coding, agentes
    Claude Sonnet 5 recomendadoclaude-sonnet-51M tokens128KAdaptive thinking + effortEquilíbrio capacidade/custo (Sonnet atual)
    Claude Sonnet 4.6 Legacyclaude-sonnet-4-61M tokens128KeffortGeração Sonnet anterior (suportada)
    Claude Haiku 4.5claude-haiku-4-5200K tokens64KExtended thinkingBaixa latência e custo
    -
    -
    -
    - - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()  # lê ANTHROPIC_API_KEY do ambiente
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude!"}],
    -)
    -print(message.content[0].text)
    -
    -
    -
    import Anthropic from '@anthropic-ai/sdk';
    -
    -const client = new Anthropic(); // lê ANTHROPIC_API_KEY do ambiente
    -const message = await client.messages.create({
    -  model: 'claude-opus-4-8',
    -  max_tokens: 1024,
    -  messages: [{ role: 'user', content: 'Olá, Claude!' }],
    -});
    -console.log(message.content[0].text);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{"role": "user", "content": "Olá, Claude!"}]
    -  }'
    -
    -
    -
    - Política de modelos deste guia: citamos apenas os modelos gerais mais recentes - (Opus 4.8, Sonnet 5, Haiku 4.5), mantendo o Sonnet 4.6 como legado ainda suportado. Gerações anteriores foram intencionalmente omitidas. -
    -
    - -
    -

    Fontes oficiais

    -

    Este guia foi construído a partir da documentação oficial pública da Anthropic em - platform.claude.com/docs (verificada em 2026-06-10), do export - llms-full.txt e do repositório oficial de cookbooks. Sempre que houver divergência - entre este guia e a documentação em produção, a documentação oficial é a fonte autoritativa. - As 115 páginas oficiais consultadas:

    - - -
    - - - -
    -

    Parte A — Fundamentos, Modelos & API de Mensagens

    -

    Esta parte cobre o essencial para começar com a API da Anthropic: visão geral da plataforma, primeira chamada e autenticação, SDKs, a tabela definitiva dos modelos atuais (Claude Opus 4.8, Sonnet 4.6 e Haiku 4.5), a anatomia da API de Mensagens, geração de texto e streaming (SSE), o campo stop_reason, structured outputs, o parâmetro effort, fast mode, janelas de contexto e contagem de tokens, embeddings, suporte multilíngue e o processamento em lote (Message Batches API).

    -
    - - -
    -

    1. Visão geral da plataforma Claude & primeira chamada

    -

    Claude é a família de modelos de linguagem da Anthropic, com desempenho de ponta em linguagem, raciocínio, análise e coding. Há duas formas de construir com Claude, cada uma para um caso de uso diferente:

    - -
    - - - - - -
     Messages APIClaude Managed Agents
    O que éAcesso direto de prompting ao modeloHarness de agente pré-construído e configurável, executado em infraestrutura gerenciada
    Melhor paraLoops de agente customizados e controle finoTarefas de longa duração e trabalho assíncrono
    - -

    O caminho recomendado para um desenvolvedor novo é: (1) fazer a primeira chamada à API, (2) entender a Messages API, (3) escolher o modelo certo (ver seção 3), e (4) explorar ferramentas e recursos avançados.

    - -

    Autenticação e primeira chamada

    -

    A autenticação usa um cabeçalho x-api-key com sua chave do Claude Console, e todo request exige o cabeçalho de versão anthropic-version: 2023-06-01. A URL base é https://api.anthropic.com e o endpoint principal é POST /v1/messages.

    - -
    Dica: exporte a chave como variável de ambiente — export ANTHROPIC_API_KEY='sua-chave-aqui' — e adicione a linha ao seu perfil de shell (~/.zshrc ou ~/.bashrc) para persistir entre sessões. Os SDKs leem essa variável automaticamente.
    - -
    -
    - - - -
    -
    -
    import anthropic
    -
    -# Lê ANTHROPIC_API_KEY do ambiente automaticamente
    -client = anthropic.Anthropic()
    -
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1000,
    -    messages=[
    -        {
    -            "role": "user",
    -            "content": "O que devo pesquisar para achar avanços recentes em energia renovável?",
    -        }
    -    ],
    -)
    -print(message.content[0].text)
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic();
    -
    -const message = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1000,
    -  messages: [
    -    {
    -      role: "user",
    -      content: "O que devo pesquisar para achar avanços recentes em energia renovável?",
    -    },
    -  ],
    -});
    -console.log(message.content);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1000,
    -    "messages": [
    -      {"role": "user", "content": "O que devo pesquisar para achar avanços recentes em energia renovável?"}
    -    ]
    -  }'
    -
    -
    - -

    A resposta é um objeto message com id, role: "assistant", um array content de blocos (aqui um bloco text), o model usado, o stop_reason (ver seção 6) e o objeto usage com input_tokens / output_tokens:

    - -
    Resposta JSON (200) -
    {
    -  "id": "msg_01HCDu5LRGeP2o7s2xGmxyx8",
    -  "type": "message",
    -  "role": "assistant",
    -  "content": [
    -    { "type": "text", "text": "Aqui estão estratégias de busca eficazes..." }
    -  ],
    -  "model": "claude-opus-4-8",
    -  "stop_reason": "end_turn",
    -  "stop_sequence": null,
    -  "usage": { "input_tokens": 21, "output_tokens": 305 }
    -}
    -
    - - -
    - - -
    -

    2. SDKs & instalação (visão rápida)

    -

    A Anthropic mantém SDKs oficiais em Python, TypeScript, Java, Go, Ruby, C# e PHP, além de uma CLI (ant). Esta seção cobre o mínimo para rodar; a referência completa de SDKs está na Parte D.

    - -
    - - - - - - -
    LinguagemPacoteInstalaçãoVersão mínima
    Pythonanthropicpip install anthropicPython 3.9+
    TypeScript@anthropic-ai/sdknpm install @anthropic-ai/sdkTS 4.9+ / Node 20+
    CLIantbrew install anthropics/tap/ant—
    - -

    Em Python o cliente é anthropic.Anthropic() (síncrono) ou anthropic.AsyncAnthropic() (assíncrono). Em TypeScript é new Anthropic(). Ambos leem ANTHROPIC_API_KEY do ambiente; alternativamente passe api_key=... / { apiKey: ... } no construtor. Recursos beta são acessados pelo namespace beta (ex.: client.beta.messages.create(..., betas=["nome-da-feature"])).

    - -
    Nota: os SDKs oferecem retries e tratamento de timeouts embutidos. Para max_tokens altos, prefira o modo streaming (ver seção 5) para evitar timeouts de HTTP.
    - - -
    - - -
    -

    3. Modelos Claude (Opus 4.8 · Sonnet 5 · Haiku 4.5)

    -

    Esta é a seção canônica de modelos do guia — as demais partes a referenciam. A geração atual de uso geral é Opus 4.8, Sonnet 5 e Haiku 4.5. Use apenas estes IDs em código novo; claude-sonnet-4-6 passou a Legacy (ainda funcional e suportado) com a chegada do Sonnet 5.

    - -
    Novo (2026-06-30): Claude Sonnet 5. A Anthropic lançou Claude Sonnet 5 (claude-sonnet-5) em GA em 2026-06-30. Ele substitui o Sonnet 4.6 como o modelo Sonnet recomendado e é o default para os planos Free/Pro no claude.ai; disponível também em Claude API, Claude Code, Amazon Bedrock, Vertex AI e Microsoft Foundry. Contexto de 1M tokens, saída máxima de 128k, adaptive thinking ligado por padrão (thinking.type:"adaptive" é o default; enabled manual retorna 400 — para desligar use thinking:{"type":"disabled"}), suporta os 5 níveis de effort (low·medium·high·xhigh·max) — inclusive max, o nível mais alto (xhigh não é o teto). Usa o tokenizer novo (geração pós-4.7). Cutoff confiável Jan 2026. Na doc oficial, o Sonnet 4.6 foi movido para "Legacy models" (segue suportado). news/claude-sonnet-5 · models/overview
    - -
    Checklist de migração claude-sonnet-4-6 → claude-sonnet-5 (trocar o ID não é drop-in — há mudanças de comportamento que falham/silenciam sem aviso): -
      -
    1. Thinking manual quebra: thinking:{type:"enabled", budget_tokens:N} retorna 400 no Sonnet 5. Troque por thinking:{type:"adaptive"} + output_config.effort (ou {type:"disabled"}).
    2. -
    3. Sampling params quebram: temperature/top_p/top_k não-default retornam 400 (em toda requisição). Remova-os e controle variedade por prompting.
    4. -
    5. Raciocínio some da UI (silencioso): thinking.display passa a "omitted" por padrão — se sua UI mostra o raciocínio, defina display:"summarized" explicitamente.
    6. -
    7. Tokenizer novo (~30% mais tokens): revise/aumente max_tokens para não truncar (stop_reason:"max_tokens"), sobretudo em high/xhigh/max.
    8. -
    9. Recalibre effort: Sonnet 5 em medium ≈ Sonnet 4.6 em high — geralmente dá para baixar um nível e economizar.
    10. -
    11. Custo: preço intro $2/$10 até 31/08/2026 (depois $3/$15) — re-baseie projeções considerando a data-limite e o tokenizer.
    12. -
    -
    - -

    Tabela comparativa

    -
    - - - - - - - - - - - - - - - - -
    CaracterísticaClaude Opus 4.8Claude Sonnet 5Claude Sonnet 4.6 LegacyClaude Haiku 4.5
    DescriçãoO modelo GA mais capaz, para raciocínio complexo e coding agênticoA melhor combinação de velocidade e inteligência (Sonnet recomendado)Geração Sonnet anterior — legada, ainda suportadaO modelo mais rápido, com inteligência quase de fronteira
    ID de APIclaude-opus-4-8claude-sonnet-5claude-sonnet-4-6claude-haiku-4-5
    Snapshot fixoclaude-opus-4-8 o ID puro já é o snapshot (geração 4.6+)claude-sonnet-5 o ID puro já é o snapshotclaude-sonnet-4-6 o ID puro já é o snapshot (geração 4.6+)claude-haiku-4-5-20251001 alias: claude-haiku-4-5
    Janela de contexto1M tokens1M tokens1M tokens200k tokens
    Máx. de saída (Messages API)128k tokens128k tokens128k tokens64k tokens
    ModalidadesTexto + imagem → texto; PDFTexto + imagem → texto; PDFTexto + imagem → texto; PDFTexto + imagem → texto; PDF
    Adaptive thinkingSim (modo recomendado)Sim (default ligado)SimNão
    Extended thinking (manual)NãoNãoSimSim
    effortlow·medium·high·xhigh·maxlow·medium·high·xhigh·maxlow·medium·high·maxNão suportado
    Latência comparativaModeradaRápidaRápidaA mais rápida
    Knowledge cutoff (confiável)Jan 2026Jan 2026Ago 2025Fev 2025
    - -
    - IDs dateless são snapshots fixos (geração 4.6+). A partir da geração 4.6, o ID - sem data — claude-opus-4-8, claude-sonnet-4-6 — é o snapshot - canônico e imutável: ele mapeia para um único conjunto de pesos fixos e não é um - ponteiro evergreen. Uma versão atualizada sempre sai sob um ID novo. Modelos de gerações anteriores - (como o Haiku 4.5) trazem a data no ID — claude-haiku-4-5-20251001 — e - expõem um alias curto (claude-haiku-4-5) que resolve para o snapshot datado mais recente - daquela versão menor. Os pesos são fixos por ID, mas a infraestrutura de serviço (roteador, classificadores, - sampling) pode evoluir e causar diferenças mínimas de comportamento. - model-ids-and-versions -
    - -

    Preços por MTok (milhão de tokens, USD)

    -

    Todos os preços abaixo são da API de primeira parte (Claude API), em rota global (padrão). A janela completa de 1M tokens (Opus 4.8, Sonnet 5 e Sonnet 4.6) é cobrada na mesma taxa por token em todo o contexto — um request de 900k tokens custa por token o mesmo que um de 9k.

    -
    - - - - - - - - - -
    ModeloEntradaSaídaCache write 5mCache write 1hCache hit (leitura)
    Claude Opus 4.8$5$25$6.25$10$0.50
    Claude Sonnet 5 intro$2 → $3$10 → $15$2.50$4$0.20
    Claude Sonnet 4.6 Legacy$3$15$3.75$6$0.30
    Claude Haiku 4.5$1$5$1.25$2$0.10
    -
    Sonnet 5 — preço introdutório. Até 2026-08-31, o claude-sonnet-5 tem preço promocional de $2 / $10 por MTok (entrada/saída); a partir de 2026-09-01 passa ao preço padrão de $3 / $15 (mesma faixa do Sonnet 4.6). As colunas de cache acima usam o preço padrão como base ($3 de entrada). Confirme sempre em pricing antes de projetar custo. pricing
    -

    O cache write de 5 minutos custa 1,25× o preço de entrada base; o de 1 hora custa 2×; a leitura de cache (hit) custa 0,1× (10%) do preço de entrada. Pela Batch API os tokens saem com 50% de desconto (ver seção 12):

    -
    - - - - - - - -
    ModeloBatch entradaBatch saída
    Claude Opus 4.8$2.50$12.50
    Claude Sonnet 5 (preço padrão)$1.50$7.50
    Claude Sonnet 4.6 Legacy$1.50$7.50
    Claude Haiku 4.5$0.50$2.50
    - -
    Atenção (tokenizer): Opus 4.7, Opus 4.8, Sonnet 5 e Fable 5 usam um tokenizer novo em relação a gerações anteriores (Opus 4.6 e Sonnet 4.6 mantêm o antigo), o que contribui para o desempenho — mas produz mais tokens para o mesmo texto (~1,0–1,35× conforme o texto; da ordem de ~30% a mais nos piores casos). Recalibre max_tokens e re-baseie estimativas de custo ao migrar (inclusive ao trocar Sonnet 4.6 → Sonnet 5); a API de token counting aceita model:"claude-sonnet-5" ou model:"claude-fable-5" para medir com o novo tokenizer.
    - -
    Opus 4.8 — atual e recomendado (verificado 2026-06-03): o claude-opus-4-8 é o Opus atual e sucessor direto do 4.7 (agora Legacy). As specs centrais são idênticas às do 4.7 (confirmado em models/overview): janela de 1M tokens, saída de 128k, adaptive thinking (sem extended), preço $5 / $25 por MTok. Diferença de comportamento: no 4.8 o effort assume high por padrão em todas as superfícies (Claude API e Claude Code) — defina-o explicitamente para usar outro nível. O suporte a ferramentas e headers beta (computer use, code execution, web fetch, fast mode, inference_geo) é herdado da superfície do 4.7; para betas de borda, confirme sempre na documentação oficial.
    - -
    Atualização 2026-07-05: a Anthropic lançou o Claude Fable 5 (claude-fable-5, GA em 2026-06-09) — o modelo mais capaz amplamente lançado da Anthropic: $10 / $50 por MTok, contexto de 1M tokens, saída máxima de 128k e adaptive thinking sempre ativo — thinking: {"type": "disabled"}, budget manual (enabled + budget_tokens) e prefill do turno assistant retornam 400; thinking.display assume "omitted" por padrão. Usa o tokenizer do Opus 4.7 (~30% mais tokens que gerações pré-4.7 para o mesmo texto), traz classificadores de segurança com stop_reason: "refusal" (sem cobrança se nada for gerado — política de toda a Claude API desde 02/06/2026, não exclusiva do Fable 5) e o parâmetro fallbacks Beta, exige retenção de 30 dias (não elegível a ZDR) e tem cache mínimo de 512 tokens. Disponibilidade: o Fable 5 (e o Mythos 5) ficaram suspensos globalmente entre 12/06 e 30/06/2026 por controles de exportação dos EUA; a exigência de licença foi retirada em 30/06 e o modelo foi reimplantado ("redeployed") a partir de 01/07/2026 com um classificador de segurança reforçado (requests bloqueados são redirecionados automaticamente para o Opus 4.8). Model ID, preço e specs permanecem os mesmos — confirme o status atual em models/overview. O Claude Mythos 5 (claude-mythos-5) está em disponibilidade limitada. O Opus 4.8 segue ativo e recomendado como o modelo mais capaz; o Sonnet 5 (GA 2026-06-30) é agora o Sonnet recomendado (ver callout acima), com Sonnet 4.6 rebaixado a Legacy e Haiku 4.5 para baixa latência. Deprecações: Sonnet 4 e Opus 4 aposentam em 2026-06-15; Opus 4.1 (anúncio de 2026-06-05) aposenta em 2026-08-05. Desde 2026-05-27, a API reporta usage.output_tokens_details.thinking_tokens no message_delta final. - models/overview · redeploying-fable-5 · model-deprecations -
    - -

    Quando usar cada modelo

    -
      -
    • Opus 4.8 — tarefas complexas, raciocínio profundo e coding agêntico de longo horizonte. Comece com effort: "xhigh" para coding/agentes; é o padrão recomendado para os casos mais difíceis.
    • -
    • Sonnet 5 recomendado — equilíbrio de velocidade, custo e inteligência para a maioria das cargas de produção (coding, agentes, fluxos enterprise); é o Sonnet atual e sucessor do 4.6. Adaptive thinking vem ligado por padrão; defina effort explicitamente (todos os 5 níveis, low…max) conforme o trade-off latência/qualidade. Ao migrar do 4.6, recalibre o effort: segundo a Anthropic, Sonnet 5 em medium ≈ Sonnet 4.6 em high, e Sonnet 5 em high ≈ Sonnet 4.6 em max — ou seja, você pode baixar um nível e manter qualidade equivalente, reduzindo custo/latência.
    • -
    • Sonnet 4.6 Legacy — geração Sonnet anterior, ainda funcional e suportada; prefira o Sonnet 5 em código novo. Migração é trocar o ID (claude-sonnet-4-6 → claude-sonnet-5) — reveja max_tokens por causa do tokenizer novo e note que thinking.display passa a "omitted" por padrão no Sonnet 5.
    • -
    • Haiku 4.5 — baixa latência e baixo custo: classificação, lookups rápidos, subagentes e volumes altos onde ganhos marginais de qualidade não compensam latência/custo.
    • -
    - -

    Aliases vs. snapshots & política de deprecação

    -

    Todo ID de modelo identifica um snapshot fixo: enquanto o ID existir, os pesos não mudam. A partir da geração 4.6 os IDs adotam um formato sem data (claude-{nome}-{maior}-{menor}, ex.: claude-sonnet-4-6, claude-opus-4-8) que ainda assim é um snapshot fixo — não um ponteiro "evergreen". Quando há uma versão atualizada, ela é lançada sob um novo ID.

    -
    Nota: em modelos anteriores à 4.6, IDs incluíam a data (claude-haiku-4-5-20251001) e havia aliases de conveniência (ex.: claude-haiku-4-5) que apontavam para o snapshot datado mais recente. Para 4.6+, o ID sem data é o snapshot — não é um alias. Por isso, na tabela acima, Sonnet 4.6 não tem ID datado separado.
    -

    Os pesos do modelo são fixos por ID, mas a infraestrutura de serviço (roteador, classificadores de segurança, lógica de sampling) pode mudar; isso ocasionalmente produz pequenas diferenças observáveis mesmo com ID e pesos inalterados. Cada ID tem seu próprio cronograma de deprecação e retirada — consulte a página de model deprecations antes de migrar.

    - - -
    - - -
    -

    3.1 Endpoint Models API (descoberta programática)

    -

    A Models API permite listar os modelos disponíveis e resolver um alias para um ID, retornando limites e capacidades de cada modelo. É útil para roteamento dinâmico e para descobrir features suportadas em runtime, sem hard-coding.

    - -
    - - - - - -
    OperaçãoMétodo / rotaDescrição
    List ModelsGET /v1/modelsLista modelos (mais recentes primeiro). Paginação por after_id/before_id, limit 1–1000 (padrão 20).
    Get a ModelGET /v1/models/{model_id}Retorna info de um modelo específico; aceita ID ou alias.
    - -

    Cada item (ModelInfo) traz: id, display_name, created_at (RFC 3339), type: "model", e os campos-chave para roteamento:

    -
      -
    • max_input_tokens — tamanho máximo da janela de contexto de entrada.
    • -
    • max_tokens — valor máximo do parâmetro max_tokens para esse modelo.
    • -
    • capabilities — objeto com flags { supported: boolean } por capacidade: batch, citations, code_execution, image_input, pdf_input, structured_outputs, context_management (com estratégias datadas), effort (níveis low/medium/high/xhigh/max) e thinking (tipos adaptive e enabled).
    • -
    - -
    -
    - - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -
    -# Lista modelos (paginação automática)
    -for model in client.models.list(limit=20):
    -    print(model.id, model.display_name)
    -
    -# Resolve um alias / inspeciona limites e capacidades
    -info = client.models.retrieve("claude-opus-4-8")
    -print(info.max_input_tokens, info.max_tokens)
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic();
    -
    -for await (const model of client.models.list({ limit: 20 })) {
    -  console.log(model.id, model.display_name);
    -}
    -
    -const info = await client.models.retrieve("claude-opus-4-8");
    -console.log(info.max_input_tokens, info.max_tokens);
    -
    -
    -
    curl https://api.anthropic.com/v1/models \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "x-api-key: $ANTHROPIC_API_KEY"
    -
    -curl https://api.anthropic.com/v1/models/claude-opus-4-8 \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "x-api-key: $ANTHROPIC_API_KEY"
    -
    -
    - - -
    - - -
    -

    4. API de Mensagens — anatomia

    -

    A Messages API (POST /v1/messages) é o coração da integração. Os parâmetros centrais de um request são:

    -
    - - - - - - - - - - -
    ParâmetroTipoDescrição
    modelstring (obrigatório)ID do modelo (ex.: claude-opus-4-8).
    max_tokensinteger (obrigatório)Máximo de tokens a gerar. Limitado pelo max_tokens do modelo (ver seção 3).
    messagesarray (obrigatório)Histórico de turnos. Cada item tem role (user ou assistant) e content (string ou array de blocos).
    systemstring ou arrayPrompt de sistema — instruções, persona, regras. Não é um turno de messages; é um campo de topo.
    temperaturenumber (0–1)Aleatoriedade da amostragem. Mais baixo → mais determinístico. ⚠️ Depreciado em Opus 4.7/4.8 e Fable 5 — ver aviso abaixo.
    stop_sequencesarray de stringsSequências que, ao serem geradas, encerram a resposta (stop_reason: "stop_sequence").
    streambooleantrue para streaming via SSE (ver seção 5).
    - -

    Conversas multiturno (API stateless)

    -

    A Messages API é stateless: você sempre envia o histórico completo a cada chamada. Para continuar uma conversa, anexe a resposta do assistant e o novo turno do user ao array messages. Turnos anteriores não precisam ter vindo de fato do Claude — você pode inserir mensagens assistant sintéticas.

    - -
    -
    - - - -
    -
    -
    message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    system="Você é um tutor paciente de física.",
    -    messages=[
    -        {"role": "user", "content": "Olá, Claude"},
    -        {"role": "assistant", "content": "Olá! Como posso ajudar?"},
    -        {"role": "user", "content": "Você pode me descrever LLMs?"},
    -    ],
    -)
    -print(message.content[0].text)
    -
    -
    -
    const message = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  system: "Você é um tutor paciente de física.",
    -  messages: [
    -    { role: "user", content: "Olá, Claude" },
    -    { role: "assistant", content: "Olá! Como posso ajudar?" },
    -    { role: "user", content: "Você pode me descrever LLMs?" },
    -  ],
    -});
    -console.log(message.content[0].text);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "system": "Você é um tutor paciente de física.",
    -    "messages": [
    -      {"role": "user", "content": "Olá, Claude"},
    -      {"role": "assistant", "content": "Olá! Como posso ajudar?"},
    -      {"role": "user", "content": "Você pode me descrever LLMs?"}
    -    ]
    -  }'
    -
    -
    - -

    Prefill ("colocando palavras na boca do Claude")

    -

    Historicamente, era possível pré-preencher o início da resposta colocando uma mensagem assistant na última posição de messages para moldar a saída (ex.: forçar um formato).

    -
    Cuidado: o prefill não é suportado em claude-opus-4-8 nem em claude-sonnet-4-6 — requests com prefill nesses modelos retornam erro 400. Para moldar o formato da resposta, use structured outputs (JSON outputs) ou instruções no system prompt.
    - -

    Entradas de visão (resumo)

    -

    Os blocos de content podem ser de tipo image além de text. A fonte da imagem pode ser base64, url ou file (referência a um arquivo da Files API). Tipos de mídia suportados: image/jpeg, image/png, image/gif, image/webp. O detalhamento de visão, PDFs e Files API está na Parte B.

    - - -
    - - -
    -

    5. Geração de texto & streaming (SSE)

    -

    Com "stream": true, a resposta é entregue incrementalmente via Server-Sent Events (SSE). Os SDKs oferecem helpers idiomáticos: em Python, client.messages.stream(...) com iteração sobre stream.text_stream; em TypeScript, o método .stream({...}) com o evento .on("text", ...).

    - -
    Transporte: a Messages API usa HTTP request-response; o streaming é SSE (stream: true) sobre a mesma conexão HTTP — um único endpoint (POST /v1/messages) atende mensagens, tools, thinking e caching, mudando só o corpo. Não há transporte WebSocket para a Messages API. WebSocket aparece apenas no transporte de servidores MCP (streamable-HTTP/WebSocket), uma camada de ferramentas separada da chamada ao modelo.
    - -
    -
    - - - -
    -
    -
    with client.messages.stream(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá"}],
    -) as stream:
    -    for text in stream.text_stream:
    -        print(text, end="", flush=True)
    -
    -    # Acumula tudo e retorna o Message completo (igual ao .create())
    -    final = stream.get_final_message()
    -
    -
    -
    const stream = client.messages.stream({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: "Olá" }],
    -});
    -
    -for await (const event of stream) {
    -  if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
    -    process.stdout.write(event.delta.text);
    -  }
    -}
    -
    -const final = await stream.finalMessage();
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "messages": [{"role": "user", "content": "Olá"}],
    -    "max_tokens": 256,
    -    "stream": true
    -  }'
    -
    -
    - -
    Dica: mesmo quando você não precisa processar texto incremental, use streaming para requests com max_tokens grande. get_final_message() (Python) / finalMessage() (TS) mantêm a conexão HTTP viva e acumulam tudo, evitando timeouts.
    - -

    Fluxo e tipos de eventos

    -

    Cada SSE traz um nome de evento (event: ...) e dados JSON com um campo type correspondente. O fluxo de um stream é:

    -
      -
    1. message_start — objeto Message com content vazio.
    2. -
    3. Uma série de blocos de conteúdo, cada um com content_block_start → um ou mais content_block_delta → content_block_stop. Cada bloco tem um index que corresponde à sua posição no array content final.
    4. -
    5. Um ou mais message_delta — mudanças de topo no Message (ex.: stop_reason, usage).
    6. -
    7. Um message_stop final.
    8. -
    -

    Podem aparecer eventos ping em qualquer ponto, e eventos error (ex.: overloaded_error, equivalente a HTTP 529 fora do streaming). Conforme a política de versionamento, novos tipos de evento podem surgir — trate tipos desconhecidos com tolerância.

    - -
    - - - - - - - -
    Tipo de deltaEm que blocoObservação
    text_deltatextFragmento de texto: {"type":"text_delta","text":"olá frien"}.
    input_json_deltatool_useFragmentos parciais de JSON no campo partial_json; acumule e parseie ao receber content_block_stop.
    thinking_deltathinkingConteúdo de raciocínio (extended/adaptive thinking).
    signature_deltathinkingAssinatura criptográfica enviada antes do content_block_stop, verifica a integridade do bloco de thinking.
    - -
    Atenção: os contadores em usage dentro de eventos message_delta são cumulativos. O stop_reason é null em message_start e só aparece preenchido em message_delta.
    - -
    Exemplo de stream SSE completo -
    event: message_start
    -data: {"type":"message_start","message":{"id":"msg_...","type":"message","role":"assistant","content":[],"model":"claude-opus-4-8","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":25,"output_tokens":1}}}
    -
    -event: content_block_start
    -data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
    -
    -event: ping
    -data: {"type":"ping"}
    -
    -event: content_block_delta
    -data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Olá"}}
    -
    -event: content_block_stop
    -data: {"type":"content_block_stop","index":0}
    -
    -event: message_delta
    -data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":15}}
    -
    -event: message_stop
    -data: {"type":"message_stop"}
    -
    - - -
    - - -
    -

    6. O campo stop_reason

    -

    Toda resposta bem-sucedida da Messages API inclui stop_reason, indicando por que o Claude parou de gerar. Ao contrário de erros (que indicam falhas no request), stop_reason faz parte de uma resposta válida. Sempre cheque esse campo na sua lógica de tratamento.

    - -
    - - - - - - - - - - -
    ValorSignificadoComo tratar
    end_turnClaude terminou naturalmente (o mais comum).Processe a resposta completa.
    max_tokensAtingiu o limite de max_tokens do request — resposta truncada.Reenvie com max_tokens maior, ou continue a geração.
    stop_sequenceEncontrou uma das suas stop_sequences personalizadas.O campo stop_sequence indica qual sequência disparou.
    tool_useClaude está chamando uma ferramenta e espera que você a execute.Execute a ferramenta e devolva o tool_result (ver Parte C).
    pause_turnO loop de sampling do servidor atingiu o limite de iterações ao executar server tools (web search/fetch). Padrão: 10 iterações.Continue a conversa reenviando a resposta como está (anexe o assistant e chame de novo).
    refusalClaude recusou por motivos de segurança.HTTP 200, mas a saída pode não seguir o schema. Reformule o pedido.
    model_context_window_exceededAtingiu o limite da janela de contexto do modelo antes do max_tokens.A resposta é válida, mas limitada pela janela. Veja a nota abaixo.
    - -
    Nota: model_context_window_exceeded está disponível por padrão em modelos Claude 4.5 e mais recentes. Em modelos anteriores, habilite com o header beta model-context-window-exceeded-2025-08-26. Ele permite pedir o máximo possível de tokens sem conhecer o tamanho exato da entrada.
    - -

    Pegadinha — respostas vazias com end_turn: às vezes o Claude retorna conteúdo vazio (2–3 tokens) com end_turn, tipicamente após tool_result. Causas comuns: (1) adicionar um bloco text logo após um tool_result (o Claude aprende a esperar input do usuário após cada uso de ferramenta), e (2) reenviar a resposta já concluída sem nada novo. Soluções: nunca adicione texto imediatamente após tool_result; e, se persistir, anexe um novo turno user ("Por favor, continue") em vez de reenviar a resposta vazia.

    - -
    -
    - - -
    -
    -
    def handle_response(response):
    -    if response.stop_reason == "tool_use":
    -        return handle_tool_use(response)
    -    elif response.stop_reason in ("max_tokens", "model_context_window_exceeded"):
    -        return handle_truncation(response)
    -    elif response.stop_reason == "pause_turn":
    -        return handle_pause(response)
    -    elif response.stop_reason == "refusal":
    -        return handle_refusal(response)
    -    else:  # end_turn e demais
    -        return response.content[0].text
    -
    -
    -
    function handleResponse(response) {
    -  switch (response.stop_reason) {
    -    case "tool_use": return handleToolUse(response);
    -    case "max_tokens":
    -    case "model_context_window_exceeded": return handleTruncation(response);
    -    case "pause_turn": return handlePause(response);
    -    case "refusal": return handleRefusal(response);
    -    default: { // end_turn e demais
    -      const block = response.content.find((b) => b.type === "text");
    -      return block?.text;
    -    }
    -  }
    -}
    -
    -
    - -
    Dica: em streaming, stop_reason é null no message_start e é fornecido no message_delta (não em outros eventos). Ao truncar por max_tokens durante tool_use, verifique se o último bloco é um tool_use incompleto e reenvie com max_tokens maior.
    - - -
    - - -
    -

    7. Structured outputs GA

    -

    Structured outputs restringem a resposta do Claude a um schema, garantindo saída válida e parseável via constrained decoding. São dois recursos complementares, usáveis isolada ou conjuntamente:

    -
      -
    • JSON outputs (output_config.format): força a resposta em um formato JSON específico (o que o Claude diz).
    • -
    • Strict tool use (strict: true em uma ferramenta): garante validação de schema nos nomes e inputs de ferramentas (como o Claude chama suas funções).
    • -
    - -
    Nota: GA na Claude API para Claude Opus 4.8, Sonnet 4.6 e Haiku 4.5 (entre outros). O antigo parâmetro beta output_format migrou para output_config.format e o header beta não é mais necessário — o caminho antigo segue funcionando por um período de transição.
    - -

    JSON outputs

    -

    Defina um JSON Schema e inclua-o em output_config.format com type: "json_schema". A resposta vem como JSON válido em response.content[0].text.

    - -
    -
    - - - -
    -
    -
    response = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Extraia os dados deste e-mail: John Smith (john@example.com), interesse no plano Enterprise, quer demo terça às 14h."}],
    -    output_config={
    -        "format": {
    -            "type": "json_schema",
    -            "schema": {
    -                "type": "object",
    -                "properties": {
    -                    "name": {"type": "string"},
    -                    "email": {"type": "string"},
    -                    "plan_interest": {"type": "string"},
    -                    "demo_requested": {"type": "boolean"},
    -                },
    -                "required": ["name", "email", "plan_interest", "demo_requested"],
    -                "additionalProperties": False,
    -            },
    -        }
    -    },
    -)
    -print(response.content[0].text)  # JSON válido garantido
    -
    -
    -
    const response = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: "Extraia os dados deste e-mail: John Smith (john@example.com)..." }],
    -  output_config: {
    -    format: {
    -      type: "json_schema",
    -      schema: {
    -        type: "object",
    -        properties: {
    -          name: { type: "string" },
    -          email: { type: "string" },
    -          plan_interest: { type: "string" },
    -          demo_requested: { type: "boolean" },
    -        },
    -        required: ["name", "email", "plan_interest", "demo_requested"],
    -        additionalProperties: false,
    -      },
    -    },
    -  },
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  -H "content-type: application/json" \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -d '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{"role": "user", "content": "Extraia os dados deste e-mail..."}],
    -    "output_config": {
    -      "format": {
    -        "type": "json_schema",
    -        "schema": {
    -          "type": "object",
    -          "properties": {
    -            "name": {"type": "string"},
    -            "email": {"type": "string"},
    -            "plan_interest": {"type": "string"},
    -            "demo_requested": {"type": "boolean"}
    -          },
    -          "required": ["name", "email", "plan_interest", "demo_requested"],
    -          "additionalProperties": false
    -        }
    -      }
    -    }
    -  }'
    -
    -
    - -
    Dica: os SDKs têm helpers que aceitam definições nativas e validam automaticamente: em Python, client.messages.parse(..., output_format=ModeloPydantic) retorna response.parsed_output; em TypeScript, zodOutputFormat(schema) ou jsonSchemaOutputFormat(schema) com client.messages.parse(...).
    - -

    Strict tool use & uso combinado

    -

    Marque uma ferramenta com strict: true para que seus inputs sejam validados contra o input_schema por sampling guiado por gramática. JSON outputs e strict tool use resolvem problemas diferentes e funcionam juntos no mesmo request — útil em fluxos agênticos onde você precisa de chamadas de ferramenta confiáveis e de uma saída final estruturada.

    - -

    Limitações de JSON Schema & complexidade

    -

    Structured outputs suportam um subconjunto do JSON Schema. Recursos como enum (tipos simples), const, anyOf/allOf (com restrições), $ref/$defs internos, default, e formatos de string (date-time, date, email, uri, uuid, etc.) são suportados. Não são suportados: schemas recursivos, $ref externo, restrições numéricas (minimum/maximum/multipleOf), restrições de string (minLength/maxLength) e additionalProperties diferente de false. Usar um recurso não suportado gera erro 400.

    -
    - - - - - - -
    Limite explícitoValorDescrição
    Ferramentas strict por request20Máx. de tools com strict: true.
    Parâmetros opcionais24Total de parâmetros não-required em todos os schemas strict + JSON output.
    Parâmetros com union types16Total que usa anyOf ou arrays de tipo (custo de compilação exponencial).
    -

    Caching de gramática: a primeira request com um schema tem latência extra de compilação; gramáticas compiladas são cacheadas por 24h desde o último uso (mudanças em name/description não invalidam o cache, mas mudar a estrutura ou o conjunto de tools sim). Há um timeout de compilação de 180s.

    - -
    Atenção: structured outputs são incompatíveis com Citations (retorna 400 se combinado com output_config.format) e com prefilling de mensagem. São compatíveis com batch, token counting e streaming. Em ZDR, prompts/respostas não são retidos, mas o JSON schema é cacheado por até 24h — não inclua PHI/dados sensíveis em nomes de propriedade, enum, const ou pattern.
    - - -
    - - -
    -

    8. Effort & Fast mode

    -

    O parâmetro effort

    -

    O parâmetro effort (em output_config.effort) controla quão "disposto" o Claude está a gastar tokens, equilibrando completude e eficiência. Não exige header beta e afeta todos os tokens da resposta — texto, chamadas de ferramenta e o thinking (quando ativo). É suportado em Claude Opus 4.8 e Sonnet 4.6 (Haiku 4.5 não suporta).

    - -
    - - - - - - - - -
    NívelDescriçãoDisponível em
    maxCapacidade máxima absoluta, sem restrição de tokens.Opus 4.8, Sonnet 4.6
    xhighCapacidade estendida para trabalho de longo horizonte (agentes/coding > 30 min, budgets na casa dos milhões).Apenas Opus 4.8
    highAlta capacidade. Equivale a não setar o parâmetro (é o padrão da API).Todos os suportados
    mediumEquilíbrio com economia moderada de tokens.Todos os suportados
    lowMais eficiente; economia significativa com alguma redução de capacidade.Todos os suportados
    - -
    -
    - - - -
    -
    -
    response = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=4096,
    -    messages=[{"role": "user", "content": "Analise trade-offs entre microsserviços e monólito."}],
    -    output_config={"effort": "medium"},
    -)
    -print(response.content[0].text)
    -
    -
    -
    const response = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 4096,
    -  messages: [{ role: "user", content: "Analise trade-offs entre microsserviços e monólito." }],
    -  output_config: { effort: "medium" },
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 4096,
    -    "messages": [{"role": "user", "content": "Analise trade-offs entre microsserviços e monólito."}],
    -    "output_config": {"effort": "medium"}
    -  }'
    -
    -
    - -
    Dica: para Opus 4.8, comece em xhigh para coding/agentes e use high como mínimo para cargas sensíveis a inteligência; reserve max para problemas de fronteira. Para Sonnet 4.6, defina effort explicitamente (recomendado medium) — caso contrário pode haver latência inesperada. Em xhigh/max no Opus 4.8, dê um max_tokens generoso (comece em 64k).
    - -

    effort e thinking: em Opus 4.8 e Sonnet 4.6 o thinking é adaptativo (thinking: {type: "adaptive"}) e o effort é o controle recomendado da profundidade — no Opus 4.8, o thinking manual (type: "enabled", budget_tokens) não é mais suportado. effort também funciona sem thinking, controlando o gasto geral. (Detalhes de thinking na Parte B.)

    - -

    Fast mode Beta (research preview)

    -

    O fast mode entrega geração de tokens de saída até 2,5× mais rápida rodando o mesmo modelo com uma configuração de inferência mais veloz (mesmos pesos, mesma inteligência). Ativa-se com speed: "fast" e o header beta fast-mode-2026-02-01, via namespace beta. Suportado em Claude Opus 4.8.

    - -
    -
    - - - -
    -
    -
    response = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=4096,
    -    speed="fast",
    -    betas=["fast-mode-2026-02-01"],
    -    messages=[{"role": "user", "content": "Refatore este módulo para injeção de dependência"}],
    -)
    -print(response.usage.speed)  # "fast" ou "standard"
    -
    -
    -
    const response = await client.beta.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 4096,
    -  speed: "fast",
    -  betas: ["fast-mode-2026-02-01"],
    -  messages: [{ role: "user", content: "Refatore este módulo para injeção de dependência" }],
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "anthropic-beta: fast-mode-2026-02-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 4096,
    -    "speed": "fast",
    -    "messages": [{"role": "user", "content": "Refatore este módulo para injeção de dependência"}]
    -  }'
    -
    -
    - -
    Atenção: fast mode custa 6× as taxas padrão do Opus em toda a janela de contexto: $30/MTok entrada · $150/MTok saída. O ganho é em tokens de saída por segundo (OTPS), não em time to first token. Tem rate limit dedicado (HTTP 429 com header retry-after) e não está disponível com a Batch API nem no Claude Platform on AWS. O usage.speed da resposta indica qual velocidade foi usada.
    - - -
    - - -
    -

    9. Janelas de contexto & contagem de tokens

    -

    A "janela de contexto" é todo o texto que o modelo consegue referenciar ao gerar uma resposta, incluindo a própria resposta — uma "memória de trabalho". Opus 4.8 e Sonnet 4.6 têm 1M tokens; Haiku 4.5 (e modelos com janela menor) têm 200k tokens. Um único request pode incluir até 600 imagens/páginas de PDF (100 em modelos de 200k).

    - -
    Nota: mais contexto não é automaticamente melhor. À medida que o número de tokens cresce, precisão e recall degradam — fenômeno conhecido como context rot. Curar o que entra no contexto importa tanto quanto quanto cabe.
    - -

    Contexto com thinking: tokens de thinking contam para a janela e são cobrados como saída, mas blocos de thinking de turnos anteriores são automaticamente removidos do cálculo da janela pela API — você não precisa removê-los manualmente. A exceção: durante um ciclo de tool_use, o bloco de thinking que acompanha o tool_use deve ser devolvido junto com os tool_result correspondentes (a API usa assinaturas criptográficas para verificar a integridade).

    - -

    Context awareness: Sonnet 4.6 e Haiku 4.5 rastreiam o "token budget" restante ao longo da conversa, recebendo no início <budget:token_budget>1000000</budget:token_budget> e, após cada chamada de ferramenta, um aviso de capacidade restante. Isso melhora a execução em tarefas longas. Para janelas que se aproximam do limite, a estratégia recomendada é a compaction server-side (Parte B); context editing oferece estratégias finas adicionais.

    - -

    Overflow: nos modelos atuais, se input_tokens + max_tokens exceder a janela, a API aceita o request e, se a geração atingir o limite, para com stop_reason: "model_context_window_exceeded" (ver seção 6). Em gerações anteriores a API retornava erro de validação.

    - -

    Contagem de tokens (conceito)

    -

    O endpoint POST /v1/messages/count_tokens conta os tokens de entrada antes de enviar o request, ajudando a gerenciar rate limits/custos, decidir roteamento de modelo e otimizar o tamanho do prompt. Aceita a mesma lista estruturada de inputs (system, tools, imagens, PDFs) e retorna { "input_tokens": N }. Todos os modelos ativos suportam contagem de tokens.

    - -
    -
    - - - -
    -
    -
    response = client.messages.count_tokens(
    -    model="claude-opus-4-8",
    -    system="Você é um cientista",
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -print(response.input_tokens)  # ex.: 14
    -
    -
    -
    const response = await client.messages.countTokens({
    -  model: "claude-opus-4-8",
    -  system: "Você é um cientista",
    -  messages: [{ role: "user", content: "Olá, Claude" }],
    -});
    -console.log(response.input_tokens);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages/count_tokens \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "system": "Você é um cientista",
    -    "messages": [{"role": "user", "content": "Olá, Claude"}]
    -  }'
    -
    -
    - -
    Atenção: a contagem é uma estimativa — o número real de tokens pode diferir por uma pequena margem. A contagem pode incluir tokens adicionados pela Anthropic para otimizações de sistema, mas você não é cobrado por tokens adicionados pelo sistema; o faturamento reflete apenas seu conteúdo.
    - - -
    - - -
    -

    10. Embeddings

    -

    Embeddings são representações numéricas de texto que permitem medir similaridade semântica — base para busca, recomendação, RAG e detecção de anomalias. A Anthropic não oferece um modelo de embedding próprio; a documentação recomenda Voyage AI como parceiro (modelos de propósito geral, multilíngues e específicos de domínio como finanças, jurídico e código).

    - -
    - - - - - - - -
    Modelo (Voyage 4)ContextoDimensãoFoco
    voyage-4-large32.0001024 (padrão), 256, 512, 2048Melhor qualidade geral/multilíngue
    voyage-432.0001024 (padrão), 256, 512, 2048Equilíbrio qualidade/eficiência
    voyage-4-lite32.0001024 (padrão), 256, 512, 2048Menor latência e custo
    voyage-code-332.0001024 (padrão), …Recuperação de código
    - -
    -
    - - -
    -
    -
    import voyageai
    -
    -vo = voyageai.Client()  # usa VOYAGE_API_KEY do ambiente
    -
    -# Use input_type para distinguir documento de consulta (melhora a recuperação)
    -docs = vo.embed(["Texto exemplo 1", "Texto exemplo 2"],
    -                model="voyage-4", input_type="document").embeddings
    -query = vo.embed(["Minha pergunta"], model="voyage-4", input_type="query").embeddings[0]
    -
    -
    -
    curl https://api.voyageai.com/v1/embeddings \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $VOYAGE_API_KEY" \
    -  -d '{
    -    "input": ["Texto exemplo 1", "Texto exemplo 2"],
    -    "model": "voyage-4"
    -  }'
    -
    -
    - -
    Dica: em tarefas de recuperação (RAG), sempre use input_type ("query" vs "document") — não omita. Os embeddings da Voyage são normalizados a comprimento 1, então similaridade por produto escalar e cosseno são equivalentes (o produto escalar é mais rápido). Quantização (output_dtype) e dimensões Matryoshka permitem reduzir armazenamento/custo.
    - - -
    - - -
    -

    11. Suporte multilíngue

    -

    Claude tem forte desempenho cross-lingual em relação ao inglês, com destaque em tarefas zero-shot. Para um guia em português, vale notar que o português (Brasil) está entre os idiomas de melhor desempenho relativo ao inglês — na avaliação MMLU traduzida por tradutores humanos, fica acima de 96% em relação ao baseline inglês nos modelos recentes, ao lado de espanhol, italiano e francês. O desempenho varia por idioma, sendo mais forte em línguas amplamente faladas, mas Claude mantém capacidade significativa mesmo em idiomas com menos recursos digitais.

    - -
    Dica (boas práticas multilíngues): -
      -
    • Forneça contexto de idioma claro: embora o Claude detecte automaticamente, declarar explicitamente a língua de entrada/saída melhora a confiabilidade. Para mais fluência, peça "fala idiomática, como um falante nativo".
    • -
    • Use o script nativo em vez de transliteração.
    • -
    • Considere contexto cultural e regional — comunicação eficaz costuma exigir mais do que tradução literal.
    • -
    -
    -

    Claude processa entrada e gera saída na maioria das línguas que usam caracteres Unicode padrão. Preserve acentuação (UTF-8) ponta a ponta.

    - - -
    - - -
    -

    12. Processamento em lote (Message Batches API)

    -

    A Message Batches API processa grandes volumes de requests de Mensagens de forma assíncrona, com 50% de desconto em entrada e saída e maior throughput. Ideal quando você não precisa de resposta imediata: avaliações em larga escala, moderação de conteúdo, análise de dados e geração em massa.

    - -

    Fluxo: (1) você cria um batch enviando uma lista de requests no parâmetro requests; (2) o sistema processa cada request independentemente e de forma assíncrona; (3) você faz polling do status e recupera os resultados ao término. Cada request tem um custom_id (1–64 caracteres, ^[a-zA-Z0-9_-]{1,64}$) e um objeto params com os parâmetros padrão da Messages API. Todos os modelos ativos suportam batches, e qualquer request da Messages API pode ser incluído (visão, tool use, system, multiturno, features beta — podendo misturar tipos no mesmo batch).

    - -
    -
    - - - -
    -
    -
    from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
    -from anthropic.types.messages.batch_create_params import Request
    -
    -batch = client.messages.batches.create(
    -    requests=[
    -        Request(
    -            custom_id="req-1",
    -            params=MessageCreateParamsNonStreaming(
    -                model="claude-opus-4-8", max_tokens=1024,
    -                messages=[{"role": "user", "content": "Olá, mundo"}],
    -            ),
    -        ),
    -        Request(
    -            custom_id="req-2",
    -            params=MessageCreateParamsNonStreaming(
    -                model="claude-opus-4-8", max_tokens=1024,
    -                messages=[{"role": "user", "content": "Olá de novo, amigo"}],
    -            ),
    -        ),
    -    ]
    -)
    -print(batch.id, batch.processing_status)
    -
    -# Recupera resultados (stream, eficiente em memória) ao término
    -for result in client.messages.batches.results(batch.id):
    -    if result.result.type == "succeeded":
    -        print(result.custom_id, "ok")
    -    elif result.result.type == "errored":
    -        print(result.custom_id, result.result.error)
    -
    -
    -
    const batch = await client.messages.batches.create({
    -  requests: [
    -    {
    -      custom_id: "req-1",
    -      params: { model: "claude-opus-4-8", max_tokens: 1024,
    -                messages: [{ role: "user", content: "Olá, mundo" }] },
    -    },
    -    {
    -      custom_id: "req-2",
    -      params: { model: "claude-opus-4-8", max_tokens: 1024,
    -                messages: [{ role: "user", content: "Olá de novo, amigo" }] },
    -    },
    -  ],
    -});
    -
    -for await (const result of await client.messages.batches.results(batch.id)) {
    -  if (result.result.type === "succeeded") console.log(result.custom_id, "ok");
    -}
    -
    -
    -
    curl https://api.anthropic.com/v1/messages/batches \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "requests": [
    -      {"custom_id": "req-1", "params": {"model": "claude-opus-4-8", "max_tokens": 1024,
    -        "messages": [{"role": "user", "content": "Olá, mundo"}]}},
    -      {"custom_id": "req-2", "params": {"model": "claude-opus-4-8", "max_tokens": 1024,
    -        "messages": [{"role": "user", "content": "Olá de novo, amigo"}]}}
    -    ]
    -  }'
    -
    -
    - -

    O processing_status começa em in_progress e vira ended quando todos os requests terminam; o objeto traz request_counts com contadores por estado (processing, succeeded, errored, canceled, expired). Os resultados ficam em results_url — prefira streamar em vez de baixar tudo de uma vez. Há quatro tipos de resultado:

    -
    - - - - - - - -
    TipoSignificadoCobrança
    succeededRequest bem-sucedido; inclui o resultado da mensagem.Cobrado
    erroredErro (request inválido ou erro interno). invalid_request_error exige corrigir o corpo; outros podem ser repetidos.Não cobrado
    canceledUsuário cancelou o batch antes deste request ser enviado.Não cobrado
    expiredBatch atingiu a expiração de 24h antes do envio.Não cobrado
    - -
    Atenção — limites: um batch é limitado a 100.000 requests ou 256 MB (o que vier primeiro). A maioria completa em menos de 1h; resultados ficam disponíveis quando tudo termina ou após 24h (o que vier primeiro) — batches que não completam em 24h expiram. Resultados ficam acessíveis para download por 29 dias. Batches têm escopo de Workspace. Cada request precisa de max_tokens ≥ 1 (max_tokens: 0 não é suportado em batch). A validação dos params é assíncrona — teste o formato com a Messages API primeiro.
    - -
    Dica: como batches podem levar mais de 5 minutos, use o cache de 1 hora (prompt caching) para melhores taxas de acerto ao processar batches com contexto compartilhado. Não é ZDR-elegível.
    - - -
    - - - - -
    -

    Parte B — Raciocínio, Caching, Contexto & Multimodal

    -

    Esta parte cobre como controlar o raciocínio do Claude (adaptive thinking, extended thinking, efforto, raciocínio com ferramentas e orçamentos de tarefa), como reduzir custo e latência com prompt caching e diagnósticos de cache, como gerenciar janelas de contexto longas (context editing e compaction) e como enviar conteúdo multimodal (imagens, PDFs, Files API) com citações verificáveis e resultados de busca para RAG.

    -
    - - -
    -

    1. Adaptive thinking (raciocínio adaptativo)

    -

    O adaptive thinking deixa o Claude decidir dinamicamente se vai raciocinar e quanto vai raciocinar, com base na complexidade de cada requisição — em vez de você fixar um orçamento de tokens de pensamento. É o modo recomendado de usar extended thinking nos modelos atuais e o único modo suportado no Claude Opus 4.8.

    - - -

    1.1. Quando usar

    -

    Adaptive thinking costuma superar o extended thinking de orçamento fixo em muitas cargas — sobretudo em tarefas bimodais (mistura de perguntas simples e difíceis) e em fluxos agênticos de horizonte longo, pois o modelo gasta raciocínio só onde compensa. Nenhum header beta é necessário. Se você precisa de latência previsível ou de controle preciso do custo de raciocínio, o extended thinking manual com budget_tokens ainda funciona no Claude Sonnet 4.6 (ver capítulo 2).

    - -

    1.2. Suporte por modelo

    -

    O modo de raciocínio e o suporte a effort variam por modelo. Para a tabela completa de capacidades dos modelos, veja Modelos Claude (Parte A).

    -
    - - - - - - -
    ModeloAdaptive thinkingeffortObservação
    claude-opus-4-8único modosim (inclui xhigh)Raciocínio desligado por padrão; ative com thinking: {type: "adaptive"}. type: "enabled" com budget_tokens é rejeitado com erro 400. Não expõe extended thinking manual.
    claude-sonnet-4-6suportadosimAceita adaptive + effort e também o modo manual enabled (ainda funcional).
    claude-haiku-4-5nãonãoUsa extended thinking manual: thinking: {type: "enabled", budget_tokens: N}. Não tem adaptive nem effort.
    -
    Atenção: o parâmetro effort está disponível em claude-opus-4-8, claude-sonnet-5 (ambos com xhigh e max) e claude-sonnet-4-6 (até max, sem xhigh); com adaptive thinking é o controle de profundidade recomendado, mas effort também funciona sem thinking, controlando o gasto geral da resposta. No claude-haiku-4-5 não há adaptive nem effort: controle o raciocínio apenas via budget_tokens (ver capítulo 2).
    - -

    1.3. Como usar

    -

    Defina thinking.type como "adaptive". No nível padrão de effort (high), o Claude quase sempre raciocina; em níveis mais baixos pode pular o raciocínio em perguntas simples.

    -
    -
    - - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -
    -response = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=16000,
    -    thinking={"type": "adaptive"},
    -    messages=[
    -        {
    -            "role": "user",
    -            "content": "Explique por que a soma de dois números pares é sempre par.",
    -        }
    -    ],
    -)
    -
    -for block in response.content:
    -    if block.type == "thinking":
    -        print(f"\nPensamento: {block.thinking}")
    -    elif block.type == "text":
    -        print(f"\nResposta: {block.text}")
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic();
    -
    -const response = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 16000,
    -  thinking: { type: "adaptive" },
    -  messages: [
    -    { role: "user", content: "Explique por que a soma de dois números pares é sempre par." },
    -  ],
    -});
    -
    -for (const block of response.content) {
    -  if (block.type === "thinking") console.log(`\nPensamento: ${block.thinking}`);
    -  else if (block.type === "text") console.log(`\nResposta: ${block.text}`);
    -}
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 16000,
    -    "thinking": { "type": "adaptive" },
    -    "messages": [
    -      { "role": "user", "content": "Explique por que a soma de dois números pares é sempre par." }
    -    ]
    -  }'
    -
    -
    - -

    1.4. Adaptive thinking com o parâmetro effort

    -

    Combine thinking: {type:"adaptive"} com output_config.effort para guiar (orientação soft) quanto o Claude raciocina. O effort só existe junto de adaptive thinking — portanto em claude-opus-4-8 e claude-sonnet-4-6; o claude-haiku-4-5 não o suporta (use budget_tokens). Para o panorama de capacidades por modelo, veja Modelos Claude (Parte A).

    -
    - - - - - - - - -
    effortComportamento de raciocínio
    maxSempre raciocina, sem restrição de profundidade. Em claude-opus-4-8 e claude-sonnet-4-6.
    xhighSempre raciocina profundamente com exploração estendida. Disponível em claude-opus-4-8.
    high (padrão)Sempre raciocina. Raciocínio profundo em tarefas complexas.
    mediumRaciocínio moderado; pode pular pensamento em perguntas muito simples.
    lowMinimiza o raciocínio; pula o pensamento em tarefas simples onde a velocidade importa.
    -
    -
    - - - -
    -
    -
    response = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=16000,
    -    thinking={"type": "adaptive"},
    -    output_config={"effort": "medium"},
    -    messages=[{"role": "user", "content": "Qual é a capital da França?"}],
    -)
    -print(response.content[0].text)
    -
    -
    -
    const response = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 16000,
    -  thinking: { type: "adaptive" },
    -  output_config: { effort: "medium" },
    -  messages: [{ role: "user", content: "Qual é a capital da França?" }],
    -});
    -console.log(response.content[0].text);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 16000,
    -    "thinking": { "type": "adaptive" },
    -    "output_config": { "effort": "medium" },
    -    "messages": [ { "role": "user", "content": "Qual é a capital da França?" } ]
    -  }'
    -
    -
    - -

    1.5. Considerações importantes

    -
      -
    • Interleaved thinking automático: o modo adaptive ativa automaticamente o raciocínio intercalado entre chamadas de ferramenta — ideal para fluxos agênticos. No Opus 4.8, o raciocínio entre ferramentas sempre vive dentro de blocos thinking.
    • -
    • Validação mais flexível: turnos anteriores do assistente não precisam começar com um bloco thinking (no modo manual a API exige isso).
    • -
    • Prompt caching: requisições consecutivas com o mesmo modo (adaptive) preservam os breakpoints de cache. Alternar entre adaptive e enabled/disabled quebra os breakpoints das mensagens (system prompt e definições de ferramenta continuam em cache).
    • -
    • Display padrão no Opus 4.8: thinking.display assume "omitted" por padrão (mudança silenciosa em relação ao comportamento anterior). Para receber o resumo do pensamento, defina display: "summarized" explicitamente. Veja o capítulo 2.
    • -
    • Controle de custo: use max_tokens como limite rígido do total de saída (pensamento + texto). Em high/max o modelo pode esgotar max_tokens; se vir stop_reason: "max_tokens", aumente max_tokens ou reduza o effort.
    • -
    -
    Dica: o disparo do raciocínio é promptável. Se o Claude raciocina demais (ou de menos), oriente no system prompt — por exemplo: “Use raciocínio estendido apenas quando melhorar de forma significativa a qualidade da resposta; na dúvida, responda diretamente.” Meça o impacto antes de levar para produção.
    -
    - - -
    -

    2. Extended thinking (raciocínio estendido) e blocos de pensamento

    -

    O extended thinking dá ao Claude uma fase de raciocínio interno antes da resposta final. Você pode controlá-lo de forma adaptativa (cap. 1) ou manual com um orçamento de tokens. Este capítulo detalha o modo manual, a exibição/criptografia dos blocos de pensamento e a preservação dos blocos entre turnos.

    - - -

    2.1. Modos de raciocínio

    -
    - - - - - - -
    ModoConfigDisponibilidadeQuando usar
    Adaptivethinking: {type: "adaptive"}claude-opus-4-8 (único modo), claude-sonnet-4-6. Não em claude-haiku-4-5.O Claude decide quando/quanto raciocinar. Use effort para guiar.
    Manualthinking: {type: "enabled", budget_tokens: N}claude-sonnet-4-6 (ainda funcional) e claude-haiku-4-5 (único modo de raciocínio do Haiku). Rejeitado em claude-opus-4-8 (400).Quando você precisa de controle preciso do gasto de tokens de pensamento.
    DisabledOmitir thinking ou {type: "disabled"}Todos os modelosQuando não precisa de raciocínio e quer a menor latência.
    - -

    2.2. Modo manual (orçamento fixo)

    -

    No modo manual você define budget_tokens — o número alvo de tokens que o Claude pode usar para raciocinar. Deve ser menor que max_tokens (o max_tokens cobre pensamento + texto da resposta). Exemplo no Sonnet 4.6:

    -
    -
    - - - -
    -
    -
    response = client.messages.create(
    -    model="claude-sonnet-4-6",
    -    max_tokens=16000,
    -    thinking={"type": "enabled", "budget_tokens": 10000},
    -    messages=[{"role": "user", "content": "Quantos números primos há entre 100 e 200?"}],
    -)
    -
    -
    -
    const response = await client.messages.create({
    -  model: "claude-sonnet-4-6",
    -  max_tokens: 16000,
    -  thinking: { type: "enabled", budget_tokens: 10000 },
    -  messages: [{ role: "user", content: "Quantos números primos há entre 100 e 200?" }],
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-sonnet-4-6",
    -    "max_tokens": 16000,
    -    "thinking": { "type": "enabled", "budget_tokens": 10000 },
    -    "messages": [ { "role": "user", "content": "Quantos números primos há entre 100 e 200?" } ]
    -  }'
    -
    -
    -
    Nota: no Claude Opus 4.8 o modo manual enabled é rejeitado (erro 400). Use sempre adaptive + effort nesse modelo.
    - -

    2.3. Thinking resumido (summarized)

    -

    Com extended thinking ativo, a Messages API retorna um resumo do raciocínio completo (não o texto bruto de pensamento), preservando os ganhos de inteligência e prevenindo uso indevido. Pontos-chave:

    -
      -
    • Você é cobrado pelos tokens completos de pensamento gerados, não pelos tokens do resumo. A contagem de tokens de saída faturada não bate com os tokens visíveis na resposta.
    • -
    • A sumarização é feita por um modelo diferente do que você chamou; o modelo de raciocínio não vê o resumo.
    • -
    • O resumo preserva as ideias-chave com latência adicional mínima e é streamável.
    • -
    - -

    2.4. Controlando a exibição: thinking.display

    -

    O campo display controla como o conteúdo de pensamento volta na resposta:

    -
    - - - - - -
    ValorComportamentoPadrão em
    "summarized"Blocos contêm o texto resumido do pensamento.Sonnet 4.6 e modelos Claude 4 anteriores (default nessas gerações)
    "omitted"Blocos voltam com thinking vazio; o campo signature ainda carrega o pensamento completo criptografado para continuidade multi-turno.Default em claude-opus-4-8, claude-opus-4-7, claude-sonnet-5, claude-fable-5 e claude-mythos-5
    -
    Atenção (mudança silenciosa): nos modelos mais novos — claude-opus-4-8, claude-opus-4-7, claude-sonnet-5, claude-fable-5 e claude-mythos-5 — display é "omitted" por padrão (era "summarized" em Opus 4.6 / Sonnet 4.6): os blocos de pensamento aparecem no stream, mas com thinking vazio. Quem migra de Sonnet 4.6 para Sonnet 5 esperando ver o raciocínio precisa definir explicitamente display: "summarized". display é inválido com thinking.type: "disabled". Mesmo com "omitted", você continua sendo cobrado pelos tokens completos de pensamento — omitir reduz latência, não custo.
    -
    # Restaurar resumo do pensamento no Opus 4.8:
    -thinking = {"type": "adaptive", "display": "summarized"}
    -
    -# Omitir (default no Opus 4.8) — menor time-to-first-text-token no streaming:
    -thinking = {"type": "adaptive", "display": "omitted"}
    - -

    2.5. Criptografia e signature

    -

    O conteúdo completo de pensamento é criptografado e devolvido no campo signature, usado para verificar que os blocos foram gerados pelo Claude quando você os reenvia. Considerações:

    -
      -
    • No streaming, a signature chega via signature_delta dentro de um content_block_delta, logo antes do content_block_stop.
    • -
    • signature é um campo opaco — não interprete nem faça parsing.
    • -
    • Valores de signature são compatíveis entre plataformas (Claude API, Amazon Bedrock e Vertex AI).
    • -
    -
    Nota: só é estritamente necessário reenviar blocos de pensamento quando se usa ferramentas com extended thinking (ver capítulo 3). Caso reenvie, passe tudo exatamente como recebeu.
    - -

    2.6. Redacted thinking

    -

    Ocasionalmente o raciocínio interno é sinalizado pelos sistemas de segurança e volta criptografado como um bloco redacted_thinking (em vez de thinking). Ele é decriptado quando reenviado ao modelo. Trate-o como um bloco normal: reenvie-o sem modificação em conversas multi-turno; ele não afeta a qualidade das respostas.

    - -

    2.7. Preservação de blocos de pensamento entre turnos

    -

    Se você reenvia blocos de pensamento, o que a API mantém em contexto depende do modelo:

    -
    - - - - - - -
    ModeloBlocos de pensamento de turnos anteriores
    claude-opus-4-8Mantidos em contexto por padrão (todos os turnos).
    claude-sonnet-4-6Mantidos em contexto por padrão (todos os turnos).
    claude-haiku-4-5Removidos (stripped) por padrão.
    -

    Use context editing para configurar esse comportamento. O faturamento de tokens de pensamento mantidos em contexto conta como tokens de input nos turnos seguintes.

    - -

    2.8. max_tokens, janela de contexto e stop_reason

    -

    O max_tokens limita o total de saída (pensamento + texto). Se o raciocínio mais a resposta atingirem o limite, a resposta volta com stop_reason: "max_tokens" e o texto pode ficar truncado. Em effort alto, deixe folga em max_tokens. Sobre o tamanho da janela e a contabilidade de tokens, veja janelas de contexto; sobre os demais valores de término, veja stop_reason (Parte A).

    -
    - - -
    -

    3. Raciocínio com uso de ferramentas (extended thinking + tool use)

    -

    Ao combinar raciocínio com tool use, há uma regra central: você deve reenviar os blocos de pensamento do turno do assistente — sem modificá-los — junto com o bloco tool_use, para que o Claude continue o raciocínio de onde parou ao receber o tool_result.

    - - -

    3.1. O ciclo com preservação de pensamento

    -
      -
    1. Você envia a mensagem do usuário com thinking ativo e as tools definidas.
    2. -
    3. O assistente responde com um ou mais blocos thinking seguidos de um bloco tool_use (stop_reason: "tool_use").
    4. -
    5. Você executa a ferramenta e devolve um turno user com o bloco tool_result.
    6. -
    7. No próximo turno do assistente, você reenvia o turno anterior do assistente incluindo os blocos de pensamento intactos (com sua signature).
    8. -
    -
    Atenção: não edite, reordene nem remova os blocos de pensamento ao reenviá-los. A API valida a signature; alterações causam erro. No claude-opus-4-8 (e no modo adaptive em geral), o interleaved thinking é automático — o Claude pode raciocinar entre múltiplas chamadas de ferramenta.
    - -

    3.2. Exemplo: continuação após tool_result

    -
    -
    - - - -
    -
    -
    tools = [{
    -    "name": "get_weather",
    -    "description": "Obtém o clima atual de uma cidade.",
    -    "input_schema": {
    -        "type": "object",
    -        "properties": {"city": {"type": "string"}},
    -        "required": ["city"],
    -    },
    -}]
    -
    -# 1) Primeira chamada — Claude raciocina e pede a ferramenta
    -first = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=16000,
    -    thinking={"type": "adaptive"},
    -    tools=tools,
    -    messages=[{"role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?"}],
    -)
    -
    -# 2) Execute a ferramenta e devolva o turno do assistente INTACTO (com os blocos thinking)
    -tool_use = next(b for b in first.content if b.type == "tool_use")
    -second = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=16000,
    -    thinking={"type": "adaptive"},
    -    tools=tools,
    -    messages=[
    -        {"role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?"},
    -        {"role": "assistant", "content": first.content},  # blocos thinking + tool_use preservados
    -        {
    -            "role": "user",
    -            "content": [{
    -                "type": "tool_result",
    -                "tool_use_id": tool_use.id,
    -                "content": "Chuva forte prevista para a tarde.",
    -            }],
    -        },
    -    ],
    -)
    -print(second.content[-1].text)
    -
    -
    -
    const tools = [{
    -  name: "get_weather",
    -  description: "Obtém o clima atual de uma cidade.",
    -  input_schema: {
    -    type: "object",
    -    properties: { city: { type: "string" } },
    -    required: ["city"],
    -  },
    -}];
    -
    -const first = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 16000,
    -  thinking: { type: "adaptive" },
    -  tools,
    -  messages: [{ role: "user", content: "Devo levar guarda-chuva em São Paulo hoje?" }],
    -});
    -
    -const toolUse = first.content.find((b) => b.type === "tool_use");
    -const second = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 16000,
    -  thinking: { type: "adaptive" },
    -  tools,
    -  messages: [
    -    { role: "user", content: "Devo levar guarda-chuva em São Paulo hoje?" },
    -    { role: "assistant", content: first.content }, // thinking + tool_use intactos
    -    {
    -      role: "user",
    -      content: [{
    -        type: "tool_result",
    -        tool_use_id: toolUse.id,
    -        content: "Chuva forte prevista para a tarde.",
    -      }],
    -    },
    -  ],
    -});
    -
    -
    -
    # O turno do assistente (content) deve conter os blocos thinking originais
    -# com sua signature, seguidos do bloco tool_use, e depois o tool_result do usuário.
    -curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 16000,
    -    "thinking": { "type": "adaptive" },
    -    "tools": [ { "name": "get_weather", "input_schema": {"type":"object","properties":{"city":{"type":"string"}},"required":["city"]} } ],
    -    "messages": [
    -      { "role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?" },
    -      { "role": "assistant", "content": [ {"type":"thinking","thinking":"...","signature":"..."}, {"type":"tool_use","id":"toolu_01","name":"get_weather","input":{"city":"São Paulo"}} ] },
    -      { "role": "user", "content": [ {"type":"tool_result","tool_use_id":"toolu_01","content":"Chuva forte prevista para a tarde."} ] }
    -    ]
    -  }'
    -
    -
    - -

    3.3. Interleaved thinking

    -

    O interleaved thinking permite ao Claude raciocinar entre chamadas de ferramenta — refletindo sobre o resultado de uma ferramenta antes de decidir a próxima. Disponibilidade:

    -
    - - - - - -
    ConfiguraçãoInterleaved thinking
    Adaptive em claude-opus-4-8 / claude-sonnet-4-6Automático (sem header beta).
    Manual (enabled) em claude-sonnet-4-6Via header anthropic-beta: interleaved-thinking-2025-05-14.
    - -

    3.4. tool_choice e raciocínio

    -

    Quando o raciocínio está ativo, há limitações com tool_choice: você não pode forçar uma ferramenta específica (tool_choice: {type: "tool", ...}) nem tool_choice: {type: "any"} de forma incompatível com o pensamento. Use tool_choice: {type: "auto"} (padrão) com raciocínio ativo e deixe o Claude decidir.

    -
    - - -
    -

    4. Orçamentos de tarefa (task budgets)

    -

    Os task budgets definem um teto de tokens para uma tarefa inteira — somando múltiplas requisições/turnos de um fluxo agêntico — em vez de limitar token a token por chamada. Servem para controlar custo e horizonte de tarefas longas com ferramentas.

    - -

    Beta Requer o header anthropic-beta: task-budgets-2026-03-13 (verificado em 2026-06-10). Apenas Claude Opus 4.8 — não suportado em Sonnet 4.6 nem Haiku 4.5. Defina output_config.task_budget = {"type":"tokens","total": N} (campo opcional remaining para retomar após compactação). O mínimo é 20.000 tokens (valores menores retornam 400); o orçamento é advisory (hint suave), enquanto max_tokens continua sendo o teto rígido por requisição.

    - -

    4.1. Como usar

    -

    Defina output_config.task_budget com o tipo e o total. Combine com effort para orientar a alocação de raciocínio dentro do orçamento. No SDK Python, use o namespace client.beta.messages e passe betas=[...].

    -
    -
    - - - -
    -
    -
    message = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=16000,
    -    thinking={"type": "adaptive"},
    -    output_config={
    -        "effort": "high",
    -        "task_budget": {"type": "tokens", "total": 64000},
    -    },
    -    betas=["task-budgets-2026-03-13"],
    -    messages=[{"role": "user", "content": "Refatore este módulo e rode os testes."}],
    -)
    -
    -
    -
    const message = await client.beta.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 16000,
    -  thinking: { type: "adaptive" },
    -  output_config: {
    -    effort: "high",
    -    task_budget: { type: "tokens", total: 64000 },
    -  },
    -  betas: ["task-budgets-2026-03-13"],
    -  messages: [{ role: "user", content: "Refatore este módulo e rode os testes." }],
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "anthropic-beta: task-budgets-2026-03-13" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 16000,
    -    "thinking": { "type": "adaptive" },
    -    "output_config": {
    -      "effort": "high",
    -      "task_budget": { "type": "tokens", "total": 64000 }
    -    },
    -    "messages": [ { "role": "user", "content": "Refatore este módulo e rode os testes." } ]
    -  }'
    -
    -
    -
    Dica: diferencie os três controles: max_tokens limita a saída de uma requisição; task_budget limita o consumo da tarefa toda (várias requisições); effort é orientação soft de quanto raciocinar. Use os três juntos para custo previsível em agentes de horizonte longo.
    -
    - - -
    -

    5. Prompt caching (cache de prompt)

    -

    O prompt caching permite reutilizar prefixos grandes e estáveis do prompt (system prompt extenso, definições de ferramenta, documentos, exemplos few-shot) entre requisições, cortando custo e latência drasticamente. Você marca pontos de cache (breakpoints) com cache_control.

    - - -

    5.1. Mínimos de tokens cacheáveis (por modelo)

    -

    Prompts menores que o mínimo são processados sem cache e nenhum erro é retornado. Verifique usage.cache_creation_input_tokens e usage.cache_read_input_tokens: se ambos forem 0, o prompt não foi cacheado.

    -
    - - - - - - -
    ModeloMínimo de tokens cacheáveis
    claude-opus-4-84.096 tokens
    claude-sonnet-4-61.024 tokens
    claude-haiku-4-54.096 tokens
    - -

    5.2. TTL e preços

    -
    - - - - - - -
    Tipo de tokenMultiplicador vs. preço base de input
    Cache write (TTL 5 min, padrão)1,25× (refrescado sem custo extra a cada uso)
    Cache write (TTL 1 h)2× (opt-in com "ttl": "1h")
    Cache hit / refresh (read)0,1× (10% do preço base)
    -

    Exemplo para claude-opus-4-8 ($5/MTok base): cache write 5m = $6,25/MTok; cache write 1h = $10/MTok; cache read = $0,50/MTok.

    - -

    5.3. Caching automático (breakpoint no nível superior)

    -

    Adicione um único cache_control no nível superior do corpo da requisição. A API aplica o breakpoint ao último bloco cacheável e move o breakpoint para a frente automaticamente conforme a conversa cresce.

    -
    -
    - - - -
    -
    -
    response = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    cache_control={"type": "ephemeral"},  # breakpoint automático no último bloco cacheável
    -    system="Você é um assistente jurídico... (system prompt longo e estável)",
    -    messages=[{"role": "user", "content": "Resuma o contrato anexo."}],
    -)
    -print(response.usage.cache_creation_input_tokens, response.usage.cache_read_input_tokens)
    -
    -
    -
    const response = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  cache_control: { type: "ephemeral" }, // breakpoint automático
    -  system: "Você é um assistente jurídico... (system prompt longo e estável)",
    -  messages: [{ role: "user", content: "Resuma o contrato anexo." }],
    -});
    -console.log(response.usage.cache_creation_input_tokens, response.usage.cache_read_input_tokens);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "cache_control": { "type": "ephemeral" },
    -    "system": "Você é um assistente jurídico... (system prompt longo e estável)",
    -    "messages": [ { "role": "user", "content": "Resuma o contrato anexo." } ]
    -  }'
    -
    -
    -
    Nota: caching automático está disponível na Claude API e na Claude Platform na AWS / Microsoft Foundry (beta). Não é suportado em Amazon Bedrock nem Vertex AI (use breakpoints explícitos lá).
    - -

    5.4. Breakpoints explícitos em blocos de conteúdo

    -

    Para controle fino, coloque cache_control diretamente em blocos específicos (system, tools, document, etc.). Há no máximo 4 breakpoints por requisição. Tudo antes de um breakpoint (inclusive) entra no prefixo cacheável.

    -
    {
    -  "model": "claude-opus-4-8",
    -  "max_tokens": 1024,
    -  "tools": [ { "name": "...", "cache_control": { "type": "ephemeral" } } ],
    -  "system": [
    -    { "type": "text", "text": "Instruções base..." },
    -    { "type": "text", "text": "Base de conhecimento longa...", "cache_control": { "type": "ephemeral" } }
    -  ],
    -  "messages": [ { "role": "user", "content": "..." } ]
    -}
    - -

    5.5. TTL de 1 hora

    -
    { "cache_control": { "type": "ephemeral", "ttl": "1h" } }
    -

    Útil para prefixos reaproveitados ao longo de minutos a uma hora (ex.: documento grande consultado várias vezes). Custa 2× o input base na escrita, mas economiza em muitas leituras subsequentes (0,1×).

    - -

    5.6. Pré-aquecimento (pre-warming) do cache

    -

    Para garantir que o prefixo já esteja em cache antes do primeiro uso real, faça uma requisição de aquecimento com max_tokens mínimo. Isso paga a escrita do cache uma vez e deixa as leituras seguintes baratas.

    -
    # Aquece o cache do prefixo sem gerar resposta longa
    -client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1,
    -    cache_control={"type": "ephemeral"},
    -    system="... prefixo grande e estável ...",
    -    messages=[{"role": "user", "content": "ok"}],
    -)
    - -

    5.7. Pegadinhas (edge cases)

    -
      -
    • Se o último bloco já tem cache_control explícito com o mesmo TTL do automático → no-op.
    • -
    • Se o último bloco tem cache_control explícito com TTL diferente → erro 400.
    • -
    • Se os 4 slots de breakpoint explícito já estão usados → erro 400 ao adicionar o automático.
    • -
    • Misturar TTLs: você pode ter breakpoints de 5m e 1h na mesma requisição, mas planeje a ordem (o prefixo mais estável com TTL maior).
    • -
    -
    Atenção: mudanças antes de um breakpoint invalidam o cache daquele ponto em diante. Mantenha conteúdo volátil (a pergunta do usuário) depois dos breakpoints e conteúdo estável (system, tools, documentos) antes.
    -
    - - -
    -

    6. Diagnóstico de cache (cache diagnostics)

    -

    Quando o cache não está acertando como esperado, os diagnósticos de cache explicam por que houve cache miss, comparando a requisição atual com a anterior e apontando o primeiro ponto de divergência (modelo, system prompt, tools ou histórico de mensagens).

    - -

    Beta Requer o header anthropic-beta: cache-diagnosis-2026-04-07 (verificado em 2026-05-24). Passe o id da resposta anterior em diagnostics.previous_message_id; a API retorna um objeto diagnostics descrevendo a divergência. Disponível apenas na Claude API — não suportado em Amazon Bedrock nem Vertex AI.

    - -

    6.1. Como usar

    -

    Passe diagnostics com o previous_message_id da requisição anterior (ou None na primeira). A resposta inclui um cache_miss_reason indicando onde o prefixo divergiu.

    -
    -
    - - - -
    -
    -
    message = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    diagnostics={"previous_message_id": None},  # ou o id da resposta anterior
    -    betas=["cache-diagnosis-2026-04-07"],
    -    cache_control={"type": "ephemeral"},
    -    system="... prefixo grande ...",
    -    messages=[{"role": "user", "content": "Continue."}],
    -)
    -# Inspecione o motivo de eventual cache miss
    -print(getattr(message, "cache_miss_reason", None))
    -
    -
    -
    const message = await client.beta.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  diagnostics: { previous_message_id: null }, // ou o id da resposta anterior
    -  betas: ["cache-diagnosis-2026-04-07"],
    -  cache_control: { type: "ephemeral" },
    -  system: "... prefixo grande ...",
    -  messages: [{ role: "user", content: "Continue." }],
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "anthropic-beta: cache-diagnosis-2026-04-07" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "diagnostics": { "previous_message_id": null },
    -    "cache_control": { "type": "ephemeral" },
    -    "system": "... prefixo grande ...",
    -    "messages": [ { "role": "user", "content": "Continue." } ]
    -  }'
    -
    -
    -
    Dica: as causas mais comuns de cache miss são: alterar conteúdo antes de um breakpoint, alternar o modo de thinking (adaptive ↔ enabled/disabled) nas mensagens, ou ficar abaixo do mínimo de tokens cacheáveis do modelo. Use o cache_miss_reason para localizar exatamente o ponto de divergência.
    -
    - - -
    -

    7. Edição de contexto (context editing)

    -

    A edição de contexto remove automaticamente conteúdo antigo da janela quando ela cresce demais — por exemplo, resultados de ferramentas já consumidos e blocos de pensamento antigos — preservando os mais recentes. Mantém agentes de horizonte longo dentro da janela sem você gerenciar o histórico manualmente.

    - -

    Beta Requer o header anthropic-beta: context-management-2025-06-27.

    - -

    7.1. Tipos de edição

    -
    - - - - - -
    Tipo de editO que limpa
    clear_tool_uses_20250919Resultados de uso de ferramentas (tool_use/tool_result) antigos.
    clear_thinking_20251015Blocos de pensamento (thinking) antigos.
    - -

    7.2. Parâmetros de um edit clear_tool_uses

    -
    - - - - - - - -
    CampoDescrição
    triggerQuando acionar a limpeza, ex. {"type": "input_tokens", "value": 30000}.
    keepQuanto preservar, ex. {"type": "tool_uses", "value": 3} (mantém os 3 usos de ferramenta mais recentes).
    clear_at_leastMínimo a limpar por acionamento (evita limpezas insignificantes).
    exclude_toolsLista de ferramentas cujos resultados nunca devem ser limpos.
    - -

    7.3. Exemplo

    -
    -
    - - - -
    -
    -
    message = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=16000,
    -    betas=["context-management-2025-06-27"],
    -    context_management={
    -        "edits": [
    -            {
    -                "type": "clear_tool_uses_20250919",
    -                "trigger": {"type": "input_tokens", "value": 30000},
    -                "keep": {"type": "tool_uses", "value": 3},
    -                "clear_at_least": {"type": "input_tokens", "value": 5000},
    -                "exclude_tools": ["get_critical_state"],
    -            },
    -            {"type": "clear_thinking_20251015"},
    -        ]
    -    },
    -    tools=[...],
    -    messages=[...],
    -)
    -
    -
    -
    const message = await client.beta.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 16000,
    -  betas: ["context-management-2025-06-27"],
    -  context_management: {
    -    edits: [
    -      {
    -        type: "clear_tool_uses_20250919",
    -        trigger: { type: "input_tokens", value: 30000 },
    -        keep: { type: "tool_uses", value: 3 },
    -        clear_at_least: { type: "input_tokens", value: 5000 },
    -        exclude_tools: ["get_critical_state"],
    -      },
    -      { type: "clear_thinking_20251015" },
    -    ],
    -  },
    -  tools: [/* ... */],
    -  messages: [/* ... */],
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "anthropic-beta: context-management-2025-06-27" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 16000,
    -    "context_management": {
    -      "edits": [
    -        {
    -          "type": "clear_tool_uses_20250919",
    -          "trigger": { "type": "input_tokens", "value": 30000 },
    -          "keep": { "type": "tool_uses", "value": 3 },
    -          "clear_at_least": { "type": "input_tokens", "value": 5000 },
    -          "exclude_tools": ["get_critical_state"]
    -        },
    -        { "type": "clear_thinking_20251015" }
    -      ]
    -    },
    -    "messages": [ ... ]
    -  }'
    -
    -
    -
    Atenção: limpar conteúdo invalida os breakpoints de cache a partir do ponto editado, pois o prefixo muda. Posicione o context editing levando em conta o cache. Use exclude_tools para nunca descartar resultados de ferramentas que carregam estado crítico (ex.: identificadores ou saldos que o agente ainda precisará).
    -
    - - -
    -

    8. Compactação de contexto (compaction)

    -

    A compaction resume automaticamente o histórico antigo da conversa em uma forma condensada quando o contexto cresce, preservando as informações essenciais e liberando espaço — diferente do context editing, que remove blocos; a compaction resume. Sobre o tamanho da janela de contexto que esses mecanismos protegem, veja a Parte A.

    - -

    Beta Requer o header anthropic-beta: compact-2026-01-12 (verificado em 2026-05-24). É distinto do header de context editing context-management-2025-06-27.

    - -

    8.1. Como usar

    -

    Adicione um edit do tipo compact_20260112 em context_management.edits. A compaction pode coexistir com edits de limpeza (cap. 7).

    -
    -
    - - - -
    -
    -
    message = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=16000,
    -    betas=["compact-2026-01-12"],
    -    context_management={"edits": [{"type": "compact_20260112"}]},
    -    messages=[...],  # histórico longo de conversa agêntica
    -)
    -
    -
    -
    const message = await client.beta.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 16000,
    -  betas: ["compact-2026-01-12"],
    -  context_management: { edits: [{ type: "compact_20260112" }] },
    -  messages: [/* histórico longo */],
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "anthropic-beta: compact-2026-01-12" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 16000,
    -    "context_management": { "edits": [ { "type": "compact_20260112" } ] },
    -    "messages": [ ... ]
    -  }'
    -
    -
    -
    Dica: use compaction para agentes que rodam por muitas dezenas de turnos (programação, pesquisa, automação) onde o histórico bruto explodiria a janela mas o significado precisa ser preservado. Para contextos onde só os blocos recentes importam e os antigos podem ser descartados sem resumir, prefira context editing (mais barato). Os dois podem ser combinados.
    -
    - - -
    -

    9. Visão (entendimento de imagens)

    -

    As capacidades de visão deixam o Claude entender e analisar imagens: descrever cenas, ler texto, interpretar gráficos/diagramas, comparar várias imagens e dar suporte a computer use e leitura de telas.

    - - -

    9.1. Limites

    -
    - - - - - - - - -
    LimiteValor
    Imagens por requisição (API, modelos com janela de 200k)100
    Imagens por requisição (API, demais modelos)600
    Dimensões máximas por imagem8000×8000 px (reduz para 2000×2000 px se > 20 imagens na requisição)
    Formatos suportadosJPEG, PNG, GIF, WebP (animações: só o 1º frame é usado)
    Tamanho máximo da requisição32 MB (endpoints padrão; menor em algumas plataformas parceiras)
    -
    Nota: mesmo com a Files API, requisições com muitas imagens grandes podem falhar antes de atingir 600 imagens por causa do limite de tamanho do payload. Reduza dimensões/tamanho (downsampling) ou referencie por file_id.
    - -

    9.2. Custo de tokens por imagem

    -

    Uma imagem usa aproximadamente width * height / 750 tokens (em pixels). Se exceder a resolução nativa do modelo, é redimensionada preservando o aspect ratio e preenchida (padding) até múltiplos de 28 px.

    -
    - - - - - -
    ModeloResolução nativa máximaTokens máximos por imagem
    claude-opus-4-8até 2576 px na borda longa~4784 tokens (alta resolução)
    claude-sonnet-4-6 / claude-haiku-4-5até 1568 px na borda longa~1568 tokens
    -
    Dica: o suporte a alta resolução (até 2576 px na borda longa) foi introduzido no Opus 4.7 e segue no claude-opus-4-8 — automático e sem header beta — ótimo para computer use, leitura de screenshots e análise de documentos. Mas pode usar até ~3× mais tokens por imagem (4784 vs. 1568). Se não precisa da fidelidade extra, faça downsampling antes de enviar para controlar custo.
    - -

    9.3. Fontes de imagem e exemplo

    -

    Há três formas de fornecer imagens: base64, url e file (via Files API — ver capítulo 11). Coloque imagens antes do texto para melhores resultados.

    -
    -
    - - - -
    -
    -
    import anthropic, base64, httpx
    -
    -client = anthropic.Anthropic()
    -
    -url = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
    -img_data = base64.standard_b64encode(httpx.get(url).content).decode("utf-8")
    -
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": img_data}},
    -            {"type": "text", "text": "O que há nesta imagem?"},
    -        ],
    -    }],
    -)
    -print(message.content[0].text)
    -
    -
    -
    // Opção mais simples: imagem por URL
    -const message = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{
    -    role: "user",
    -    content: [
    -      { type: "image", source: { type: "url", url: "https://exemplo.com/foto.jpg" } },
    -      { type: "text", text: "O que há nesta imagem?" },
    -    ],
    -  }],
    -});
    -console.log(message.content[0].text);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{
    -      "role": "user",
    -      "content": [
    -        { "type": "image", "source": { "type": "url", "url": "https://exemplo.com/foto.jpg" } },
    -        { "type": "text", "text": "O que há nesta imagem?" }
    -      ]
    -    }]
    -  }'
    -
    -
    -
    Nota: em Amazon Bedrock e Vertex AI, apenas fontes base64 estão disponíveis atualmente. Ao pedir coordenadas (pontos, bounding boxes), elas vêm em relação à imagem redimensionada/com padding — reescale no cliente.
    -
    - - -
    -

    10. Suporte a PDF

    -

    O Claude processa PDFs entendendo texto e elementos visuais (gráficos, tabelas, diagramas): cada página é convertida em imagem e tem o texto extraído, e o modelo analisa ambos. Útil para relatórios financeiros, documentos jurídicos, tradução e extração estruturada.

    - - -

    10.1. Requisitos e limites

    -
    - - - - - - -
    RequisitoLimite
    Tamanho máximo da requisição32 MB (varia por plataforma)
    Máximo de páginas por requisição600 (100 para modelos com janela de 200k tokens)
    FormatoPDF padrão, sem senha/criptografia
    -

    Os limites valem para o payload inteiro (PDF + qualquer outro conteúdo). Como o suporte a PDF usa as capacidades de visão, está sujeito às mesmas limitações da visão. Todos os modelos ativos suportam PDF.

    - -

    10.2. Custo (estimativa de tokens)

    -
      -
    • Texto: tipicamente 1.500–3.000 tokens por página, conforme densidade. Sem taxa adicional de PDF.
    • -
    • Imagem: como cada página vira imagem, aplica-se o mesmo cálculo de tokens da visão.
    • -
    -
    Atenção: PDFs densos (fontes pequenas, tabelas complexas, muitos gráficos) podem encher a janela de contexto antes de atingir o limite de páginas. Divida o documento em seções; para arquivos grandes, faça downsampling das imagens embutidas. Use a Files API para manter o payload pequeno.
    - -

    10.3. Três formas de enviar um PDF

    -

    Via url, base64 ou file_id (Files API). Coloque o PDF antes do texto.

    -
    -
    - - - -
    -
    -
    # Opção 1: PDF por URL (mais simples)
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "document", "source": {"type": "url", "url": "https://exemplo.com/relatorio.pdf"}},
    -            {"type": "text", "text": "Quais são as conclusões principais deste documento?"},
    -        ],
    -    }],
    -)
    -print(message.content)
    -
    -
    -
    // Opção 1: PDF por URL
    -const response = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{
    -    role: "user",
    -    content: [
    -      { type: "document", source: { type: "url", url: "https://exemplo.com/relatorio.pdf" } },
    -      { type: "text", text: "Quais são as conclusões principais deste documento?" },
    -    ],
    -  }],
    -});
    -console.log(response);
    -
    -
    -
    # Opção 2: PDF em base64
    -curl https://api.anthropic.com/v1/messages \
    -  -H "content-type: application/json" \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -d '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{
    -      "role": "user",
    -      "content": [
    -        { "type": "document", "source": { "type": "base64", "media_type": "application/pdf", "data": "JVBERi0xLj..." } },
    -        { "type": "text", "text": "Quais são as conclusões principais deste documento?" }
    -      ]
    -    }]
    -  }'
    -
    -
    - -

    10.4. PDF via Files API + prompt caching

    -

    Para PDFs reutilizados, faça upload uma vez (Files API, cap. 11) e referencie por file_id; combine com prompt caching colocando cache_control no bloco document.

    -
    # PDF via Files API (beta) — depois referencie por file_id
    -with open("relatorio.pdf", "rb") as f:
    -    up = client.beta.files.upload(file=("relatorio.pdf", f, "application/pdf"))
    -
    -message = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    betas=["files-api-2025-04-14"],
    -    messages=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "document", "source": {"type": "file", "file_id": up.id},
    -             "cache_control": {"type": "ephemeral"}},
    -            {"type": "text", "text": "Resuma o documento."},
    -        ],
    -    }],
    -)
    -
    Nota: em Amazon Bedrock e Vertex AI, apenas fontes base64 estão disponíveis. No Bedrock Converse API, a análise visual completa do PDF exige citações habilitadas; sem isso, há apenas extração de texto.
    -
    - - -
    -

    11. Files API

    -

    A Files API permite fazer upload de arquivos (PDFs, imagens, e outros formatos) uma vez e referenciá-los por file_id em várias requisições — evitando reenviar base64, reduzindo o payload e a latência.

    - -

    Beta Requer o header anthropic-beta: files-api-2025-04-14. No SDK, use o namespace client.beta.files e passe betas=["files-api-2025-04-14"] nas chamadas de mensagem.

    - -

    11.1. Upload e uso

    -
    -
    - - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -
    -# 1) Upload
    -with open("document.pdf", "rb") as f:
    -    file_upload = client.beta.files.upload(file=("document.pdf", f, "application/pdf"))
    -
    -# 2) Referencie por file_id em uma mensagem
    -message = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    betas=["files-api-2025-04-14"],
    -    messages=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "document", "source": {"type": "file", "file_id": file_upload.id}},
    -            {"type": "text", "text": "Quais são as conclusões principais?"},
    -        ],
    -    }],
    -)
    -print(message.content)
    -
    -
    -
    import Anthropic, { toFile } from "@anthropic-ai/sdk";
    -import fs from "fs";
    -
    -const anthropic = new Anthropic();
    -
    -// 1) Upload
    -const fileUpload = await anthropic.beta.files.upload({
    -  file: await toFile(fs.createReadStream("document.pdf"), undefined, { type: "application/pdf" }),
    -});
    -
    -// 2) Referencie por file_id
    -const response = await anthropic.beta.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  betas: ["files-api-2025-04-14"],
    -  messages: [{
    -    role: "user",
    -    content: [
    -      { type: "document", source: { type: "file", file_id: fileUpload.id } },
    -      { type: "text", text: "Quais são as conclusões principais?" },
    -    ],
    -  }],
    -});
    -console.log(response);
    -
    -
    -
    # 1) Upload
    -curl -X POST https://api.anthropic.com/v1/files \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -H "anthropic-beta: files-api-2025-04-14" \
    -  -F "file=@document.pdf"
    -
    -# 2) Use o file_id retornado
    -curl https://api.anthropic.com/v1/messages \
    -  -H "content-type: application/json" \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -H "anthropic-beta: files-api-2025-04-14" \
    -  -d '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{
    -      "role": "user",
    -      "content": [
    -        { "type": "document", "source": { "type": "file", "file_id": "file_abc123" } },
    -        { "type": "text", "text": "Quais são as conclusões principais?" }
    -      ]
    -    }]
    -  }'
    -
    -
    - -

    11.2. Operações de gerenciamento

    -
    - - - - - - - - -
    OperaçãoEndpoint / SDK
    UploadPOST /v1/files · client.beta.files.upload(...)
    ListarGET /v1/files · client.beta.files.list()
    MetadadosGET /v1/files/{file_id} · client.beta.files.retrieve_metadata(file_id)
    Baixar conteúdoGET /v1/files/{file_id}/content · client.beta.files.download(file_id)
    ExcluirDELETE /v1/files/{file_id} · client.beta.files.delete(file_id)
    -
    Dica: além de PDFs e imagens, a Files API aceita outros formatos (.csv, .xlsx, .docx, .md, .txt) — veja “Working with other file formats” na doc de Files. Para conteúdo reutilizado em muitas requisições, Files API + prompt caching é a combinação mais econômica.
    -
    - - -
    -

    12. Citações e resultados de busca (citations & search results)

    -

    As citações fazem o Claude fundamentar afirmações em trechos exatos das fontes que você forneceu (documentos, PDFs, resultados de busca), retornando referências verificáveis. Os search results são um tipo de bloco para alimentar RAG com citações nativas.

    - - -

    12.1. Habilitando citações

    -

    Adicione "citations": {"enabled": true} ao bloco document (ou search_result). Quando habilitado, blocos de texto da resposta podem conter um array citations apontando para o local exato na fonte.

    -
    -
    - - - -
    -
    -
    message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{
    -        "role": "user",
    -        "content": [
    -            {
    -                "type": "document",
    -                "source": {"type": "text", "media_type": "text/plain",
    -                           "data": "O céu é azul devido ao espalhamento de Rayleigh..."},
    -                "title": "Por que o céu é azul",
    -                "citations": {"enabled": True},
    -            },
    -            {"type": "text", "text": "Por que o céu é azul? Cite a fonte."},
    -        ],
    -    }],
    -)
    -for block in message.content:
    -    if block.type == "text":
    -        print(block.text)
    -        for c in (block.citations or []):
    -            print("  citação:", c)
    -
    -
    -
    const message = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{
    -    role: "user",
    -    content: [
    -      {
    -        type: "document",
    -        source: { type: "text", media_type: "text/plain",
    -                  data: "O céu é azul devido ao espalhamento de Rayleigh..." },
    -        title: "Por que o céu é azul",
    -        citations: { enabled: true },
    -      },
    -      { type: "text", text: "Por que o céu é azul? Cite a fonte." },
    -    ],
    -  }],
    -});
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  -H "content-type: application/json" \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -d '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{
    -      "role": "user",
    -      "content": [
    -        { "type": "document",
    -          "source": { "type": "text", "media_type": "text/plain", "data": "O céu é azul devido ao espalhamento de Rayleigh..." },
    -          "title": "Por que o céu é azul",
    -          "citations": { "enabled": true } },
    -        { "type": "text", "text": "Por que o céu é azul? Cite a fonte." }
    -      ]
    -    }]
    -  }'
    -
    -
    - -

    12.2. Tipos de localização de citação

    -
    - - - - - - - -
    TipoFonteCampos de localização
    char_locationDocumento de texto simplesstart_char_index, end_char_index
    page_locationPDFstart_page_number, end_page_number
    content_block_locationDocumento de conteúdo customizado (lista de blocos)start_block_index, end_block_index
    search_result_locationBloco search_resultsearch_result_index, start_block_index, end_block_index
    -

    Cada citação inclui também o cited_text (o trecho exato citado) e o document_index/título, permitindo renderizar referências clicáveis.

    - -

    12.3. Search results (RAG com citações nativas)

    -

    O bloco search_result representa um resultado de busca/recuperação que o Claude pode citar nativamente. Há dois jeitos de fornecê-los:

    -
      -
    • Método 1 — retorno de ferramenta: uma ferramenta de busca devolve blocos search_result dentro do tool_result.
    • -
    • Método 2 — conteúdo de usuário no nível superior: você inclui blocos search_result diretamente no content de uma mensagem do usuário.
    • -
    -

    Schema do bloco search_result:

    -
    {
    -  "type": "search_result",
    -  "source": "https://exemplo.com/artigo",
    -  "title": "Título do resultado",
    -  "content": [ { "type": "text", "text": "Trecho recuperado..." } ],
    -  "citations": { "enabled": true },
    -  "cache_control": { "type": "ephemeral" }
    -}
    -

    Campos: source, title e content são obrigatórios; citations e cache_control são opcionais. O conteúdo é somente texto.

    -
    -
    - - -
    -
    -
    # Método 2: search_result direto no conteúdo do usuário
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{
    -        "role": "user",
    -        "content": [
    -            {
    -                "type": "search_result",
    -                "source": "https://docs.exemplo.com/api/auth",
    -                "title": "Guia de autenticação",
    -                "content": [{"type": "text", "text": "Use o header x-api-key com sua chave de API..."}],
    -                "citations": {"enabled": True},
    -            },
    -            {"type": "text", "text": "Como autenticar? Cite a fonte."},
    -        ],
    -    }],
    -)
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  -H "content-type: application/json" \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -d '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{
    -      "role": "user",
    -      "content": [
    -        { "type": "search_result",
    -          "source": "https://docs.exemplo.com/api/auth",
    -          "title": "Guia de autenticação",
    -          "content": [ { "type": "text", "text": "Use o header x-api-key com sua chave de API..." } ],
    -          "citations": { "enabled": true } },
    -        { "type": "text", "text": "Como autenticar? Cite a fonte." }
    -      ]
    -    }]
    -  }'
    -
    -
    -
    Nota: citações em search_result são tudo-ou-nada — habilite em todos os blocos de uma mesma requisição de forma consistente. Search results estão disponíveis na Claude API, no Amazon Bedrock e no Vertex AI. O conteúdo é somente texto (sem imagens dentro do search_result).
    -
    Dica: use search results em vez de injetar trechos como texto puro quando precisar de citações verificáveis num pipeline RAG: o Claude referencia o índice do resultado e os blocos exatos, e você pode renderizar a fonte clicável para o usuário final.
    -
    - - - - - - - - -
    -

    Parte C — Ferramentas (Tool Use), Skills & MCP

    -

    Esta parte cobre como o Claude chama ferramentas: o contrato tool_use → tool_result, a definição de ferramentas client-side e server-side, o catálogo completo de ferramentas fornecidas pela Anthropic (bash, text editor, computer use, memory, code execution, web search, web fetch, tool search, advisor), os recursos avançados (uso paralelo, chamada programática, modo estrito, streaming refinado, gerenciamento de contexto, combinações, prompt caching), as Agent Skills (SKILL.md + recursos, com divulgação progressiva) e o Model Context Protocol (MCP connector, servidores remotos e MCP tunnels).

    -
    - - - - -
    -

    1. Tool use — como funciona

    - - -

    Tool use (uso de ferramentas / function calling) permite que o Claude chame funções que você define ou que a Anthropic fornece. O Claude decide quando chamar uma ferramenta com base no pedido do usuário e na description da ferramenta; ele então devolve uma chamada estruturada que sua aplicação executa (ferramentas client-side) ou que a Anthropic executa (ferramentas server-side). O modelo nunca executa nada por conta própria: ele emite uma requisição estruturada, alguém roda a operação, e o resultado volta para a conversa.

    - -
    Nota: esse contrato faz o modelo se comportar menos como um gerador de texto e mais como uma função que você chama. A diferença é que quem decide qual função invocar é um modelo de linguagem, com base na conversa. Se você está escrevendo regex para extrair uma decisão da saída do modelo, essa decisão deveria ter sido uma chamada de ferramenta.
    - -

    Onde as ferramentas rodam: os três tipos

    -

    O eixo principal que diferencia ferramentas é onde o código executa. Toda ferramenta cai em uma de três categorias, e a categoria determina pelo que sua aplicação é responsável.

    -
    - - - - - - -
    CategoriaQuem executaExemplosO que você faz
    Ferramentas definidas pelo usuário (client-side)Sua aplicaçãoLógica de negócio, APIs internas, consultas a bancoEscreve o schema, executa o código, devolve o tool_result. É o grosso do tráfego de tool use.
    Ferramentas de schema-Anthropic (client-side)Sua aplicaçãobash, text_editor, computer, memoryMesma mecânica das definidas pelo usuário, mas o schema é treinado-no-modelo, então o Claude as chama de forma mais confiável.
    Ferramentas executadas no servidorAnthropicweb_search, web_fetch, code_execution, tool_searchVocê apenas habilita a ferramenta e lê a resposta final; nunca constrói um tool_result para elas.
    - -

    O loop agêntico (ferramentas client-side)

    -

    Ferramentas client-side (tanto as definidas pelo usuário quanto as de schema-Anthropic) exigem que sua aplicação conduza um loop. O formato canônico é um while baseado em stop_reason:

    -
      -
    1. Envie uma requisição com seu array tools e a mensagem do usuário.
    2. -
    3. O Claude responde com stop_reason: "tool_use" e um ou mais blocos tool_use.
    4. -
    5. Execute cada ferramenta e formate as saídas como blocos tool_result.
    6. -
    7. Envie uma nova requisição contendo as mensagens originais, a resposta do assistente e uma mensagem de usuário com os blocos tool_result.
    8. -
    9. Repita a partir do passo 2 enquanto stop_reason for "tool_use".
    10. -
    -

    O loop termina em qualquer outro motivo de parada ("end_turn", "max_tokens", "stop_sequence" ou "refusal"), o que significa que o Claude produziu uma resposta final ou parou por outro motivo.

    - -

    O loop do lado servidor e pause_turn

    -

    Ferramentas server-side rodam seu próprio loop dentro da infraestrutura da Anthropic. Uma única requisição sua pode disparar várias buscas web ou execuções de código antes de a resposta voltar. Esse loop interno tem um limite de iterações; se o modelo ainda está iterando ao atingir o teto, a resposta volta com stop_reason: "pause_turn" em vez de "end_turn". Um turno pausado significa que o trabalho não terminou: reenvie a conversa (incluindo a resposta pausada) para o modelo continuar. Veja a seção Ferramentas server-side.

    - -

    Quando usar (e quando não usar) ferramentas

    -

    Tool use serve quando a tarefa exige algo que o modelo não consegue fazer só com texto: ações com efeitos colaterais (enviar e-mail, escrever arquivo, atualizar registro), dados frescos ou externos (preços atuais, conteúdo de um banco), saídas estruturadas com formato garantido, e integração com sistemas existentes. Não serve quando o modelo pode responder só com o treino (resumo, tradução, conhecimento geral), quando a interação é Q&A de uma rodada sem efeitos colaterais, ou quando a latência da chamada dominaria uma resposta trivial.

    - -

    Preço do tool use

    -

    Requisições com tool use são cobradas por: (1) total de tokens de entrada enviados ao modelo (incluindo o parâmetro tools); (2) tokens de saída gerados; (3) para ferramentas server-side, cobrança adicional por uso (ex.: web search cobra por busca). Ao usar tools, a API injeta automaticamente um system prompt especial que habilita o tool use. Em todos os modelos atuais, esse prompt de sistema custa 346 tokens para tool_choice auto/none e 313 tokens para any/tool (assumindo ao menos 1 ferramenta; com none e nenhuma ferramenta, 0 tokens). Esses tokens entram nos contadores normais de usage.

    - -
    - - - - - - -
    Modeloauto / noneany / tool
    Claude Opus 4.8 (claude-opus-4-8)346 tokens313 tokens
    Claude Sonnet 4.6 (claude-sonnet-4-6)346 tokens313 tokens
    Claude Haiku 4.5 (claude-haiku-4-5)346 tokens313 tokens
    -
    Nota: esta tabela mostra apenas o custo em tokens do system prompt de tool use por modelo. Para a tabela comparativa de modelos, preços por token, snapshots e orientação de escolha (Opus 4.8 para tarefas complexas/raciocínio, Sonnet 4.6 para equilíbrio, Haiku 4.5 para baixa latência/custo), veja Modelos Claude.
    - -

    Exemplo mínimo (ferramenta server-side)

    -

    O exemplo mais simples usa uma ferramenta server-side, na qual a Anthropic cuida da execução:

    -
    -
    - - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -response = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    tools=[{"type": "web_search_20260209", "name": "web_search"}],
    -    messages=[{"role": "user", "content": "Qual a novidade mais recente do rover em Marte?"}],
    -)
    -print(response.content)
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic();
    -const response = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  tools: [{ type: "web_search_20260209", name: "web_search" }],
    -  messages: [{ role: "user", content: "Qual a novidade mais recente do rover em Marte?" }],
    -});
    -console.log(response.content);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "tools": [{"type": "web_search_20260209", "name": "web_search"}],
    -    "messages": [{"role": "user", "content": "Qual a novidade mais recente do rover em Marte?"}]
    -  }'
    -
    -
    -
    - - - - -
    -

    2. Definindo ferramentas

    - - -

    Ferramentas client-side (tanto de schema-Anthropic quanto definidas pelo usuário) são declaradas no parâmetro de topo tools. Cada definição inclui:

    -
    - - - - - - - -
    ParâmetroDescrição
    nameNome da ferramenta. Deve casar com a regex ^[a-zA-Z0-9_-]{1,64}$.
    descriptionDescrição em texto puro, detalhada, do que a ferramenta faz, quando usá-la e como se comporta.
    input_schemaObjeto JSON Schema definindo os parâmetros esperados.
    input_examples(Opcional) Array de objetos de entrada de exemplo para ajudar o Claude a entender como usar a ferramenta.
    -

    Propriedades opcionais disponíveis em qualquer definição (cache_control, strict, defer_loading, allowed_callers, eager_input_streaming) estão na Referência de ferramentas.

    - -

    Exemplo de definição simples

    -
    {
    -  "name": "get_weather",
    -  "description": "Get the current weather in a given location",
    -  "input_schema": {
    -    "type": "object",
    -    "properties": {
    -      "location": {
    -        "type": "string",
    -        "description": "The city and state, e.g. San Francisco, CA"
    -      },
    -      "unit": {
    -        "type": "string",
    -        "enum": ["celsius", "fahrenheit"],
    -        "description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
    -      }
    -    },
    -    "required": ["location"]
    -  }
    -}
    - -

    Boas práticas para descrições

    -
      -
    • Descrições extremamente detalhadas — de longe o fator mais importante. Explique o que a ferramenta faz, quando (e quando não) usar, o que cada parâmetro significa e quaisquer limitações. Mire em pelo menos 3–4 frases por ferramenta.
    • -
    • Considere input_examples para ferramentas complexas — com objetos aninhados, parâmetros opcionais ou formatos sensíveis. Cada exemplo deve ser válido perante o input_schema (exemplos inválidos retornam erro 400). Custo: ~20–50 tokens para exemplos simples, ~100–200 para objetos aninhados complexos. Não disponível em ferramentas server-side.
    • -
    • Consolide operações relacionadas em menos ferramentas — em vez de create_pr, review_pr, merge_pr, prefira uma ferramenta com um parâmetro action.
    • -
    • Use namespacing nos nomes — quando as ferramentas abrangem vários serviços, prefixe com o serviço (github_list_prs, slack_send_message). Isso é especialmente importante ao usar tool search.
    • -
    • Desenhe respostas com informação de alto sinal — retorne identificadores estáveis (slugs, UUIDs) e só os campos de que o Claude precisa. Respostas inchadas desperdiçam contexto.
    • -
    - -

    Controlando a saída: tool_choice

    -

    Há quatro opções para o campo tool_choice:

    -
    - - - - - - - -
    ValorComportamento
    autoO Claude decide se chama alguma ferramenta. Padrão quando há tools.
    anyO Claude deve usar uma das ferramentas, sem forçar uma específica.
    toolForça sempre uma ferramenta específica: {"type": "tool", "name": "get_weather"}.
    noneImpede o uso de qualquer ferramenta. Padrão quando não há tools.
    -
    Atenção: com any ou tool, a API faz prefill da mensagem do assistente para forçar a ferramenta — o modelo não emite texto natural antes dos blocos tool_use. Com adaptive/extended thinking, tool_choice any e tool não são suportados e geram erro; apenas auto (padrão) e none são compatíveis. Mudar tool_choice sob prompt caching invalida blocos de mensagem em cache.
    -
    Dica: combine tool_choice: {"type": "any"} com strict tool use (strict: true) para garantir tanto que uma ferramenta será chamada quanto que os inputs seguem o schema exatamente.
    -
    - -
    -

    2.1. Tratando chamadas de ferramenta (handle-tool-calls)

    - - -

    Para ferramentas client-side, a resposta tem stop_reason: "tool_use" e um ou mais blocos tool_use com id (identificador único, casado depois pelo resultado), name e input (objeto conforme o input_schema). Ao receber, você deve: (1) extrair name, id e input; (2) rodar a ferramenta correspondente; (3) continuar a conversa enviando uma mensagem user com um bloco tool_result.

    - -

    O bloco tool_result tem:

    -
      -
    • tool_use_id: o id da requisição tool_use que este resultado responde.
    • -
    • content (opcional): o resultado, como string ("15 degrees"), lista de blocos aninhados, ou blocos de documento. Pode usar tipos text, image ou document.
    • -
    • is_error (opcional): true se a execução resultou em erro.
    • -
    - -
    Cuidado — requisitos de formatação: os blocos tool_result devem vir imediatamente após os blocos tool_use correspondentes; não pode haver mensagens entre a mensagem do assistente (com tool_use) e a mensagem do usuário (com tool_result). Dentro da mensagem de usuário, os blocos tool_result devem vir primeiro no array de content; qualquer texto vem depois. Texto antes do tool_result causa erro 400 (tool_use ids were found without tool_result blocks immediately after).
    - -

    Exemplo de resultado bem-sucedido e de resultado de erro:

    -
    {
    -  "role": "user",
    -  "content": [
    -    { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "15 degrees" }
    -  ]
    -}
    -
    {
    -  "role": "user",
    -  "content": [
    -    {
    -      "type": "tool_result",
    -      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    -      "content": "ConnectionError: the weather service API is not available (HTTP 500)",
    -      "is_error": true
    -    }
    -  ]
    -}
    - -
    Dica: escreva mensagens de erro instrutivas. Em vez de "failed", inclua o que deu errado e o que o Claude deve tentar a seguir (ex.: "Rate limit exceeded. Retry after 60 seconds."). Se uma chamada é inválida ou falta um parâmetro, o Claude tenta de novo 2–3 vezes antes de se desculpar. Para servidor, o Claude trata erros transparentemente — você não precisa lidar com is_error em ferramentas server-side.
    - -

    Para web search, os códigos de erro possíveis incluem: too_many_requests (limite de taxa), invalid_input (query inválida), max_uses_exceeded (limite de buscas excedido), query_too_long e unavailable (erro interno).

    - -
    Nota — diferença de outras APIs: diferentemente de APIs que usam papéis especiais (tool/function), a Claude API integra ferramentas diretamente nas mensagens user e assistant. Mensagens contêm arrays de blocos text, image, tool_use e tool_result: mensagens user incluem conteúdo do cliente e tool_result; mensagens assistant contêm conteúdo gerado e tool_use.
    -
    - - - - -
    -

    3. Tipos de ferramentas e referência (catálogo)

    - - -

    A Anthropic fornece dois tipos: ferramentas server-side (executam na infraestrutura da Anthropic) e ferramentas client-side de schema-Anthropic (a Anthropic define o schema, sua aplicação executa). Ambas aparecem no array tools junto com suas ferramentas próprias. O catálogo abaixo lista os valores exatos de type e os headers beta — verificados na doc oficial.

    - -
    - - - - - - - - - - - - - -
    FerramentatypeExecuçãoStatus
    Web searchweb_search_20260209
    web_search_20250305
    ServidorGA
    Web fetchweb_fetch_20260209
    web_fetch_20250910
    ServidorGA
    Code executioncode_execution_20260120
    code_execution_20250825
    ServidorGA
    Advisoradvisor_20260301ServidorBeta advisor-tool-2026-03-01
    Tool searchtool_search_tool_regex_20251119
    tool_search_tool_bm25_20251119
    ServidorGA
    MCP connectormcp_toolsetServidorBeta mcp-client-2025-11-20
    Memorymemory_20250818ClienteGA
    Bashbash_20250124ClienteGA
    Text editortext_editor_20250728
    text_editor_20250124
    ClienteGA
    Computer usecomputer_20251124
    computer_20250124
    ClienteBeta computer-use-2025-11-24 / computer-use-2025-01-24
    -
    Nota: os valores de tool search também aceitam aliases sem data (tool_search_tool_regex, tool_search_tool_bm25), que resolvem para a versão datada mais recente.
    - -

    Versionamento de ferramentas

    -

    A maioria das ferramentas carrega o sufixo _YYYYMMDD no type. Uma nova versão sai quando o comportamento, o schema ou o suporte a modelos muda; as versões antigas continuam disponíveis. As relações variam:

    -
      -
    • Por capacidade: web_search_20260209 / web_fetch_20260209 adicionam filtragem dinâmica de conteúdo; code_execution_20260120 adiciona chamada programática de ferramentas. Em cada caso, ambas as versões são atuais — você escolhe conforme precisa da nova capacidade.
    • -
    • Por modelo: text_editor_20250728 é para modelos Claude 4; text_editor_20250124 é para modelos anteriores.
    • -
    • Variante, não versão: tool_search_tool_regex_20251119 e tool_search_tool_bm25_20251119 são dois algoritmos lançados juntos; nenhum substitui o outro.
    • -
    • O mcp_toolset não é versionado por data — o versionamento vai no header anthropic-beta.
    • -
    - -

    Propriedades opcionais de definição (em qualquer ferramenta)

    -
    - - - - - - - - - -
    PropriedadeFinalidadeDisponível em
    cache_controlDefine um breakpoint de prompt cache nesta definiçãoTodas as ferramentas
    strictGarante validação de schema sobre nomes e inputsTodas, exceto mcp_toolset
    defer_loadingExclui a ferramenta do system prompt inicial; carrega sob demanda via tool searchTodas (para mcp_toolset, ver config do toolset)
    allowed_callersRestringe quais chamadores podem invocar a ferramentaTodas, exceto mcp_toolset
    input_examplesExemplos de inputFerramentas de usuário e de schema-Anthropic (não server-side)
    eager_input_streamingHabilita streaming refinado de inputApenas ferramentas definidas pelo usuário
    -

    O allowed_callers é um array que aceita "direct" (o modelo chama diretamente num bloco tool_use — padrão) e/ou "code_execution_20260120" (código rodando dentro de um sandbox de code execution pode chamar a ferramenta). Omitir "direct" torna a ferramenta chamável só de dentro do code execution. Ferramentas com defer_loading: true são removidas do prefixo antes do cálculo da chave de cache, preservando o prompt cache.

    -
    - - - - -
    -

    4. Ferramentas client-side detalhadas

    -

    As quatro ferramentas de schema-Anthropic client-side (bash, text_editor, computer, memory) mais a server-side code_execution (incluída aqui por proximidade conceitual). A vantagem de usar uma ferramenta de schema-Anthropic em vez de criar a sua equivalente é que esses schemas são treinados-no-modelo: o Claude foi otimizado em milhares de trajetórias bem-sucedidas com essas assinaturas exatas, então ele as chama de forma mais confiável.

    -
    - -
    -

    4.1. Bash tool — bash_20250124

    - -

    A bash tool permite ao Claude executar comandos shell em uma sessão bash persistente, viabilizando operações de sistema, scripts e automação de linha de comando. A sessão mantém estado (variáveis de ambiente, diretório de trabalho) entre comandos. GA · ZDR elegível.

    -

    É uma ferramenta schema-less: você não fornece input_schema — o schema está embutido no modelo e não pode ser modificado. Parâmetros: command (obrigatório, salvo quando se usa restart) e restart (opcional, true reinicia a sessão).

    -
    -
    - - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -response = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    tools=[{"type": "bash_20250124", "name": "bash"}],
    -    messages=[{"role": "user", "content": "List all Python files in the current directory."}],
    -)
    -print(response)
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic();
    -const response = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  tools: [{ type: "bash_20250124", name: "bash" }],
    -  messages: [{ role: "user", content: "List all Python files in the current directory." }],
    -});
    -console.log(response);
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "content-type: application/json" \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "tools": [{"type": "bash_20250124", "name": "bash"}],
    -    "messages": [{"role": "user", "content": "List all Python files in the current directory."}]
    -  }'
    -
    -
    -
    Cuidado: a bash tool dá ao Claude acesso a shell. Rode-a em um ambiente isolado (VM/contêiner com privilégios mínimos), restrinja o diretório de trabalho e considere uma allowlist de comandos quando o agente opera sobre código não confiável.
    -
    - -
    -

    4.2. Text editor tool — text_editor_20250728

    - -

    Permite ao Claude visualizar e modificar arquivos de texto — depurar, refatorar, gerar documentação, criar testes. A ferramenta tem o nome str_replace_based_edit_tool. Para modelos Claude 4 use text_editor_20250728; para modelos anteriores, text_editor_20250124. GA · ZDR elegível. Você pode opcionalmente passar max_characters para controlar a truncagem ao ler arquivos grandes (compatível com text_editor_20250728+).

    -

    Comandos suportados:

    -
    - - - - - - - -
    ComandoParâmetrosO que faz
    viewpath, view_range (opcional, [início, fim], 1-indexado, -1 = fim do arquivo)Lê arquivo (ou intervalo de linhas) ou lista um diretório.
    str_replacepath, old_str (deve casar exatamente, incluindo espaços), new_strSubstitui um trecho específico por outro. Edição precisa.
    createpath, file_textCria um novo arquivo com o conteúdo dado.
    insertpath, insert_line (0 = começo), insert_textInsere texto após a linha indicada.
    -
    {
    -  "type": "tool_use",
    -  "id": "toolu_01A09q90qw90lq917835lq9",
    -  "name": "str_replace_based_edit_tool",
    -  "input": {
    -    "command": "str_replace",
    -    "path": "primes.py",
    -    "old_str": "for num in range(2, limit + 1)",
    -    "new_str": "for num in range(2, limit + 1):"
    -  }
    -}
    -
    - -
    -

    4.3. Computer use tool — computer_20251124

    - -

    Permite ao Claude interagir com ambientes de desktop: captura de tela, controle de mouse/teclado, automação. Beta — exige um header beta:

    -
      -
    • computer-use-2025-11-24 (tipo computer_20251124) para Claude Opus 4.8 e Sonnet 4.6.
    • -
    • computer-use-2025-01-24 (tipo computer_20250124) para Claude Haiku 4.5.
    • -
    -

    ZDR elegível. Parâmetros da definição: display_width_px, display_height_px e display_number. Frequentemente combinado com text_editor e bash.

    -

    Ações disponíveis:

    -
    - - - - - - -
    GrupoAções
    Básicas (todas as versões)screenshot, left_click (com coordinate [x,y]), type, key (ex.: "ctrl+s"), mouse_move
    Aprimoradas (computer_20250124)scroll, left_click_drag, right_click, middle_click, double_click, triple_click, left_mouse_down/left_mouse_up, hold_key, wait
    Aprimoradas (computer_20251124)Todas as anteriores + zoom (ver uma região em resolução plena; exige enable_zoom: true e um region [x1,y1,x2,y2])
    -

    Para teclas modificadoras (Shift, Ctrl, Alt) durante clique/scroll, use o parâmetro text na própria ação (ex.: {"action": "left_click", "coordinate": [500,300], "text": "shift"}).

    -
    -
    - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -response = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    tools=[
    -        {"type": "computer_20251124", "name": "computer",
    -         "display_width_px": 1024, "display_height_px": 768, "display_number": 1},
    -        {"type": "text_editor_20250728", "name": "str_replace_based_edit_tool"},
    -        {"type": "bash_20250124", "name": "bash"},
    -    ],
    -    messages=[{"role": "user", "content": "Save a picture of a cat to my desktop."}],
    -    betas=["computer-use-2025-11-24"],
    -)
    -print(response)
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "content-type: application/json" \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "anthropic-beta: computer-use-2025-11-24" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "tools": [
    -      {"type": "computer_20251124", "name": "computer",
    -       "display_width_px": 1024, "display_height_px": 768, "display_number": 1}
    -    ],
    -    "messages": [{"role": "user", "content": "Save a picture of a cat to my desktop."}]
    -  }'
    -
    -
    -
    Cuidado: computer use tem riscos próprios, ampliados ao acessar a internet. Use uma VM/contêiner dedicado de privilégio mínimo, evite dar acesso a dados sensíveis, restrinja a internet a uma allowlist de domínios e peça confirmação humana para ações de consequência real. O Claude pode seguir instruções encontradas em conteúdo (prompt injection via páginas/imagens). A Anthropic treina o modelo para resistir e roda classificadores que pedem confirmação ao detectar injeções em screenshots — proteção que pode ser desativada via suporte para casos sem humano no loop. Há uma implementação de referência (contêiner Docker, ferramentas, loop de agente, UI web).
    -
    - -
    -

    4.4. Memory tool — memory_20250818

    - -

    Permite ao Claude armazenar e recuperar informação entre conversas, via um diretório de arquivos de memória. É o primitivo-chave para recuperação just-in-time: em vez de carregar tudo de uma vez, o agente guarda o que aprende e recupera sob demanda, mantendo o contexto ativo focado. GA · ZDR elegível.

    -

    A ferramenta é client-side: você controla onde e como os dados são guardados. O Claude faz chamadas de ferramenta e sua aplicação as executa localmente. Por segurança, restrinja todas as operações ao diretório /memories. Os SDKs trazem helpers (subclasse de BetaAbstractMemoryTool em Python; betaMemoryTool em TypeScript).

    -

    Comandos que sua implementação precisa tratar: view (lista diretório ou mostra arquivo, com view_range opcional), create (path, file_text), str_replace (old_str/new_str), insert (insert_line, insert_text), delete (recursivo para diretórios) e rename (old_path/new_path; não sobrescreve destino existente).

    -

    Quando habilitada, a Anthropic injeta automaticamente no system prompt o protocolo de memória: "IMPORTANT: ALWAYS VIEW YOUR MEMORY DIRECTORY BEFORE DOING ANYTHING ELSE", lembrando o Claude de checar progresso anterior e gravar status, pois o contexto pode ser resetado a qualquer momento.

    -
    Cuidado — path traversal: inputs maliciosos podem tentar acessar arquivos fora de /memories. Sua implementação DEVE validar todos os caminhos: confirmar que começam com /memories, resolver para a forma canônica e verificar que permanecem no diretório, rejeitar sequências como ../, ..\\ e variantes URL-encoded (%2e%2e%2f), e usar utilitários nativos (pathlib.Path.resolve() + relative_to() em Python). Considere também limitar tamanho de arquivos e expirar memórias antigas.
    -

    A memory tool combina com context editing (limpa tool_result antigos no cliente) e com compaction (sumariza a conversa no servidor): use ambos em fluxos longos — a memória persiste o que é crítico através das fronteiras de compactação.

    -
    - -
    -

    4.5. Code execution tool — code_execution_20250825 / code_execution_20260120

    - -

    Roda código Python e Bash em um contêiner isolado para analisar dados, gerar arquivos e iterar sobre soluções. É um primitivo central para agentes de alto desempenho — habilita a filtragem dinâmica de web search/web fetch. GA (server-side) desde 2026-02-17, sem header beta (confirmado na doc oficial em 2026-06-10; o header legado code-execution-2025-08-25 segue aceito por compatibilidade — alguns exemplos de SDK ainda o usam via namespace beta). Não é elegível para ZDR.

    -
    Dica: code execution é gratuito quando usado com web search ou web fetch — incluindo web_search_20260209 ou web_fetch_20260209, não há cobrança extra por chamadas de code execution além dos custos normais de token. As cobranças padrão de code execution aplicam-se quando essas ferramentas não estão presentes.
    -

    Versões: code_execution_20250825 suporta comandos Bash e operações de arquivo e roda em todos os modelos atuais; code_execution_20260120 adiciona persistência de estado do REPL e chamada programática de ferramentas a partir do sandbox, disponível em Opus 4.5+ e Sonnet 4.5+ (inclui Opus 4.8/4.7/4.6 e Sonnet 4.6; não Haiku 4.5). A legada code_execution_20250522 é só Python.

    -
    Atenção: versões antigas não têm compatibilidade retroativa garantida com modelos novos. Use a versão que corresponde ao seu modelo. Haiku 4.5 suporta apenas code_execution_20250825. Code execution está disponível na Claude API, Claude Platform on AWS e Microsoft Foundry; não está em Amazon Bedrock nem Vertex AI.
    -

    Contêiner (runtime): Python 3.11.12, Linux x86_64, 5 GiB de RAM, 5 GiB de disco, 1 CPU. Sem acesso à internet e isolamento total do host. Contêineres expiram 30 dias após a criação e são escopados ao workspace da API key. Bibliotecas pré-instaladas incluem pandas, numpy, scipy, scikit-learn, matplotlib, seaborn, pyarrow, openpyxl, pillow, python-pptx, python-docx, pypdf, pdfplumber, reportlab, sympy, sqlite, ripgrep, entre outras.

    -

    Você pode reutilizar um contêiner entre requisições passando o container ID de uma resposta anterior, mantendo arquivos criados. Para enviar seus próprios arquivos, use a Files API (header files-api-2025-04-14) e referencie-os com um bloco container_upload ({"type": "container_upload", "file_id": "file_abc123"}).

    -
    -
    - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -response = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=4096,
    -    messages=[{"role": "user",
    -               "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"}],
    -    tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
    -)
    -print(response)
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 4096,
    -    "messages": [{"role": "user", "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"}],
    -    "tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
    -  }'
    -
    -
    -
    - - - - -
    -

    5. Ferramentas server-side

    - -

    Ferramentas server-side (web_search, web_fetch, code_execution, tool_search) executam na infraestrutura da Anthropic. Quando uma roda, aparece um bloco server_tool_use na resposta, com id prefixado por srvtoolu_ (vs. toolu_ das ferramentas de cliente). O resultado aparece logo após, no mesmo turno do assistente — você não responde com tool_result.

    -
    {
    -  "type": "server_tool_use",
    -  "id": "srvtoolu_01A2B3C4D5E6F7G8H9",
    -  "name": "web_search",
    -  "input": { "query": "latest quantum computing breakthroughs" }
    -}
    - -

    Continuação com pause_turn

    -

    O loop interno tem limite de iterações; ao atingi-lo, a resposta volta com stop_reason: "pause_turn". Para continuar, reenvie a conversa passando a resposta pausada como mensagem assistant (preservando as mesmas ferramentas). Você pode opcionalmente modificar o conteúdo antes de continuar.

    - -

    ZDR e allowed_callers

    -

    As versões básicas — web_search_20250305 e web_fetch_20250910 — são elegíveis para Zero Data Retention (ZDR). As versões _20260209 com filtragem dinâmica não são ZDR-elegíveis por padrão (a filtragem usa code execution internamente). Para usá-las com ZDR, desabilite a filtragem dinâmica com "allowed_callers": ["direct"], restringindo a ferramenta à invocação direta.

    - -

    Filtragem de domínio

    -

    Ferramentas que acessam a web aceitam allowed_domains e blocked_domains (use um ou outro, nunca ambos na mesma requisição). Regras: domínios sem esquema HTTP/HTTPS (example.com, não https://example.com); subdomínios são incluídos automaticamente (example.com cobre docs.example.com); subcaminhos são suportados (example.com/blog casa example.com/blog/post-1); curinga (*) apenas um por entrada, e só após a parte do domínio (válido: example.com/*; inválido: *.example.com). Restrições no nível da requisição devem ser compatíveis com as do nível da organização no Console (só podem restringir mais, nunca ampliar).

    -
    Atenção: caracteres Unicode em nomes de domínio podem criar ataques de homógrafos (ex.: аmazon.com com 'а' cirílico parece amazon.com). Prefira nomes ASCII e teste seus filtros contra variações de homógrafos.
    -
    Atenção: incluir uma ferramenta code_execution autônoma ao lado das versões _20260209 dos tools web cria dois ambientes de execução, o que pode confundir o modelo. Use um ou outro, ou fixe ambos na mesma versão.
    -
    - -
    -

    5.1. Web search — web_search_20260209 / web_search_20250305

    - -

    Dá ao Claude acesso a conteúdo web em tempo real, com citações das fontes. A versão mais recente (web_search_20260209) suporta filtragem dinâmica em Claude Opus 4.8 e Sonnet 4.6: o Claude escreve e executa código para filtrar os resultados antes de chegarem ao contexto, melhorando a precisão e reduzindo tokens. A versão anterior (web_search_20250305) permanece disponível sem filtragem dinâmica. GA.

    -
    Nota: a filtragem dinâmica requer a ferramenta code execution habilitada. O administrador da organização deve habilitar web search no Console. A filtragem dinâmica está na Claude API, Claude Platform on AWS e Microsoft Foundry; em Vertex AI só a busca básica; não está em Amazon Bedrock.
    -

    Parâmetros da definição:

    -
    - - - - - - -
    ParâmetroDescrição
    max_usesLimita o nº de buscas por requisição. Exceder gera erro max_uses_exceeded.
    allowed_domains / blocked_domainsFiltragem de domínio (ver seção acima).
    user_locationLocaliza resultados: type: "approximate", city, region, country, timezone (ID IANA).
    -

    A resposta inclui blocos server_tool_use (a query usada) e web_search_tool_result com web_search_result (url, title, encrypted_content, page_age), e o texto final com citações.

    -
    {
    -  "type": "web_search_20250305",
    -  "name": "web_search",
    -  "max_uses": 5,
    -  "allowed_domains": ["example.com", "trusteddomain.org"],
    -  "user_location": {
    -    "type": "approximate",
    -    "city": "San Francisco",
    -    "region": "California",
    -    "country": "US",
    -    "timezone": "America/Los_Angeles"
    -  }
    -}
    -
    - -
    -

    5.2. Web fetch — web_fetch_20260209 / web_fetch_20250910

    - -

    Recupera o conteúdo completo de páginas web e documentos PDF específicos (com extração automática de texto para PDFs) e responde com citações opcionais. A versão web_fetch_20260209 suporta filtragem dinâmica (Opus 4.8, Sonnet 4.6), útil para extrair seções de documentos longos. GA. Não suporta sites renderizados dinamicamente com JavaScript.

    -
    Cuidado — exfiltração de dados: habilitar web fetch em ambientes onde o Claude processa entrada não confiável junto a dados sensíveis cria risco de exfiltração. Para mitigar, o Claude não pode construir URLs dinamicamente — só busca URLs fornecidas explicitamente pelo usuário ou vindas de resultados anteriores de web search/web fetch. Ainda há risco residual: considere desabilitar a ferramenta, usar max_uses para limitar requisições, e allowed_domains para restringir a domínios seguros.
    -

    Parâmetros principais: max_uses, allowed_domains/blocked_domains, e citações (habilitadas via citations: { enabled: true } no resultado). O resultado (web_fetch_tool_result / web_fetch_result) traz a URL, um bloco document com o texto, title e retrieved_at. As citações usam char_location com document_index, start_char_index/end_char_index e cited_text.

    -
    - - - -
    -

    5.4. Advisor tool — advisor_20260301

    - -

    Pareia um modelo executor mais rápido e barato com um modelo advisor de maior inteligência que dá orientação estratégica no meio da geração. O advisor lê toda a conversa e produz um plano ou correção de rumo (tipicamente 400–700 tokens de texto), e o executor continua. Encaixa em cargas agênticas de longo horizonte (agentes de coding, computer use, pesquisa multi-passo) onde a maioria dos turnos é mecânica mas um excelente plano é crucial. Beta — header advisor-tool-2026-03-01. ZDR elegível.

    -

    O modelo executor (campo model de topo) e o advisor (campo model dentro da definição da ferramenta) devem formar um par válido — o advisor deve ser ao menos tão capaz quanto o executor:

    -
    - - - - - - -
    ExecutorAdvisor
    Claude Haiku 4.5 (claude-haiku-4-5)Claude Opus 4.8 (claude-opus-4-8)
    Claude Sonnet 4.6 (claude-sonnet-4-6)Claude Opus 4.8 (claude-opus-4-8)
    Claude Opus 4.8 (claude-opus-4-8)Claude Opus 4.8 (claude-opus-4-8)
    -

    Par inválido retorna 400 invalid_request_error. Disponível em beta na Claude API e Claude Platform on AWS (não em Bedrock, Vertex AI ou Microsoft Foundry). Desde 02/06/2026, a definição da ferramenta aceita max_tokens (tools[].max_tokens) para limitar a saída do advisor por chamada — reduz latência e custo quando você não precisa de orientações longas.

    -
    -
    - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -response = client.beta.messages.create(
    -    model="claude-sonnet-4-6",          # executor
    -    max_tokens=4096,
    -    betas=["advisor-tool-2026-03-01"],
    -    tools=[{"type": "advisor_20260301", "name": "advisor", "model": "claude-opus-4-8"}],  # advisor
    -    messages=[{"role": "user", "content": "Build a concurrent worker pool in Go with graceful shutdown."}],
    -)
    -print(response)
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "anthropic-beta: advisor-tool-2026-03-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-sonnet-4-6",
    -    "max_tokens": 4096,
    -    "tools": [{"type": "advisor_20260301", "name": "advisor", "model": "claude-opus-4-8"}],
    -    "messages": [{"role": "user", "content": "Build a concurrent worker pool in Go with graceful shutdown."}]
    -  }'
    -
    -
    -
    - - - - -
    -

    6. Recursos avançados de tool use

    -

    Recursos que melhoram desempenho, confiabilidade, latência e custo de contexto em fluxos agênticos.

    -
    - -
    -

    6.1. Uso paralelo de ferramentas

    - -

    Por padrão, o Claude pode usar várias ferramentas para responder a uma query. As chamadas em um único turno são não ordenadas: você pode rodá-las concorrentemente (Promise.all, asyncio.gather) ou em sequência. Para desabilitar, use disable_parallel_tool_use=true: com tool_choice: auto garante no máximo uma ferramenta; com any/tool, garante exatamente uma.

    -
    Dica: envie todos os tool_result em uma única mensagem de usuário (não um por turno) para manter o paralelismo funcionando nos turnos seguintes. Se o Claude ocasionalmente agrupar chamadas que dependem entre si (ex.: criar e depois atualizar o mesmo recurso), não precisa detectar isso antes: despache tudo e, se uma falhar, devolva o erro natural em um tool_result com is_error: true — o Claude reconhece a dependência e refaz a chamada.
    -
    - -
    -

    6.2. Chamada programática de ferramentas (programmatic tool calling)

    - -

    Permite ao Claude escrever código que chama suas ferramentas programaticamente dentro do sandbox de code execution, em vez de exigir round trips pelo modelo a cada invocação. Reduz latência em fluxos multi-ferramenta e diminui o consumo de tokens (o Claude filtra/processa dados antes de chegarem ao contexto). Ex.: checar conformidade de orçamento de 20 funcionários — em vez de 20 round trips com milhares de linhas no contexto, um único script roda as 20 consultas, filtra e retorna só quem excedeu o limite.

    -

    Requer code_execution_20260120, suportado em Opus 4.5+ e Sonnet 4.5+ (inclui Opus 4.8/4.7/4.6 e Sonnet 4.6; não Haiku 4.5). Não é ZDR-elegível. Disponível na Claude API, Claude Platform on AWS e Microsoft Foundry (não em Bedrock/Vertex AI).

    -

    Marque a ferramenta com "allowed_callers": ["code_execution_20260120"] para torná-la chamável de dentro do sandbox. O bloco tool_use da resposta inclui um campo caller identificando quem chamou. Monitore expires_at do contêiner: se ele expira enquanto aguarda seu tool_result, o Claude pode tratar como timeout e refazer.

    -
    {
    -  "type": "code_execution_20260120",
    -  "name": "code_execution"
    -}
    -{
    -  "name": "query_database",
    -  "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
    -  "input_schema": { "type": "object", "properties": { "sql": {"type": "string"} }, "required": ["sql"] },
    -  "allowed_callers": ["code_execution_20260120"]
    -}
    -
    - -
    -

    6.3. Modo estrito (strict tool use)

    - -

    Definir strict: true na definição de uma ferramenta garante que os inputs do Claude casem com seu JSON Schema, restringindo a amostragem de tokens a saídas válidas (grammar-constrained sampling). Sem modo estrito, o Claude pode retornar tipos incompatíveis ("2" em vez de 2) ou campos faltando. Use para validar parâmetros, construir fluxos agênticos e garantir chamadas type-safe — funções recebem argumentos corretamente tipados toda vez, sem precisar validar e refazer. Disponível em todas as ferramentas exceto mcp_toolset.

    -
    Atenção: a gramática usa apenas o subconjunto suportado de JSON Schema. Por exemplo, pattern com strict: true gera erro (string patterns are not supported) — remova o pattern ou o strict. Inclua "additionalProperties": false no schema.
    -
    {
    -  "name": "get_weather",
    -  "description": "Get the current weather in a given location",
    -  "strict": true,
    -  "input_schema": {
    -    "type": "object",
    -    "properties": {
    -      "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA" },
    -      "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
    -    },
    -    "required": ["location"],
    -    "additionalProperties": false
    -  }
    -}
    -
    - -
    -

    6.4. Streaming refinado de input (fine-grained tool streaming)

    - -

    Permite fazer streaming dos valores de parâmetro de uma ferramenta sem buffering nem validação de JSON no servidor, reduzindo a latência para começar a receber parâmetros grandes. Disponível em todos os modelos e plataformas. Habilite com eager_input_streaming: true em qualquer ferramenta definida pelo usuário, e ative stream na requisição. ZDR elegível.

    -
    Atenção: com streaming refinado você pode receber JSON inválido ou parcial. Trate esses casos no seu código.
    -
    - -
    -

    6.5. Gerenciando o contexto das ferramentas

    - -

    Definições de ferramentas e blocos tool_result acumulados consomem o contexto. Quatro abordagens atacam fontes diferentes de pressão:

    -
    - - - - - - - -
    AbordagemO que reduzQuando encaixa
    Tool searchDefinições carregadas no inícioToolsets grandes (20+) onde a maioria não é necessária a cada turno
    Programmatic tool callingRound trips de tool_resultCadeias de chamadas que podem rodar como um único script
    Prompt cachingCusto de tokens das definições repetidasToolsets estáveis em muitas requisições
    Context editingBlocos tool_result antigos no históricoConversas longas onde resultados antigos já não importam
    -

    Elas compõem. Ponto de partida para um agente de alto volume: (1) habilite prompt caching nas definições desde o dia 1; (2) adicione tool search quando passar de ~20 ferramentas; (3) adicione context editing quando as conversas começarem a ficar longas; (4) considere programmatic tool calling se notar cadeias repetitivas de chamadas pequenas.

    -
    - -
    -

    6.6. Combinações de ferramentas

    - -

    Pareamentos comuns das ferramentas fornecidas pela Anthropic — pontos de partida, não prescrições:

    -
    - - - - - - - - -
    PadrãoFerramentasUso
    Agente de pesquisaweb_search + code_executionBusca encontra fontes; code execution analisa e sintetiza (ex.: comparar resultados financeiros computando sobre os dados).
    Agente de codingtext_editor + bashO loop canônico de dev: inspeciona código, edita, roda testes, repete. Pareie com diretório restrito e allowlist de comandos.
    Cite-then-fetchweb_search + web_fetchBusca traz URLs candidatas; fetch recupera só as 2–3 relevantes, evitando baixar tudo.
    Agente de longa duraçãomemory + qualquer toolsetMemória persiste estado entre conversas; é ortogonal ao resto do toolset.
    Tudo-em-umcomputer_useOpera um desktop completo — alcança qualquer app que um humano alcança. É a opção mais geral e a mais lenta (cada ação é um round trip de screenshot).
    -
    - -
    -

    6.7. Tool use com prompt caching

    - -

    Coloque cache_control: {"type": "ephemeral"} na última ferramenta do array tools para cachear todo o prefixo de definições (da primeira até o breakpoint). Para mcp_toolset, coloque o breakpoint na própria entrada do toolset — a API o aplica à última ferramenta expandida. Ferramentas com defer_loading: true não entram no prefixo (são adicionadas inline como tool_reference quando descobertas), então adicionar ferramentas via tool search não quebra o cache.

    -

    O cache segue a hierarquia de prefixo tools → system → messages; mudar um nível invalida ele e tudo depois:

    -
    - - - - - - - - - -
    MudançaInvalida
    Modificar definições de ferramentasCache inteiro (tools, system, messages)
    Ligar/desligar web search ou citaçõesCaches de system e messages
    Mudar tool_choiceCache de messages
    Mudar disable_parallel_tool_useCache de messages
    Alternar presença de imagensCache de messages
    Mudar parâmetros de thinkingCache de messages
    -
    - -
    -

    6.8. Tool Runner (SDK)

    - -

    O Tool Runner é a abstração do SDK que conduz o loop agêntico, embrulha erros e dá segurança de tipos automaticamente — roda as ferramentas quando o Claude as chama, gerencia o ciclo requisição/resposta e o estado da conversa. Beta, disponível nos SDKs Python, TypeScript, C#, Go, Java, PHP e Ruby. Use o loop manual quando precisar de aprovação humana, logging customizado ou execução condicional.

    -

    Em Python, o decorador @beta_tool deriva o JSON Schema a partir das anotações de tipo e da docstring da função (use @beta_async_tool no cliente assíncrono). Em TypeScript, prefira betaZodTool() (validação Zod, requer Zod 3.25.0+) ou betaTool() (baseado em JSON Schema).

    -
    -
    - - -
    -
    -
    import json
    -from anthropic import Anthropic, beta_tool
    -
    -client = Anthropic()
    -
    -@beta_tool
    -def get_weather(location: str, unit: str = "fahrenheit") -> str:
    -    """Get the current weather in a given location.
    -
    -    Args:
    -        location: The city and state, e.g. San Francisco, CA
    -        unit: Temperature unit, either 'celsius' or 'fahrenheit'
    -    """
    -    return json.dumps({"temperature": "20°C", "condition": "Sunny"})
    -
    -runner = client.beta.messages.tool_runner(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    tools=[get_weather],
    -    messages=[{"role": "user", "content": "What's the weather like in Paris?"}],
    -)
    -for message in runner:
    -    print(message)
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
    -import { z } from "zod";
    -
    -const client = new Anthropic();
    -
    -const getWeatherTool = betaZodTool({
    -  name: "get_weather",
    -  description: "Get the current weather in a given location",
    -  inputSchema: z.object({
    -    location: z.string().describe("The city and state, e.g. San Francisco, CA"),
    -    unit: z.enum(["celsius", "fahrenheit"]).default("fahrenheit"),
    -  }),
    -  run: async (input) => JSON.stringify({ temperature: "20°C", condition: "Sunny" }),
    -});
    -
    -const finalMessage = await client.beta.messages.toolRunner({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  tools: [getWeatherTool],
    -  messages: [{ role: "user", content: "What's the weather like in Paris?" }],
    -});
    -
    -
    -
    - -
    -

    6.9. Tutorial: construir um agente que usa ferramentas

    - -

    O tutorial constrói um agente de gerenciamento de calendário em cinco "anéis" concêntricos, cada um um programa completo e executável que adiciona exatamente um conceito sobre o anterior. A ferramenta de exemplo é create_calendar_event, cujo schema usa objetos aninhados, arrays e campos opcionais (input realista):

    -
      -
    1. Anel 1 — Uma ferramenta, um turno: o menor programa possível. Envia o array tools com a mensagem do usuário; a resposta volta com stop_reason: "tool_use" e um bloco tool_use; você executa e devolve o tool_result com tool_use_id casando o id.
    2. -
    3. Anel 2 — O loop agêntico: faz o while baseado em stop_reason à mão.
    4. -
    5. Anel 3 — Uso paralelo de ferramentas.
    6. -
    7. Anel 4 — Tratamento de erros com is_error.
    8. -
    9. Anel 5 — Tool Runner: substitui o loop manual pela abstração do SDK.
    10. -
    -
    Dica: cada anel roda standalone — copie qualquer um para um arquivo novo e ele executa sem o código dos anteriores.
    -
    - -
    -

    6.10. Solução de problemas (troubleshooting)

    - -
    - - - - - - - - - - -
    SintomaCausa provávelCorreção
    Claude chama a ferramenta erradaAmbiguidade nas descriçõesAfie as descrições — diferencie por quando usar, não só o que fazem.
    Claude nunca chama sua ferramentaColisão de nomes ou schema genéricoCheque nomes duplicados; adicione input_examples.
    Tipos de parâmetro errados / parâmetro inexistenteModelo adivinhando sem modo estritoAdicione strict: true (se o schema estiver no subconjunto) ou input_examples.
    Chamadas paralelas não funcionamFormatação do históricoEnvie vários tool_result em UMA mensagem de usuário.
    Cache sempre invalidatool_choice variandoMantenha tool_choice estável ou ponha o breakpoint antes do ponto de variação.
    tool_use ids ... without tool_result blocks immediately afterFalta tool_result ou ele não é o primeiro blocoUm tool_result por tool_use, antes de qualquer texto.
    Comparação de string em inputs falha (modelos atuais)Escaping de Unicode/barra muda entre versõesFaça json.loads()/JSON.parse() — nunca compare strings serializadas cruas.
    -
    - - - - -
    -

    7. Agent Skills

    - -

    Agent Skills são capacidades modulares que estendem o Claude. Cada Skill empacota instruções, metadados e recursos opcionais (scripts, templates) que o Claude usa automaticamente quando relevantes. Diferentemente de prompts (instruções de conversa para tarefas pontuais), Skills carregam sob demanda e eliminam a necessidade de repetir a mesma orientação em várias conversas. Benefícios: especializar o Claude, reduzir repetição (criar uma vez, usar automaticamente) e compor capacidades. Não elegível para ZDR.

    - -

    Divulgação progressiva: três níveis de carregamento

    -

    Skills são diretórios no sistema de arquivos da VM do Claude. A arquitetura habilita divulgação progressiva — o Claude carrega informação em estágios, conforme necessário:

    -
    - - - - - - -
    NívelQuando carregaCusto de tokensConteúdo
    Nível 1: MetadadosSempre (no startup)~100 tokens por Skillname e description do frontmatter YAML
    Nível 2: InstruçõesQuando a Skill é acionadaMenos de 5k tokensCorpo do SKILL.md com instruções e orientação
    Nível 3+: RecursosConforme necessárioEfetivamente ilimitadoArquivos empacotados executados via bash sem carregar conteúdo no contexto
    -

    Skills rodam em um ambiente de code execution com acesso ao sistema de arquivos. Quando uma Skill é acionada, o Claude lê o SKILL.md via bash; se ele referencia outros arquivos (FORMS.md, schema), o Claude os lê também; quando há scripts executáveis, o Claude os roda via bash e recebe só a saída (o código do script nunca entra no contexto). Isso permite acesso a arquivos sob demanda, execução eficiente de scripts e nenhum limite prático de conteúdo empacotado não usado.

    - -

    Estrutura de uma Skill (SKILL.md)

    -

    Toda Skill exige um arquivo SKILL.md com frontmatter YAML. Campos obrigatórios: name e description.

    -
    ---
    -name: pdf-processing
    -description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
    ----
    -
    -# PDF Processing
    -
    -## Instructions
    -[Orientação clara, passo a passo, para o Claude seguir]
    -
    -## Examples
    -[Exemplos concretos de uso]
    -

    Requisitos: name ≤ 64 caracteres, só minúsculas/números/hífens, sem tags XML, sem as palavras reservadas "anthropic"/"claude"; description não vazia, ≤ 1024 caracteres, sem tags XML, devendo incluir o que a Skill faz e quando usá-la.

    -

    Skills pré-construídas (mesmo mecanismo das custom): PowerPoint (pptx), Excel (xlsx), Word (docx) e PDF (pdf).

    - -
    Cuidado — segurança: use Skills apenas de fontes confiáveis (criadas por você ou obtidas da Anthropic). Uma Skill maliciosa pode direcionar o Claude a invocar ferramentas ou executar código de formas que não correspondem ao propósito declarado. Audite todo o conteúdo (SKILL.md, scripts, recursos), desconfie de Skills que buscam dados de URLs externas, e trate a instalação com o mesmo rigor de instalar software em produção.
    -
    - -
    -

    7.1. Quickstart de Agent Skills

    - -

    O quickstart mostra como começar a usar as Skills pré-construídas (PowerPoint, Excel, Word, PDF) na API. As Skills integram-se à Messages API através da ferramenta code execution, especificando-se a Skill no parâmetro container (ver guia da API a seguir).

    -
    - -
    -

    7.2. Usando Skills com a Claude API

    - -

    Skills integram-se à Messages API via code execution, com a mesma estrutura container tanto para Skills da Anthropic quanto custom. Pré-requisitos: API key, a ferramenta code execution habilitada, e três headers beta: code-execution-2025-08-25 (Skills rodam no contêiner de code execution), skills-2025-10-02 (habilita Skills) e files-api-2025-04-14 (para upload/download de arquivos do contêiner).

    -
    - - - - - - - - -
    AspectoSkills da AnthropicSkills custom
    typeanthropiccustom
    skill_idNomes curtos: pptx, xlsx, docx, pdfGerado: skill_01AbCd...
    Formato de versionPor data: 20251013 ou latestTimestamp epoch ou latest
    GestãoPré-construídas e mantidas pela AnthropicUpload/gestão via Skills API (/v1/skills)
    DisponibilidadeTodos os usuáriosPrivada ao seu workspace
    -

    As Skills vão no parâmetro container (até 8 Skills por requisição); especifique type e skill_id, opcionalmente version.

    -
    -
    - -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -H "anthropic-beta: code-execution-2025-08-25,skills-2025-10-02" \
    -  -H "content-type: application/json" \
    -  -d '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 4096,
    -    "container": {
    -      "skills": [
    -        {"type": "anthropic", "skill_id": "pptx", "version": "latest"}
    -      ]
    -    },
    -    "messages": [{"role": "user", "content": "Create a presentation about renewable energy"}],
    -    "tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
    -  }'
    -
    -
    -
    Nota — onde funcionam: Custom Skills não sincronizam entre superfícies (claude.ai, API, Claude Code são separadas). Escopo de compartilhamento: claude.ai (só o usuário individual), Claude API (todo o workspace), Claude Code (pessoal ~/.claude/skills/ ou de projeto .claude/skills/). Na Claude API, o runtime das Skills não tem acesso à internet, não permite instalação de pacotes em runtime — só os pré-instalados do code execution.
    -
    - -
    -

    7.3. Boas práticas de autoria de Skills

    - -
      -
    • Concisão é a chave. O contexto é um bem público. Assuma que o Claude já é muito inteligente — só adicione contexto que ele não tem. Questione cada parágrafo: "o Claude realmente precisa disso?".
    • -
    • Ajuste os graus de liberdade à fragilidade da tarefa. Alta liberdade (instruções em texto) quando várias abordagens são válidas; média (pseudocódigo/scripts com parâmetros) quando há um padrão preferido; baixa (scripts específicos, poucos parâmetros) quando operações são frágeis e a consistência é crítica ("Run exactly this script... Do not modify").
    • -
    -
    - -
    -

    7.4. Skills para empresas (governança)

    - -

    Guia para admins e arquitetos que governam Skills em escala organizacional. Cobre revisão de segurança e vetting (avaliação de tier de risco contra indicadores: execução de código, manipulação de instruções, referências a MCP, padrões de rede, credenciais hardcoded, escopo de acesso a arquivos), uma checklist de revisão (ler todo o conteúdo, verificar comportamento dos scripts em sandbox, checar instruções adversariais e exfiltração, confirmar ausência de credenciais), e avaliação antes do deploy em cinco dimensões: precisão de acionamento, comportamento em isolamento, coexistência (a nova Skill degrada as outras?), seguimento de instruções e qualidade de saída.

    -

    Exija suites de avaliação com 3–5 queries representativas por Skill (casos que devem e não devem acionar + bordas ambíguas), testando nos modelos usados (Haiku, Sonnet, Opus), pois a eficácia varia por modelo. Ciclo de vida: Planejar → Criar e revisar → Testar → Implantar → Monitorar → Iterar ou descontinuar, com separação de funções (autores não revisam a si mesmos).

    -
    - - - - -
    -

    8. MCP — Model Context Protocol

    - -

    O MCP connector permite conectar a servidores MCP remotos diretamente da Messages API, sem implementar um cliente MCP separado. Beta — header mcp-client-2025-11-20 (a versão anterior mcp-client-2025-04-04 está depreciada). Não elegível para ZDR. Recursos: integração direta, chamada de ferramentas via Messages API, configuração flexível (habilitar todas, allowlist ou denylist), autenticação OAuth e múltiplos servidores numa requisição.

    -
    Atenção — limitações: da especificação MCP, apenas chamadas de ferramenta são suportadas hoje. O servidor deve ser exposto publicamente via HTTP (Streamable HTTP ou SSE); servidores STDIO locais não podem ser conectados diretamente (use MCP tunnels). Disponível na Claude API, Claude Platform on AWS e Microsoft Foundry (não em Bedrock/Vertex AI).
    - -

    Os dois componentes

    -

    O MCP connector usa: (1) MCP Server Definition — o array mcp_servers, que define conexão (URL, autenticação); (2) MCP Toolset — entrada mcp_toolset no array tools, que configura quais ferramentas habilitar.

    -

    Campos de mcp_servers: type (apenas "url"), url (deve começar com https://), name (identificador único, referenciado por exatamente um toolset) e authorization_token (opcional, token OAuth se o servidor exigir).

    -
    -
    - - -
    -
    -
    import anthropic
    -
    -client = anthropic.Anthropic()
    -response = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1000,
    -    messages=[{"role": "user", "content": "What tools do you have available?"}],
    -    mcp_servers=[
    -        {"type": "url", "url": "https://example-server.modelcontextprotocol.io/sse",
    -         "name": "example-mcp", "authorization_token": "YOUR_TOKEN"}
    -    ],
    -    tools=[{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}],
    -    betas=["mcp-client-2025-11-20"],
    -)
    -print(response)
    -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  -H "Content-Type: application/json" \
    -  -H "X-API-Key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -H "anthropic-beta: mcp-client-2025-11-20" \
    -  -d '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1000,
    -    "messages": [{"role": "user", "content": "What tools do you have available?"}],
    -    "mcp_servers": [
    -      {"type": "url", "url": "https://example-server.modelcontextprotocol.io/sse",
    -       "name": "example-mcp", "authorization_token": "YOUR_TOKEN"}
    -    ],
    -    "tools": [{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}]
    -  }'
    -
    -
    - -

    Configuração do MCP toolset

    -

    O mcp_toolset tem mcp_server_name (deve casar com um name em mcp_servers), default_config (configuração padrão aplicada a todas as ferramentas do conjunto), configs (overrides por ferramenta) e cache_control. Cada config aceita enabled (padrão true) e defer_loading (padrão false). Precedência (maior → menor): config específica em configs, default_config, padrões do sistema.

    -

    Padrões comuns:

    -
    - - - - - - -
    PadrãoComo
    Habilitar todasSó {"type": "mcp_toolset", "mcp_server_name": "..."}
    Allowlist (só específicas)default_config: {enabled: false} + configs habilitando ferramentas específicas
    Denylist (desabilitar específicas)Default habilitado + configs com enabled: false nas indesejadas
    -
    {
    -  "type": "mcp_toolset",
    -  "mcp_server_name": "google-calendar-mcp",
    -  "default_config": { "enabled": false },
    -  "configs": {
    -    "search_events": { "enabled": true },
    -    "create_event":  { "enabled": true }
    -  }
    -}
    -
    - -
    -

    8.1. Servidores MCP remotos

    - -

    Várias empresas implantaram servidores MCP remotos que desenvolvedores podem conectar via o MCP connector. Para conectar: revise a documentação do servidor, garanta credenciais de autenticação e siga as instruções específicas de cada empresa.

    -
    Atenção: esses servidores são serviços de terceiros, não são da Anthropic. Conecte-se apenas a servidores que você confia e revise as práticas de segurança e termos de cada um. Há centenas de servidores MCP no GitHub.
    -
    - -
    -

    8.2. MCP tunnels

    - -

    MCP tunnels conectam o Claude a servidores MCP que rodam dentro da sua rede privada. O tráfego flui por uma conexão somente de saída (outbound-only), então você não abre portas de entrada no firewall, não expõe serviços à internet pública nem precisa fazer allowlist dos IPs da Anthropic. Beta (research preview, exige solicitar acesso); depende de um provedor de rede terceiro (Cloudflare).

    - -

    Como funciona

    -

    Uma implantação tem dois componentes na sua rede: cloudflared (o agente de túnel, que inicia conexões outbound-only para a borda do túnel operada pela Anthropic) e Proxy (componente de roteamento da Anthropic que termina o TLS interno, valida que os IPs upstream estão num intervalo permitido e roteia por hostname). Cada servidor MCP exposto ganha um hostname sob seu domínio de túnel (ex.: docs.<seu-dominio-de-tunel>), que você anexa a uma sessão de Managed Agent no Console ou passa à Messages API via MCP connector.

    - -

    Modelo de segurança (três camadas)

    -
    - - - - - - -
    CamadaProtege contra
    mTLS externo (Anthropic ↔ provedor de transporte) com validação de IPClientes não autorizados alcançarem o túnel
    TLS interno (backend da Anthropic → seu proxy)Inspeção de payload pelo provedor de transporte ou intermediários
    OAuth em cada servidor MCPUso não autorizado de ferramentas MCP por tráfego autenticado do túnel
    -

    Como o proxy termina o TLS interno com um certificado que só você possui, a Cloudflare não consegue ler payloads (recebe apenas metadados: IP de egresso, fingerprint do host cloudflared, timing/volume, e o subdomínio *.tunnel.anthropic.com).

    -
    Cuidado: se um atacante obtiver seu tunnel token e uma de suas chaves privadas TLS, poderá personificar seu proxy e ler payloads de requisições MCP. Trate ambos como segredos de alto valor.
    - -

    Usando os servidores tunelados

    -

    Uma vez ativo o túnel (com certificado CA ativo e stack conectado), os servidores MCP roteados ficam acessíveis a partir de Claude Managed Agents e da Messages API. O túnel carrega o tráfego criptografado mas não autentica ao servidor — se o upstream exige OAuth/bearer próprio, forneça-o como faria com qualquer servidor MCP. Pela Messages API, passe a URL roteada no array mcp_servers: o host é <subdominio>.<seu-dominio-de-tunel> e o path é o que seu servidor upstream serve (FastMCP streamable-http usa /mcp). O corpo e o header anthropic-beta: mcp-client-2025-11-20 seguem o formato padrão do MCP connector — só a url é específica do túnel.

    -
    Nota: túneis MCP criados pelo Console não aparecem como conectores no claude.ai.
    - -

    Quickstart, deploy e operação

    -

    Documentação operacional do MCP tunnels:

    -
      -
    • Quickstart (doc): caminho mais curto, com Docker Compose e credenciais manuais. Um stack de três contêineres (servidor MCP de amostra, proxy do túnel, conector outbound); o servidor fica acessível em https://echo.<seu-dominio>/mcp sem nada escutando em porta pública. Precisa de Docker/Compose, papel no Console que gerencie túneis, e OpenSSL 1.1.1+.
    • -
    • Deploy com Docker Compose (doc): stack como contêineres endurecidos em um único host, replicável em vários hosts. Requer túnel criado no Console (ID tnl_...).
    • -
    • Deploy com Helm (doc): chart oficial da Anthropic que instala o stack como um único Deployment em um cluster Kubernetes.
    • -
    • Gerenciar no Console (doc): criar túnel, registrar certificado CA, recuperar o tunnel token e anexar servidores a agentes. Autenticação à Tunnels API por Workload Identity Federation (recomendado, escopo org:manage_tunnels) ou credenciais manuais.
    • -
    • Referência (doc): config do proxy (/etc/mcp-gateway/config.yaml) com listen_addr, tunnel_domain, tls.cert_file/key_file, routes (mapa subdomínio → upstream scheme://host:port), upstream.allowed_ips (defesa primária contra SSRF, padrão RFC1918); mais a Tunnels REST API e o CLI de setup.
    • -
    • Segurança (doc): exigir OAuth em cada servidor, habilitar SSO, restringir upstream.allowed_ips ao menor CIDR, monitorar logs, rotacionar credenciais, fixar imagens por digest SHA-256, limitar alcance de rede.
    • -
    • Troubleshooting (doc): diagnóstico de conectividade, TLS e roteamento.
    • -
    -

    Requisitos de rede (saída): api.anthropic.com (443 TCP, provisionamento/rotação de token); cloudflared para a borda do túnel (198.41.192.0/19, 2606:4700:a0::/44, porta 7844 TCP e UDP, contínuo); proxy para seus servidores MCP upstream.

    -
    - - - - - - - - -
    -

    Parte D — Referência REST/SDK, Agentes Gerenciados, Governança & Nuvem

    -

    Esta parte é a referência canônica de baixo nível: os SDKs oficiais (com foco em Python e JavaScript/TypeScript; demais linguagens citadas como referência), o contrato REST language-neutral da API de Mensagens, Token Counting, Message Batches, Models e Files, os códigos de erro e rate limits, as plataformas de nuvem (Amazon Bedrock, Vertex AI, Microsoft Foundry, Claude Platform on AWS), os Claude Managed Agents (harness gerenciado) e o plano de governança/Admin (Admin API, workspaces, Workload Identity Federation, Usage & Cost, retenção e residência de dados, Compliance API).

    -
    - - - - -
    -

    1. SDKs oficiais

    -

    A Anthropic mantém SDKs idiomáticos para oito superfícies, todos com tipagem, streaming, retries e tratamento de erros embutidos. Todos enviam automaticamente o header anthropic-version: 2023-06-01 e leem a chave da variável de ambiente ANTHROPIC_API_KEY. Os mesmos clientes suportam as plataformas de nuvem (Bedrock, Vertex AI, Foundry, Claude Platform on AWS) através de classes/pacotes específicos — veja a seção 9.

    - -
    SDKs em profundidade: esta seção dá a visão geral e o contrato REST. Para uso completo dos SDKs, veja a Parte E — SDK Python (anthropic) e a Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk): clientes sync/async, todas as opções, streaming, helpers de ferramentas e MCP, batches, paginação, hierarquia de erros, retries/timeouts, respostas cruas, logging, namespace beta e clientes/pacotes de plataforma.
    - -

    1.1. Pacotes, instalação e versão mínima

    -
    Foco deste guia: os SDKs cobertos em profundidade são Python - (Parte E) e JavaScript/TypeScript (Parte F). - A Anthropic também mantém SDKs oficiais para Java, Go, C#/.NET, Ruby e PHP, além de uma CLI — citados aqui apenas como - referência; consulte a doc oficial para detalhes deles.
    -
    - - - - - - - - - - -
    LinguagemPacoteInstalaçãoRuntime / referência
    Python focoanthropicpip install anthropicPython 3.9+ · ver Parte E
    JavaScript/TypeScript foco@anthropic-ai/sdknpm install @anthropic-ai/sdkTS 4.9+ (Node 20+, Deno, Bun, Workers) · ver Parte F
    Java referênciacom.anthropic:anthropic-javaimplementation("com.anthropic:anthropic-java")Java 8+
    Go referênciaanthropic-sdk-gogo get github.com/anthropics/anthropic-sdk-goGo 1.23+
    C# / .NET referênciaAnthropicdotnet add package Anthropic.NET Standard 2.0+
    Ruby referênciaanthropicbundle add anthropicRuby 3.2.0+
    PHP referênciaanthropic-ai/sdkcomposer require anthropic-ai/sdkPHP 8.1.0+
    -
    Nota: versões de pacote são fatos perecíveis. Verifique a versão instalada com anthropic.__version__ (Python) ou pelo gerenciador de pacotes (npm ls @anthropic-ai/sdk). Repositórios oficiais: anthropics/anthropic-sdk-python e anthropics/anthropic-sdk-typescript (foco), além de -java, -go, -ruby, -csharp, -php.
    - -

    1.2. Inicialização do client (síncrono e assíncrono)

    -

    O exemplo "Olá, Claude" em três superfícies. Em Python existem dois clients: Anthropic() (síncrono) e AsyncAnthropic() (assíncrono, mesma interface com await).

    -
    -
    - - - -
    -
    -
    import os
    -from anthropic import Anthropic, AsyncAnthropic
    -
    -# Síncrono — api_key é opcional (lê ANTHROPIC_API_KEY do ambiente)
    -client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
    -
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -print(message.content[0].text)
    -
    -# Assíncrono — mesma API, com await
    -import asyncio
    -aclient = AsyncAnthropic()
    -
    -async def main():
    -    msg = await aclient.messages.create(
    -        model="claude-opus-4-8",
    -        max_tokens=1024,
    -        messages=[{"role": "user", "content": "Olá, Claude"}],
    -    )
    -    print(msg.content[0].text)
    -
    -asyncio.run(main())
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic(); // lê ANTHROPIC_API_KEY do ambiente
    -
    -const message = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: "Olá, Claude" }],
    -});
    -console.log(message.content);
    -
    -
    -
    # CLI oficial (ant)
    -ant messages create \
    -  --model claude-opus-4-8 \
    -  --max-tokens 1024 \
    -  --message '{role: user, content: "Olá, Claude"}' \
    -  --transform content
    -
    -
    - -

    1.3. Recursos do SDK: streaming, retries, timeouts, paginação

    -

    Os SDKs encapsulam quatro comportamentos operacionais. Os valores abaixo são os defaults do SDK Python; outros SDKs seguem convenções equivalentes.

    -
    - - - - - - - -
    RecursoComportamento padrãoComo configurar
    StreamingSSE evento a evento via stream=True; ou helper de contexto client.messages.stream(...) com text_stream e get_final_message()stream=True (iterável de eventos, menos memória) ou with client.messages.stream(...) as s:
    Retries2 tentativas automáticas com backoff exponencial em erros de conexão, 408, 409, 429 e ≥500Anthropic(max_retries=0) ou client.with_options(max_retries=5)
    Timeouts10 minutos por padrão; lança APITimeoutErrorAnthropic(timeout=20.0) ou httpx.Timeout(...) granular
    Auto-paginaçãoItera entre páginas automaticamente em métodos list()for batch in client.messages.batches.list(limit=20): · ou .has_next_page()/.get_next_page()
    -
    -
    - - -
    -
    -
    from anthropic import Anthropic
    -
    -client = Anthropic(max_retries=2, timeout=600.0)
    -
    -# Streaming com helper de contexto: acumula texto e mensagem final
    -with client.messages.stream(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Escreva um haicai"}],
    -) as stream:
    -    for text in stream.text_stream:
    -        print(text, end="", flush=True)
    -    final = stream.get_final_message()
    -    print("\n", final.usage)
    -
    -# Auto-paginação: percorre todas as páginas de batches
    -for batch in client.messages.batches.list(limit=20):
    -    print(batch.id)
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic({ maxRetries: 2, timeout: 600_000 });
    -
    -// Streaming: helper com finalMessage()
    -const stream = client.messages.stream({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: "Escreva um haicai" }],
    -});
    -for await (const event of stream) {
    -  if (event.type === "content_block_delta") process.stdout.write(JSON.stringify(event.delta));
    -}
    -const finalMessage = await stream.finalMessage();
    -console.log(finalMessage.usage);
    -
    -
    -
    Dica: em Python, pip install "anthropic[aiohttp]" habilita o backend DefaultAioHttpClient para melhor concorrência assíncrona. client.with_raw_response.create(...) expõe headers da resposta (por exemplo request-id); message._request_id é a propriedade pública para correlacionar requisições com o suporte.
    -
    Atenção (requisições longas): evite max_tokens alto sem streaming. O SDK lança ValueError se uma requisição não-streaming for estimada em > ~10 minutos. Use stream=True (ou o helper .stream() com get_final_message()) para gerações longas. O SDK define TCP keep-alive para mitigar quedas de conexões ociosas.
    -
    - - - - -
    -

    2. Referência REST — endpoints & autenticação

    -

    A API REST da Anthropic é language-neutral: os SDKs são wrappers finos sobre os endpoints HTTP descritos aqui. Base URL (API de primeira parte): https://api.anthropic.com. As plataformas de nuvem usam base URLs próprias (veja a seção 9).

    - - -

    2.1. Headers obrigatórios e versionamento

    -
    - - - - - - - -
    HeaderValorObrigatório
    x-api-keyChave da API sk-ant-api... (ou bearer token em plataformas de nuvem)Sim (ou Authorization: Bearer com WIF/OAuth)
    anthropic-version2023-06-01Sim
    content-typeapplication/jsonSim (para corpos JSON)
    anthropic-betaLista de features beta, ex. files-api-2025-04-14Apenas quando a feature exigir
    -

    A política de versionamento garante, para uma dada versão da Messages API, a preservação dos parâmetros de entrada e saída existentes. A Anthropic pode: adicionar inputs opcionais, adicionar valores à saída, alterar condições de erro e adicionar novas variantes a enums de saída (por exemplo, novos tipos de eventos de streaming). Trate enums de saída como abertos.

    - - -

    2.2. Mapa de endpoints REST

    -
    - - - - - - - - - - - - - - - - - - -
    RecursoMétodo & caminhoDescrição
    MessagesPOST /v1/messagesGera a próxima mensagem da conversa
    Token CountingPOST /v1/messages/count_tokensConta tokens sem gerar
    Batches — criarPOST /v1/messages/batchesCria lote de requisições
    Batches — listarGET /v1/messages/batchesLista lotes (paginado)
    Batches — recuperarGET /v1/messages/batches/{id}Estado do lote
    Batches — resultadosGET /v1/messages/batches/{id}/resultsStream JSONL de resultados
    Batches — cancelarPOST /v1/messages/batches/{id}/cancelInicia cancelamento
    Batches — deletarDELETE /v1/messages/batches/{id}Remove lote (precisa estar ended)
    Models — listarGET /v1/modelsModelos disponíveis
    Models — recuperarGET /v1/models/{model_id}Metadados de um modelo
    Files (beta)POST/GET/DELETE /v1/filesUpload/listagem/exclusão de arquivos
    OAuth (WIF)POST /v1/oauth/tokenTroca de JWT por token de acesso
    Admin / Organização/v1/organizations/*Admin API (requer chave sk-ant-admin...)
    Compliance/v1/compliance/*Atividade, chats, arquivos (Claude Enterprise)
    Managed Agents (beta)/v1/agents, /v1/sessions, /v1/environments …Harness de agentes gerenciados
    -
    - - - - -
    -

    3. POST /v1/messages — corpo da requisição & resposta

    -

    Envia uma lista estruturada de mensagens de entrada (texto e/ou imagem) e o modelo gera a próxima mensagem. Pode ser usado para consultas únicas ou conversas multi-turno stateless.

    - - -

    3.1. Parâmetros do corpo (request body)

    -
    - - - - - - - - - - - - - - - - - - - - - - -
    ParâmetroTipoObrig.Descrição
    modelstring (Model)SimID do modelo, ex. claude-opus-4-8
    messagesarray de MessageParamSimTurnos alternados user/assistant. content é string ou array de blocos. Limite de 100.000 mensagens por requisição
    max_tokensnumberSimMáximo de tokens a gerar. 0 pré-aquece o cache sem gerar. Máximo varia por modelo
    systemstring ou array de TextBlockParamNãoPrompt de sistema. Não existe role "system" em messages
    metadataobjectNão{ user_id } — identificador opaco para detecção de abuso
    stop_sequencesarray de stringNãoStrings que param a geração; produzem stop_reason: "stop_sequence"
    streambooleanNãoStreaming via SSE
    temperaturenumberNão0.0–1.0, default 1.0
    top_pnumberNãoNucleus sampling (uso avançado)
    top_knumberNãoAmostragem entre os top-K tokens (uso avançado)
    toolsarray de ToolUnionNãoDefinições de ferramentas (function calling / server tools)
    tool_choiceToolChoiceNãoauto · any · tool (específica) · none
    thinkingThinkingConfigParamNãoadaptive (recomendado para Opus 4.8) · enabled (com budget_tokens) · disabled
    service_tier"auto" ou "standard_only"NãoSeleção de tier de capacidade
    containerstringNãoReuso de container entre requisições (code execution)
    context_managementobjectNãoCompactação / edição de contexto server-side (beta)
    output_format / output_configobjectNãoSaída estruturada (JSON schema) e nível de effort
    mcp_serversarrayNãoServidores MCP remotos (MCP connector, beta)
    inference_geostringNão"global" (default) ou "us" — residência de inferência (veja a seção 11.6)
    -
    Atenção (sampling depreciado): temperature, top_p e top_k retornam 400 quando definidos com valor não-default em Claude Opus 4.7, Opus 4.8, Sonnet 5, Fable 5 e Mythos 5 (seguem válidos em Opus 4.6, Sonnet 4.6 e modelos anteriores). Isso vale em toda requisição, independentemente de thinking estar ativo. Os campos continuam nos tipos do SDK para compatibilidade de type-check, mas a API rejeita valores não-default — omita-os e guie a variedade estilística por prompting (recomendação oficial). Ao migrar de Sonnet 4.6 → Sonnet 5, audite chamadas com temperature/top_p explícitos antes de trocar o ID. Fonte: model-deprecations.
    -
    Atenção (prefill): Claude Opus 4.8 e Sonnet 4.6 não suportam pré-preencher (prefill) a última mensagem assistant. Enviar um turno assistant final retorna 400 invalid_request_error. Use saída estruturada (output_config.format), instruções no system prompt ou structured outputs.
    - -

    3.2. Objeto de resposta (Message)

    -
    - - - - - - - - - - - - - -
    CampoTipoDescrição
    idstringIdentificador único da mensagem (ex. msg_013Zva...)
    type"message"Sempre "message"
    role"assistant"Sempre "assistant"
    contentarray de ContentBlockBlocos gerados: text, thinking, redacted_thinking, tool_use, server_tool_use, web_search_tool_result, web_fetch_tool_result, code_execution_tool_result, container_upload, entre outros
    modelstringModelo que atendeu a requisição
    stop_reasonenumMotivo do término (tabela abaixo)
    stop_sequencestring ou nullA stop_sequence que disparou o término, se houver
    usageUsageContagem de tokens / billing (seção 3.3)
    stop_detailsobjectDetalhes de recusa: category ("cyber"/"bio"; no Fable 5 também "reasoning_extraction" — bloqueio por engenharia reversa/duplicação de outputs sob os ToS, desde 09/06/2026), explanation, type: "refusal"
    containerobject{ id, expires_at } quando a ferramenta de code execution é usada
    -

    Valores de stop_reason:

    -
    - - - - - - - - - -
    ValorSignificado
    "end_turn"Ponto de parada natural
    "max_tokens"Atingiu max_tokens ou o máximo do modelo
    "stop_sequence"Gerou uma das stop_sequences
    "tool_use"O modelo invocou uma ou mais ferramentas
    "pause_turn"Turno longo pausado; reenvie a resposta para continuar
    "refusal"Classificador de streaming interveio por política
    -
    Nota: em modo não-streaming, stop_reason é sempre não-nulo. Em streaming, é null no evento message_start e não-nulo nos demais.
    - -

    3.3. Objeto Usage

    -
    - - - - - - - - - - - -
    CampoTipoDescrição
    input_tokensnumberTokens de entrada (excluindo tokens de cache)
    output_tokensnumberTokens de saída gerados
    cache_creation_input_tokensnumberTokens usados para criar entrada de cache
    cache_read_input_tokensnumberTokens lidos do cache
    cache_creationobjectDetalhe: ephemeral_5m_input_tokens e ephemeral_1h_input_tokens
    server_tool_useobjectContagem de chamadas server-side: web_search_requests, web_fetch_requests
    service_tierenum"standard" · "priority" · "batch"
    inference_geostringGeografia onde a inferência rodou
    -
    Dica: total de tokens de entrada = input_tokens + cache_creation_input_tokens + cache_read_input_tokens.
    - -

    3.4. Exemplo completo

    -
    -
    - - -
    -
    -
    curl https://api.anthropic.com/v1/messages \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{"role": "user", "content": "Olá, Claude"}]
    -  }'
    -
    -
    -
    import anthropic
    -client = anthropic.Anthropic()
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -print(message.content[0].text)
    -print(message.usage)  # Usage(input_tokens=..., output_tokens=...)
    -
    -
    -
    Resposta JSON (200) -
    {
    -  "id": "msg_013Zva2CMHLNnXjNJJKqJ2EF",
    -  "type": "message",
    -  "role": "assistant",
    -  "content": [{"type": "text", "text": "Olá! Sou o Claude."}],
    -  "model": "claude-opus-4-8",
    -  "stop_reason": "end_turn",
    -  "stop_sequence": null,
    -  "usage": {
    -    "input_tokens": 2095,
    -    "output_tokens": 503,
    -    "cache_creation_input_tokens": 0,
    -    "cache_read_input_tokens": 0,
    -    "service_tier": "standard"
    -  }
    -}
    -
    -
    - - - - -
    -

    4. POST /v1/messages/count_tokens

    -

    Conta o número de tokens de uma Message — incluindo tools, imagens e documentos — sem criar a mensagem. Útil para validar custos e limites antes de enviar. Aceita os mesmos parâmetros relevantes da Messages API: model, messages, system, tools, tool_choice, thinking, mcp_servers (mas não max_tokens).

    - -

    A resposta é um objeto simples com input_tokens (number). O limite de tamanho de requisição é o mesmo da Token Counting API (32 MB).

    -
    -
    - - -
    -
    -
    curl https://api.anthropic.com/v1/messages/count_tokens \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "model": "claude-opus-4-8",
    -    "messages": [{"role": "user", "content": "Olá, mundo"}]
    -  }'
    -# -> {"input_tokens": 10}
    -
    -
    -
    count = client.messages.count_tokens(
    -    model="claude-opus-4-8",
    -    messages=[{"role": "user", "content": "Olá, mundo"}],
    -)
    -print(count.input_tokens)  # 10
    -
    -
    -
    - - - - -
    -

    5. Message Batches API

    -

    Processa múltiplas requisições da Messages API de uma vez, de forma assíncrona, com desconto de 50% sobre o preço padrão. Um lote começa a processar imediatamente e pode levar até 24 horas. Resultados ficam disponíveis por 29 dias. Para o lado conceitual do processamento em lote (quando usar, trade-offs, custo), veja a Parte A — Batch Processing; aqui detalhamos os endpoints REST e o ciclo de vida do objeto MessageBatch.

    - - -

    5.1. Criar um lote

    -

    O corpo é um array requests; cada item tem um custom_id (único por lote, usado para casar resultados) e params (os mesmos parâmetros da Messages API).

    -
    -
    - - -
    -
    -
    curl https://api.anthropic.com/v1/messages/batches \
    -  --header "x-api-key: $ANTHROPIC_API_KEY" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "content-type: application/json" \
    -  --data '{
    -    "requests": [
    -      {
    -        "custom_id": "req-1",
    -        "params": {
    -          "model": "claude-opus-4-8",
    -          "max_tokens": 1024,
    -          "messages": [{"role": "user", "content": "Olá, mundo"}]
    -        }
    -      }
    -    ]
    -  }'
    -
    -
    -
    batch = client.messages.batches.create(
    -    requests=[
    -        {
    -            "custom_id": "req-1",
    -            "params": {
    -                "model": "claude-opus-4-8",
    -                "max_tokens": 1024,
    -                "messages": [{"role": "user", "content": "Olá, mundo"}],
    -            },
    -        },
    -    ]
    -)
    -print(batch.id, batch.processing_status)
    -
    -
    - -

    5.2. Objeto MessageBatch e ciclo de vida

    -
    - - - - - - - - - - - - - -
    CampoTipoDescrição
    idstringEx. msgbatch_013Zva...
    type"message_batch"Sempre "message_batch"
    processing_statusenum"in_progress" · "canceling" · "ended"
    request_countsobjectprocessing, succeeded, errored, canceled, expired
    created_atstring (RFC 3339)Criação
    ended_atstringQuando todas as requisições terminaram (só após ended)
    expires_atstringExpiração (24h após criação)
    archived_atstringQuando os resultados ficaram indisponíveis
    cancel_initiated_atstringInício do cancelamento, se houve
    results_urlstringURL do arquivo .jsonl (só após ended)
    -
    Nota: os contadores em request_counts permanecem zerados (exceto processing) até o lote inteiro terminar. Um lote precisa estar ended antes de ser deletado — cancele primeiro se ainda estiver em progresso. A exclusão retorna { "id": "...", "type": "message_batch_deleted" }.
    - -

    5.3. Resultados em JSONL

    -

    O endpoint /results faz stream de um arquivo .jsonl: cada linha é um MessageBatchIndividualResponse com custom_id e result. Os resultados não são garantidos na ordem das requisições — use custom_id para casar. O result.type assume: "succeeded" (com message), "errored" (com error), "canceled" ou "expired".

    -
    Linha JSONL de resultado (succeeded) -
    {
    -  "custom_id": "req-1",
    -  "result": {
    -    "type": "succeeded",
    -    "message": {
    -      "id": "msg_abc123",
    -      "type": "message",
    -      "role": "assistant",
    -      "content": [{"type": "text", "text": "Olá!"}],
    -      "stop_reason": "end_turn",
    -      "usage": {"input_tokens": 11, "output_tokens": 4}
    -    }
    -  }
    -}
    -
    -
    -
    - -
    -
    -
    # Após .processing_status == "ended"
    -result_stream = client.messages.batches.results("msgbatch_abc123")
    -for entry in result_stream:
    -    if entry.result.type == "succeeded":
    -        print(entry.custom_id, entry.result.message.content)
    -    elif entry.result.type == "errored":
    -        print(entry.custom_id, "erro:", entry.result.error)
    -
    -
    -
    - - - - -
    -

    6. Models API

    -

    Determina quais modelos estão disponíveis para a sua conta. Modelos mais recentes aparecem primeiro. Dois endpoints: GET /v1/models (lista paginada) e GET /v1/models/{model_id} (recupera um).

    -
    Nota de fronteira: a tabela geral de modelos, capacidades e preços da API direta vive na Parte A — Modelos, e a referência detalhada da Models API em Parte A — Models API. Esta seção documenta o esquema do endpoint do ponto de vista REST/SDK, sem reproduzir a tabela de modelos. Os IDs específicos de plataforma (Bedrock/Vertex/Foundry, que diferem da API direta) são registrados na seção 9.
    - - -

    6.1. Listar modelos & paginação

    -

    Query params: before_id / after_id (cursores) e limit (default 20, de 1 a 1000). A resposta traz data[], has_more, first_id e last_id.

    -

    Cada ModelInfo traz: id, type: "model", display_name, created_at (RFC 3339), max_input_tokens, max_tokens e um objeto capabilities que reporta suporte a batch, citations, code_execution, context_management, effort (níveis low/medium/high/max/xhigh), image_input, pdf_input, structured_outputs e thinking (tipos adaptive/enabled).

    -
    -
    - - -
    -
    -
    curl https://api.anthropic.com/v1/models \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "x-api-key: $ANTHROPIC_API_KEY"
    -
    -
    -
    for model in client.models.list(limit=20):
    -    print(model.id, model.display_name, model.max_input_tokens)
    -
    -info = client.models.retrieve("claude-opus-4-8")
    -print(info.created_at, info.capabilities)
    -
    -
    -
    Resposta JSON (200) — recortada -
    {
    -  "data": [
    -    {
    -      "id": "claude-opus-4-8",
    -      "type": "model",
    -      "display_name": "Claude Opus 4.8",
    -      "created_at": "2025-11-01T00:00:00Z",
    -      "capabilities": {
    -        "batch": {"supported": true},
    -        "thinking": {"supported": true, "types": {"adaptive": {"supported": true}, "enabled": {"supported": true}}},
    -        "effort": {"supported": true, "low": {"supported": true}, "medium": {"supported": true}, "high": {"supported": true}, "max": {"supported": true}, "xhigh": {"supported": true}}
    -      }
    -    }
    -  ],
    -  "has_more": true,
    -  "first_id": "...",
    -  "last_id": "..."
    -}
    -
    -
    - - - - -
    -

    7. Files API (lado REST)

    -

    A Files API (beta — header anthropic-beta: files-api-2025-04-14) permite enviar arquivos uma vez e referenciá-los por file_id em múltiplas requisições, em vez de reenviar bytes. Os recursos são escopados por workspace. Endpoints sob /v1/files: upload, listar, recuperar metadados, baixar e deletar. O limite de tamanho de requisição da Files API é 500 MB.

    - -
    Nota: a profundidade conceitual da Files API (tipos de documento, citações, vínculo com blocos document) é coberta na Parte B. Aqui registramos o lado REST/SDK. No SDK Python, o upload aceita PathLike, tupla (filename, content, content_type) ou BinaryIO, via client.beta.files.upload(...).
    -
    -
    - -
    -
    -
    from pathlib import Path
    -from anthropic import Anthropic
    -
    -client = Anthropic()
    -
    -# Upload (beta)
    -f = client.beta.files.upload(file=Path("/caminho/relatorio.pdf"))
    -
    -# Referência por file_id na Messages API
    -resp = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "text", "text": "Resuma este documento."},
    -            {"type": "document", "source": {"type": "file", "file_id": f.id}},
    -        ],
    -    }],
    -    betas=["files-api-2025-04-14"],
    -)
    -
    -
    -
    - - - - -
    -

    8. Erros & rate limits

    - - -

    8.1. Códigos HTTP e tipos de erro

    -
    - - - - - - - - - - - - - -
    Statuserror.typeSignificado
    400invalid_request_errorFormato/conteúdo inválido (também outros 4XX não listados)
    401authentication_errorProblema com a chave da API (ou credenciais AWS no Claude Platform on AWS)
    402billing_errorProblema de billing/pagamento
    403permission_errorChave sem permissão para o recurso
    404not_found_errorRecurso não encontrado
    413request_too_largeExcede o tamanho máximo de bytes
    429rate_limit_errorAtingiu um rate limit
    500api_errorErro interno inesperado
    504timeout_errorTimeout durante o processamento (use streaming)
    529overloaded_errorAPI temporariamente sobrecarregada
    -

    Limites de tamanho de requisição: Messages 32 MB · Token Counting 32 MB · Batch 256 MB · Files 500 MB. Exceder retorna 413 (na API direta, devolvido pelo Cloudflare antes de chegar aos servidores).

    - -

    8.2. Formato do erro & request ID

    -

    Erros são sempre JSON com um objeto error de topo (type + message) e um request_id. Toda resposta inclui o header request-id (ex. req_018Ee...) — inclua-o em tickets de suporte. Nos SDKs, leia message._request_id.

    -
    {
    -  "type": "error",
    -  "error": {
    -    "type": "not_found_error",
    -    "message": "The requested resource could not be found."
    -  },
    -  "request_id": "req_011CSHoEeqs5C35K2UUqR7Fy"
    -}
    -
    Nota (Claude Platform on AWS): respostas trazem dois IDs — o AWS (x-amzn-requestid, primário, indexado no CloudTrail) e o Anthropic (request-id, secundário). Use o AWS para CloudTrail e o Anthropic para o suporte da Anthropic.
    - -

    8.3. Rate limit headers & retry/backoff

    -

    A API direta retorna headers de rate limit que permitem reagir antes do 429:

    -
    - - - - - - - -
    HeaderSignificado
    anthropic-ratelimit-requests-limit / -remaining / -resetLimite, restante e reset de requisições por minuto
    anthropic-ratelimit-input-tokens-limit / -remaining / -resetTokens de entrada por minuto
    anthropic-ratelimit-output-tokens-limit / -remaining / -resetTokens de saída por minuto
    retry-afterSegundos a esperar antes de tentar novamente (em 429)
    -
    Atenção: erros 529 podem ocorrer sob alta carga global. Um aumento abrupto de uso pode gerar 429 por limites de aceleração — aumente o tráfego gradualmente. Implemente retry com backoff exponencial (os SDKs já fazem 2 tentativas por padrão em conexão, 408, 409, 429 e ≥500). Em streaming SSE, um erro pode ocorrer após o 200, fora do mecanismo padrão.
    -
    Nota: Microsoft Foundry não inclui os headers de rate limit da Anthropic — gerencie via ferramentas do Azure. Veja a Rate Limits API para ler programaticamente os limites configurados.
    - -
    - - - - -
    -

    9. Plataformas: Bedrock, Vertex AI, Foundry & Claude Platform on AWS

    -

    Os SDKs oficiais suportam quatro plataformas além da API de primeira parte. Todas usam o mesmo formato da Messages API; o que muda é a base URL, a autenticação e os IDs de modelo.

    -
    - - - - - - - -
    PlataformaQuem opera o stackBase URLAuthClient SDK (Python)
    Claude in Amazon BedrockAWSbedrock-mantle.{region}.api.awsIAM/SigV4 (ou bearer token)AnthropicBedrockMantle
    Claude on Vertex AIGoogle Cloud (parceiro){location}-aiplatform.googleapis.comCredenciais GCP (ADC)AnthropicVertex
    Claude in Microsoft FoundryAnthropic (billing via Azure){resource}.services.ai.azure.com/anthropicAPI key ou Entra IDAnthropicFoundry
    Claude Platform on AWSAnthropic (billing via AWS Marketplace)aws-external-anthropic.{region}.api.awsIAM/SigV4 ou API keyAnthropicAWS Beta
    - - -

    9.1. Amazon Bedrock

    -

    Claude in Amazon Bedrock roda em infraestrutura gerenciada pela AWS com zero operator access da Anthropic, servindo a Messages API em /anthropic/v1/messages. IDs de modelo carregam o prefixo anthropic. — ex. anthropic.claude-opus-4-8 e anthropic.claude-haiku-4-5 (ambos abertos a todos os clientes Bedrock).

    -

    Autenticação: três caminhos — service role do Bedrock (recomendado), IAM assumed roles (sessão máx. 12h) e bearer tokens (12h, menos preferido). Instalação: pip install -U "anthropic[bedrock]" (Python) ou npm install @anthropic-ai/bedrock-sdk.

    -
    -
    - - -
    -
    -
    from anthropic import AnthropicBedrockMantle
    -
    -client = AnthropicBedrockMantle(aws_region="us-east-1")
    -
    -message = client.messages.create(
    -    model="anthropic.claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -print(message.content[0].text)
    -
    -
    -
    curl https://bedrock-mantle.us-east-1.api.aws/anthropic/v1/messages \
    -  --aws-sigv4 "aws:amz:us-east-1:bedrock-mantle" \
    -  --user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \
    -  -H "x-amz-security-token: $AWS_SESSION_TOKEN" \
    -  -H "content-type: application/json" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -d '{
    -    "model": "anthropic.claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{"role": "user", "content": "Olá, Claude"}]
    -  }'
    -
    -
    -
    Nota: Bedrock oferece endpoints Global (roteamento dinâmico, sem prêmio) e Regional (data residency, prêmio de 10%). Cota padrão: 2 milhões de input TPM (até 4 milhões sem aprovação adicional da Anthropic). Recursos não suportados no Bedrock incluem: Files API, server-side tools (code execution, web search/fetch, advisor), Agent Skills, MCP connector, Batches, Models, Admin/Compliance e Managed Agents. A integração legada (InvokeModel/Converse) usa o client AnthropicBedrock e tem formato de request/response próprio; este guia foca a integração atual (Messages API) — para o mapeamento de shapes da legada, consulte a página oficial. - claude-in-amazon-bedrock · legada: claude-on-amazon-bedrock-legacy
    - -

    9.2. Google Vertex AI

    -

    A API Vertex é quase idêntica à Messages API, com duas diferenças no formato: (1) model não vai no corpo — é parte da URL do endpoint GCP; (2) anthropic_version vai no corpo (não no header) e deve valer vertex-2023-10-16. IDs de modelo: claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5@20251001 (datado). Instalação: pip install -U google-cloud-aiplatform "anthropic[vertex]".

    -
    -
    - - -
    -
    -
    from anthropic import AnthropicVertex
    -
    -# Antes: gcloud auth application-default login
    -client = AnthropicVertex(project_id="MY_PROJECT_ID", region="global")
    -
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=100,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -print(message)
    -
    -
    -
    MODEL_ID=claude-opus-4-8
    -LOCATION=global
    -PROJECT_ID=MY_PROJECT_ID
    -
    -curl -X POST \
    -  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -  -H "Content-Type: application/json" \
    -  "https://$LOCATION-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/anthropic/models/${MODEL_ID}:streamRawPredict" \
    -  -d '{
    -    "anthropic_version": "vertex-2023-10-16",
    -    "messages": [{"role": "user", "content": "Olá, Claude"}],
    -    "max_tokens": 100
    -  }'
    -
    -
    -
    Nota: Vertex oferece endpoints global, multi-region e regional (estes últimos com prêmio de 10%). Payload limitado a 30 MB. Claude Opus 4.8 e Sonnet 4.6 têm janela de 1M tokens no Vertex. Recursos não suportados são semelhantes aos do Bedrock (sem Files, code execution/web fetch/advisor, Agent Skills, MCP connector, Batches, Models, Admin/Compliance, Managed Agents).
    - -

    9.3. Microsoft Foundry

    -

    Em Foundry, os modelos rodam na infraestrutura da Anthropic; é uma integração comercial para billing/acesso via Azure. Hierarquia: resource (segurança/billing) contém deployments (instâncias do modelo). O nome do deployment é o valor passado em model. Base URL: https://{resource}.services.ai.azure.com/anthropic/v1/*. Auth: API key (header api-key ou x-api-key) ou Entra ID (Authorization: Bearer). Suportado pelos SDKs C#, Java, PHP, Python e TypeScript (Go e Ruby não têm suporte nativo).

    -
    -
    - - -
    -
    -
    import os
    -from anthropic import AnthropicFoundry
    -
    -client = AnthropicFoundry(
    -    api_key=os.environ.get("ANTHROPIC_FOUNDRY_API_KEY"),
    -    resource="example-resource",  # nome do resource
    -)
    -
    -message = client.messages.create(
    -    model="claude-opus-4-8",   # nome do deployment
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá!"}],
    -)
    -print(message.content)
    -
    -
    -
    curl https://{resource}.services.ai.azure.com/anthropic/v1/messages \
    -  -H "content-type: application/json" \
    -  -H "api-key: YOUR_AZURE_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -d '{
    -    "model": "claude-opus-4-8",
    -    "max_tokens": 1024,
    -    "messages": [{"role": "user", "content": "Olá!"}]
    -  }'
    -
    -
    -
    Nota: Claude Opus 4.8 e Sonnet 4.6 têm janela de 1M tokens no Foundry. Recursos não suportados: Admin API, Compliance API, Models API e Message Batches API. Para suporte, forneça request-id e apim-request-id. Não há headers de rate limit da Anthropic — use o monitoramento do Azure.
    - -

    9.4. Claude Platform on AWS

    -

    Dá a experiência completa da plataforma Anthropic (Messages API, Agent Skills, code execution, features beta) operada pela Anthropic, acessada via conta AWS com billing pelo AWS Marketplace. Diferente do Bedrock (onde a AWS opera o stack), aqui a AWS provê apenas a camada de auth (SigV4/API key), controle IAM e billing.

    -

    Setup obrigatório (uma vez por conta AWS): habilitar outbound web identity federation com aws iam enable-outbound-web-identity-federation — sem isso toda requisição retorna "Outbound web identity federation is disabled for your account". É preciso um workspace ID (formato wrkspc_..., vinculado a uma região AWS) e definir ANTHROPIC_AWS_WORKSPACE_ID + AWS_REGION. Instalação: pip install -U "anthropic[aws]".

    -
    -
    - -
    -
    -
    from anthropic import AnthropicAWS
    -
    -# Lê ANTHROPIC_AWS_WORKSPACE_ID e resolve credenciais via cadeia padrão AWS (SigV4)
    -client = AnthropicAWS(aws_region="us-west-2")
    -
    -message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -print(message.content[0].text)
    -
    -
    -
    Atenção: precedência de credenciais do client AnthropicAWS: (1) api_key → x-api-key; (2) aws_access_key+aws_secret_access_key → SigV4; (3) aws_profile → SigV4; (4) ANTHROPIC_AWS_API_KEY → x-api-key; (5) cadeia padrão de credenciais AWS → SigV4. A região é obrigatória (sem fallback). As chaves de API são geradas no AWS Console (não no Claude Console). Tokens de curto prazo (12h) podem ser gerados pelas bibliotecas token-generator da AWS.
    -
    Nota: escolha Bedrock (não Claude Platform on AWS) se precisar de FedRAMP High, IL4/IL5, HIPAA-ready ou que a AWS seja o único processador de dados. Claude Platform on AWS suporta AWS PrivateLink e o parâmetro inference_geo.
    -
    - - - - -
    -

    10. Claude Managed Agents

    -

    Os Claude Managed Agents são um harness de agente pré-construído e configurável que roda em infraestrutura gerenciada — ideal para tarefas longas e trabalho assíncrono. Em vez de construir seu próprio loop de agente, execução de ferramentas e runtime, você obtém um ambiente onde o Claude lê arquivos, roda comandos, navega na web e executa código com segurança, com prompt caching e compactação embutidos.

    - -
    Atenção (beta): Managed Agents está em Beta. Todas as requisições exigem o header anthropic-beta: managed-agents-2026-04-01 (o SDK define automaticamente). Por ser stateful (sessões longas com histórico e estado server-side), não é elegível a ZDR nem a BAA HIPAA. Dreams exige adicionalmente dreaming-2026-04-21. Rate limits: 300 req/min em endpoints de criação, 600 req/min em leitura.
    -
    Novidades de 09/06/2026: (1) scheduled deployments — sessões executadas em agenda cron sem scheduler próprio (doc: managed-agents/scheduled-deployments); (2) vaults agora suportam credenciais por variável de ambiente, injetadas com segurança no sandbox (para CLIs/SDKs/serviços que autenticam via env var); (3) os eventos de webhook session.thread_* ganharam o campo session_thread_id, identificando a thread multi-agente que disparou o evento.
    - -

    10.1. Conceitos centrais

    -
    - - - - - - - -
    ConceitoDescrição
    AgentModelo + system prompt + tools + servidores MCP + skills. Criado uma vez e referenciado por ID; é versionado
    EnvironmentOnde as sessões rodam: container cloud gerenciado pela Anthropic ou self_hosted (sua infra)
    SessionInstância de um agente em um environment, executando uma tarefa e gerando outputs; mantém histórico
    EventsMensagens trocadas entre sua aplicação e o agente (turnos de usuário, resultados de tools, status)
    - -

    10.2. Quickstart: agente → environment → sessão → eventos

    -

    O fluxo é: criar um agente (com o toolset agent_toolset_20260401 que habilita bash, operações de arquivo, web search etc.), criar um environment, iniciar uma sessão e então enviar eventos user.message, recebendo respostas via SSE.

    -
    -
    - - -
    -
    -
    from anthropic import Anthropic
    -
    -client = Anthropic()  # define o beta header automaticamente
    -
    -# 1) Agente
    -agent = client.beta.agents.create(
    -    name="Coding Assistant",
    -    model="claude-opus-4-8",
    -    system="Você é um assistente de código. Escreva código limpo e documentado.",
    -    tools=[{"type": "agent_toolset_20260401"}],
    -)
    -
    -# 2) Environment (container cloud)
    -env = client.beta.environments.create(
    -    name="quickstart-env",
    -    config={"type": "cloud", "networking": {"type": "unrestricted"}},
    -)
    -
    -# 3) Sessão
    -session = client.beta.sessions.create(
    -    agent=agent.id,
    -    environment_id=env.id,
    -    title="Sessão quickstart",
    -)
    -print(agent.id, env.id, session.id)
    -
    -
    -
    # 1) Criar agente
    -curl https://api.anthropic.com/v1/agents \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -H "anthropic-beta: managed-agents-2026-04-01" \
    -  -H "content-type: application/json" \
    -  -d '{
    -    "name": "Coding Assistant",
    -    "model": "claude-opus-4-8",
    -    "system": "Você é um assistente de código.",
    -    "tools": [{"type": "agent_toolset_20260401"}]
    -  }'
    -
    -# 3) Iniciar sessão (após criar environment)
    -curl https://api.anthropic.com/v1/sessions \
    -  -H "x-api-key: $ANTHROPIC_API_KEY" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -H "anthropic-beta: managed-agents-2026-04-01" \
    -  -H "content-type: application/json" \
    -  -d '{"agent": "'"$AGENT_ID"'", "environment_id": "'"$ENVIRONMENT_ID"'"}'
    -
    -
    - -

    10.3. Environments & containers

    -

    Um environment é criado uma vez e referenciado por ID a cada sessão; várias sessões compartilham o environment, mas cada uma recebe um container isolado. Containers cloud vêm com Ubuntu 22.04, x86_64, até 8 GB de RAM e 10 GB de disco, e rede desabilitada por padrão (habilite via networking na config). Vêm pré-instalados Python 3.12+, Node.js 20+, Go, Rust, Java 21+, Ruby, PHP, C/C++, clientes SQLite/PostgreSQL/Redis e utilitários (git, curl, jq, ripgrep etc.).

    - - -

    10.4. Self-hosted sandboxes & modelo de segurança

    -

    Os self-hosted sandboxes mantêm a orquestração na Anthropic mas movem a execução de tools para infra que você controla — o código, filesystem e egress de rede do agente nunca saem do seu ambiente. Um environment worker (processo seu) consome itens da fila de trabalho do environment self_hosted, baixa as skills do agente, roda tool calls localmente e devolve resultados. Filesystem: /workspace (trabalho/skills) e /mnt/session/outputs (outputs finais).

    - -
    Cuidado (modelo de responsabilidade compartilhada): ao self-hospedar, você é responsável pela qualidade/hardening da imagem do container, controles de egress de rede, armazenamento e rotação do ANTHROPIC_ENVIRONMENT_KEY (a chave que autoriza o polling da fila — guarde em secret manager, nunca em env files ou imagens), isolamento de workloads não confiáveis e retenção/redação dos logs e conteúdo de sessão. A Anthropic não inspeciona sua imagem, não consegue revogar uma chave vazada antes de você detectá-la e não isola tools dentro do seu container.
    - -

    10.5. Eventos & streaming

    -

    A comunicação é baseada em eventos ({domain}.{action}). Você envia eventos de usuário; recebe eventos de agente, sessão e span.

    -
    - - - - - - - -
    DireçãoEventos (exemplos)
    User (envia)user.message · user.interrupt · user.custom_tool_result · user.tool_confirmation · user.define_outcome · user.tool_result (self-hosted)
    Agent (recebe)agent.message · agent.thinking · agent.tool_use · agent.tool_result · agent.mcp_tool_use · agent.custom_tool_use · agent.thread_context_compacted
    Session (recebe)session.status_running · session.status_idle (com stop_reason) · session.status_rescheduled · session.status_terminated · session.updated · session.error
    Span (recebe)span.model_request_start · span.model_request_end (com model_usage) · span.outcome_evaluation_*
    - - -

    10.6. Tools, skills, permission policies, memory, vaults, outcomes

    -
    - - - - - - - - - - - - - -
    RecursoO que faz
    Tools (agent_toolset_20260401)Toolset pré-construído: bash, operações de arquivo, web search/fetch; mais mcp_toolset e custom tools
    SkillsPacotes de capacidade carregados no container (baixados para /workspace/skills/<nome>/)
    Permission policiesalways_allow (executa sem confirmação) ou always_ask (pausa e aguarda aprovação via user.tool_confirmation). Custom tools não são governadas por políticas
    Memory storesColeção de documentos texto escopada por workspace, montada como diretório na sessão; cada alteração cria uma memory version imutável (audit trail). Requer o agent toolset
    Vaults & credentialsRegistram credenciais de terceiros uma vez e referenciam por ID na criação da sessão (per-user). Workspace-scoped
    Define outcomesDefine o "pronto" e uma rubrica; o harness provisiona um grader em janela de contexto separada que avalia e devolve gaps para o agente iterar
    Dreams Research PreviewJob assíncrono que lê uma memory store + transcrições e produz uma nova store reorganizada (dedup, atualização, novos insights); a store de entrada nunca é modificada
    GitHubMonta repositório no container e conecta ao GitHub MCP para clonar, ler e abrir PRs (repos são cacheados entre sessões)
    Multi-agentUm coordenador delega a outros agentes em session threads isoladas; compartilham container, filesystem e vault, mas têm contexto/tools próprios. Padrões: paralelização, especialização, escalonamento
    WebhooksNotificam mudanças de estado sem polling; entregam type+id (busque o objeto via GET). Assinados com header X-Webhook-Signature e segredo whsec_...; valide com o helper unwrap() do SDK
    - -
    Nota de fronteira: a Parte C também cobre Managed Agents do ângulo de ferramentas/skills/MCP. Aqui o foco é a superfície REST/governança (endpoints /v1/agents, /v1/sessions, /v1/environments, eventos, segurança self-hosted, retenção). Coordene com a Parte C para evitar duplicação de conteúdo conceitual de tools.
    -
    - - - - -
    -

    11. Governança & Admin

    -

    O plano de governança gerencia membros, workspaces, chaves, limites, custos, retenção e residência de dados. A maior parte usa a Admin API, que exige uma chave especial sk-ant-admin... (distinta das chaves padrão) provisionável apenas por membros com role admin.

    - -

    11.1. Admin API

    -

    Permite gerenciar programaticamente os recursos da organização: membros e roles, convites, workspaces e seus membros, e chaves de API. Indisponível para contas individuais (configure uma organização). Endpoints sob /v1/organizations/*, autenticados com x-api-key: $ANTHROPIC_ADMIN_KEY.

    - -

    Roles de organização:

    -
    - - - - - - - - -
    RolePermissões
    userUsar o Workbench
    claude_code_userWorkbench + Claude Code
    developerWorkbench + gerenciar chaves de API
    billingWorkbench + gerenciar billing
    adminTudo acima + gerenciar usuários
    -
    -
    - -
    -
    -
    # Listar membros da organização
    -curl "https://api.anthropic.com/v1/organizations/users?limit=10" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
    -
    -# Info da organização
    -curl "https://api.anthropic.com/v1/organizations/me" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
    -
    -
    -
    Atenção: novas chaves de API só podem ser criadas no Claude Console (não via Admin API). Admins de organização não podem ser removidos via API. Convites expiram em 21 dias. No Claude Platform on AWS, apenas os endpoints de workspace (/v1/organizations/workspaces) estão disponíveis.
    - -

    11.2. Workspaces

    -

    Workspaces organizam o uso da API dentro de uma organização — separam projetos/ambientes/times mantendo billing centralizado. IDs usam o prefixo wrkspc_. Máximo de 100 workspaces por organização (arquivados não contam). O Default Workspace não pode ser renomeado/arquivado/deletado e não tem ID (aparece como null em relatórios).

    - -

    Chaves de API são escopadas a um único workspace. Recursos escopados por workspace incluem Files, Message Batches e Skills; o prompt cache é isolado por workspace na API direta, Claude Platform on AWS e Foundry (por organização no Bedrock/Vertex). Roles de workspace: Workspace User, Limited Developer, Developer, Admin e Billing (herdada). Limites de workspace podem ser menores (não maiores) que os da organização.

    - -

    11.3. Autenticação: API keys vs Workload Identity Federation

    -

    Há dois métodos de autenticação, com o mesmo acesso aos endpoints:

    -
    - - - - - -
    MétodoCredencialMelhor para
    API keySegredo longo sk-ant-api... no header x-api-keyDev local, protótipos, scripts, servidores single-tenant
    Workload Identity Federation (WIF)Token bearer de curta duração trocado do JWT do seu IdPProdução em nuvem (AWS, GCP, Azure), CI/CD, Kubernetes — elimina segredos estáticos
    - - -

    11.4. Workload Identity Federation (WIF)

    -

    WIF permite que cargas de trabalho autentiquem com tokens OIDC de curta duração emitidos por um IdP que você já opera (AWS IAM, Google Cloud, ou qualquer emissor OIDC como GitHub Actions, Kubernetes, SPIFFE, Microsoft Entra ID, Okta), em vez de chaves estáticas sk-ant-.... O workload troca seu JWT em POST /v1/oauth/token (grant jwt-bearer da RFC 7523) por um token de acesso sk-ant-oat01-... de curta duração, que o SDK renova automaticamente.

    - -

    Três recursos no Console expressam "tokens assinados pelo emissor X, com claims Y, podem agir como service account Z":

    -
    - - - - - - -
    RecursoPrefixoPapel
    Service accountsvac_...Identidade não-humana que o token federado representa; ativa-se ao ser adicionada a um workspace
    Federation issuerfdis_...Registra o IdP (URL do iss + fonte JWKS: discovery/explicit_url/inline)
    Federation rulefdrl_...Ponte: match (subject_prefix/audience/claims/CEL) → target (service account) → authorization (scope, default workspace:developer; token_lifetime_seconds 60–86400, default 3600)
    -

    O corpo da troca de token (POST /v1/oauth/token) exige: grant_type (urn:ietf:params:oauth:grant-type:jwt-bearer), assertion (o JWT), federation_rule_id, organization_id, service_account_id e workspace_id (condicional). A resposta segue OAuth 2.0 (access_token, token_type, expires_in, scope).

    -
    -
    - - -
    -
    -
    from anthropic import Anthropic, WorkloadIdentityCredentials, IdentityTokenFile
    -
    -client = Anthropic(
    -    credentials=WorkloadIdentityCredentials(
    -        identity_token_provider=IdentityTokenFile("/var/run/secrets/anthropic.com/token"),
    -        federation_rule_id="fdrl_...",
    -        organization_id="00000000-0000-0000-0000-000000000000",
    -        service_account_id="svac_...",
    -        workspace_id="wrkspc_...",
    -    ),
    -)
    -
    -message = client.messages.create(
    -    model="claude-sonnet-4-6",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -print(message.content[0].text)
    -
    -
    -
    # 1) Trocar JWT do IdP por token de acesso Anthropic
    -RESPONSE=$(curl -sS https://api.anthropic.com/v1/oauth/token \
    -  -H "content-type: application/json" \
    -  --data '{
    -    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    -    "assertion": "'"$JWT"'",
    -    "federation_rule_id": "fdrl_...",
    -    "organization_id": "00000000-0000-0000-0000-000000000000",
    -    "service_account_id": "svac_...",
    -    "workspace_id": "wrkspc_..."
    -  }')
    -ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r .access_token)
    -
    -# 2) Chamar a API com Authorization: Bearer
    -curl https://api.anthropic.com/v1/messages \
    -  -H "authorization: Bearer $ACCESS_TOKEN" \
    -  -H "anthropic-version: 2023-06-01" \
    -  -H "content-type: application/json" \
    -  --data '{"model":"claude-sonnet-4-6","max_tokens":1024,"messages":[{"role":"user","content":"Olá"}]}'
    -
    -
    -

    Provedores de identidade suportados (guias dedicados): AWS · Google Cloud · Microsoft Azure · GitHub Actions · Kubernetes · SPIFFE · Okta.

    -
    Atenção (precedência): ANTHROPIC_API_KEY fica acima dos tiers de federação na cadeia de precedência — uma chave esquecida no ambiente silenciosamente sobrescreve o WIF. Ao migrar, confirme que ANTHROPIC_API_KEY está removida em todo lugar (env do container, secrets de CI, perfis de shell). Use ant auth status para ver qual fonte venceu. O token mintado vive o menor entre o token_lifetime_seconds da regra e o dobro da vida restante do JWT (piso de 60s); o SDK renova em expiração-120s (advisory) e expiração-30s (mandatória).
    - -

    11.5. Rate Limits API

    -

    Lê programaticamente os limites configurados para a organização e workspaces (mesma informação da página Limits do Console). Parte da Admin API (chave sk-ant-admin...). Endpoint org: GET /v1/organizations/rate_limits; workspace: GET /v1/organizations/workspaces/{id}/rate_limits (só retorna overrides; ausências são herdadas). É somente leitura — para alterar, use a aba Limits do Console.

    - -

    Cada entrada é um grupo de rate limit com group_type (model_group, batch, token_count, files, skills, web_search) e uma lista limits de pares {type, value} — requests_per_minute, input_tokens_per_minute, output_tokens_per_minute, enqueued_batch_requests etc. Filtre por ?model= (apenas no endpoint org) ou ?group_type=.

    - -

    11.6. Usage & Cost API

    -

    Acesso programático granular a uso e custo históricos. Parte da Admin API. Dois endpoints: GET /v1/organizations/usage_report/messages (uso — tokens por modelo/workspace/service tier; buckets 1m/1h/1d) e GET /v1/organizations/cost_report (custo em USD, granularidade diária). Dados aparecem em ~5 minutos; polling recomendado: 1×/min.

    - -
    -
    - -
    -
    -
    # Uso diário por modelo (últimos 7 dias)
    -curl "https://api.anthropic.com/v1/organizations/usage_report/messages?\
    -starting_at=2026-05-01T00:00:00Z&\
    -ending_at=2026-05-08T00:00:00Z&\
    -group_by[]=model&bucket_width=1d" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
    -
    -# Custo por workspace (mensal)
    -curl "https://api.anthropic.com/v1/organizations/cost_report?\
    -starting_at=2026-05-01T00:00:00Z&ending_at=2026-05-31T00:00:00Z&\
    -group_by[]=workspace_id&group_by[]=description" \
    -  --header "anthropic-version: 2023-06-01" \
    -  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
    -
    -
    -
    Nota: filtros/grupos incluem api_key_ids[], workspace_ids[], models[], service_tiers[], context_window[], inference_geo (valores global/us/not_available) e speed (beta, exige fast-mode-2026-02-01). Custos de Priority Tier e de code execution não aparecem no endpoint de custo (use o de uso). Para custos por usuário do Claude Code, use a Claude Code Analytics API. Integrações prontas: CloudZero, Datadog, Grafana Cloud, Honeycomb, Vantage.
    - -

    11.7. Retenção de dados (ZDR & HIPAA)

    -

    A Anthropic oferece dois arranjos de tratamento de dados para a Claude API: Zero Data Retention (ZDR) — dados do cliente não são armazenados em repouso após a resposta, exceto onde exigido por lei ou para combater abuso — e HIPAA readiness — para PHI, com BAA assinado e organização HIPAA-enabled.

    - -

    ZDR cobre as APIs de Mensagens e Token Counting (e Claude Code com chaves Commercial/Enterprise). Não cobre: Console/Workbench, Managed Agents (stateful), produtos de consumo, Teams/Enterprise (exceto Claude Code via Enterprise com ZDR) e integrações de terceiros. HIPAA readiness é imposta no nível da organização: requisições com features não-elegíveis retornam 400.

    -

    Elegibilidade de features (recorte):

    -
    - - - - - - - - - - - -
    FeatureZDRHIPAA
    Messages API / Token countingSimSim
    Prompt caching / Extended & adaptive thinking / Citations / 1M contextSimSim
    Structured outputsSim (qualificado)Sim (sem PHI no schema)
    Context management (compaction/editing)SimNão
    Web fetch / Advisor / Computer use / Tool searchSimNão
    Batch processingNãoNão
    Code execution / Programmatic tool callingNãoNão
    Files API / Agent skills / MCP connector / Managed Agents / MCP tunnelsNãoNão
    -
    Atenção: CORS não é suportado para organizações com ZDR — use um backend proxy e nunca exponha chaves no JavaScript do navegador. Mesmo com ZDR/HIPAA, dados podem ser retidos por até 2 anos se sinalizados por violação de política. Bedrock/Vertex têm o provedor de nuvem como processador (consulte suas próprias políticas); Claude Platform on AWS segue a política da API direta (ZDR sob demanda; HIPAA indisponível).
    - -

    11.8. Residência de dados

    -

    Dois controles independentes: Inference geo (onde a inferência roda, por requisição, via inference_geo) e Workspace geo (onde dados são armazenados em repouso, fixado na criação do workspace — atualmente só "us").

    - -

    Valores de inference_geo: "global" (default) e "us" (só infra dos EUA). A resposta reporta onde rodou em usage.inference_geo. Suportado em Claude Opus 4.8, Sonnet 4.6 e posteriores (modelos anteriores retornam 400). Configurável por workspace via allowed_inference_geos e default_inference_geo (campo data_residency na Admin API).

    -
    Nota (pricing): inferência US-only (inference_geo: "us") custa 1,1× a tarifa padrão em todas as categorias de token (e drena 1,1 token por token no burndown de Priority Tier). Roteamento global usa preço padrão. Disponível na API direta e Claude Platform on AWS; suportado também na Batch API (por requisição). Em Bedrock/Vertex/Foundry, a região é determinada pela URL/inference profile (parâmetro não se aplica).
    - -

    11.9. Compliance API

    -

    Acesso programático à atividade, chats, arquivos, projetos e usuários da organização para auditoria e governança. Habilitada sob demanda: organizações Claude Enterprise têm acesso completo; organizações Claude Console têm acesso apenas ao Activity Feed. Endpoints sob /v1/compliance/*, autenticados por x-api-key.

    - -

    Dois tipos de chave: uma Compliance Access Key (sk-ant-api01-..., criada no claude.ai) alcança todos os endpoints; uma Admin API key (sk-ant-admin01-...) alcança apenas o Activity Feed. Scopes: read:compliance_activities (feed), read:compliance_user_data (chats/arquivos/projetos/usuários), read:compliance_org_data (organizações/roles/grupos) e delete:compliance_user_data (deletes). Limite: 600 req/min por organização-pai. O Activity Feed retém 6 anos e novos eventos são consultáveis em ~1 min.

    -
    -
    - -
    -
    -
    # Evento de atividade mais recente
    -curl "https://api.anthropic.com/v1/compliance/activities?limit=1" \
    -  --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY"
    -
    -
    -
    Nota: o Activity Feed registra quem fez o quê e quando (autenticação, criação de chat/arquivo, ações administrativas) — não captura texto de prompt nem respostas. Para corpos de mensagem e conteúdo de arquivo, use os endpoints de conteúdo com uma Compliance Access Key (read:compliance_user_data), que servem apenas dados do claude.ai. Deletes são imediatos e irreversíveis. Padrões de consumo: window polling (com created_at.gte/.lt) ou cursor-driven (persistindo first_id/before_id); correlacione com SIEM por actor.user_id/email_address/ip_address/created_at.
    -
    - - - - - - - - -
    -

    Parte E — SDK Python (anthropic): referência exaustiva

    -

    Cobertura completa e fiel do SDK oficial anthropic para Python, extraída de - platform.claude.com/docs/en/api/sdks/python, - do api.md do repositório oficial e da referência da API. Aprofunda o que a - Parte D (D1 · SDKs) resume: instalação e extras, clientes síncrono/assíncrono e todas as - opções de construtor, mensagens, streaming, ferramentas, batches, contagem de tokens, arquivos, modelos, - paginação automática, hierarquia de erros, retries/timeouts, respostas cruas, sistema de tipos, logging, - requisições não documentadas, cliente HTTP customizado, namespace beta e os cinco clientes de plataforma. - Todos os exemplos usam os modelos atuais (claude-opus-4-8, claude-sonnet-4-6, - claude-haiku-4-5).

    -
    - -
    -

    E1. Instalação, requisitos e extras

    -

    O SDK anthropic dá acesso conveniente à API REST da Anthropic a partir de Python, com suporte a - operações síncronas e assíncronas, streaming e integrações com Amazon Bedrock, Vertex AI, Microsoft Foundry e - Claude Platform on AWS. Requer Python 3.9 ou superior.

    -
    # Instalação base
    -pip install anthropic
    -
    -# Extras por integração de plataforma
    -pip install "anthropic[bedrock]"   # Amazon Bedrock
    -pip install "anthropic[vertex]"    # Google Vertex AI
    -pip install "anthropic[aws]"       # Claude Platform on AWS
    -# Microsoft Foundry já vem incluso no pacote base
    -
    -# Backend assíncrono alternativo (melhor concorrência)
    -pip install "anthropic[aiohttp]"
    -
    - - - - - - - -
    ExtraHabilita
    anthropic[bedrock]Clientes AnthropicBedrockMantle / AnthropicBedrock
    anthropic[vertex]Cliente AnthropicVertex
    anthropic[aws]Cliente AnthropicAWS (beta)
    anthropic[aiohttp]Backend HTTP DefaultAioHttpClient (assíncrono)
    -

    E1.1 Versão instalada em tempo de execução

    -

    Se um recurso novo não aparece, confirme a versão efetivamente carregada no ambiente Python:

    -
    import anthropic
    -print(anthropic.__version__)
    -
    Dica: use python-dotenv - para carregar ANTHROPIC_API_KEY="..." de um arquivo .env e manter a chave fora do controle de versão.
    -

    O pacote segue SemVer, mas mudanças que afetam apenas tipos estáticos, internos públicos não - documentados, ou que não impactam a maioria dos usuários, podem sair como minor.

    - -
    - -
    -

    E2. Inicializando o cliente (síncrono e assíncrono)

    -

    O cliente síncrono é Anthropic; o assíncrono é AsyncAnthropic - (mesma interface, com await). Ambos leem a chave de ANTHROPIC_API_KEY por padrão.

    -
    -
    - - -
    -
    -
    import os
    -from anthropic import Anthropic
    -
    -client = Anthropic(
    -    api_key=os.environ.get("ANTHROPIC_API_KEY"),  # padrão; pode ser omitido
    -)
    -
    -message = client.messages.create(
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -    model="claude-opus-4-8",
    -)
    -print(message.content)
    -
    -
    -
    import os, asyncio
    -from anthropic import AsyncAnthropic
    -
    -client = AsyncAnthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
    -
    -async def main() -> None:
    -    message = await client.messages.create(
    -        max_tokens=1024,
    -        messages=[{"role": "user", "content": "Olá, Claude"}],
    -        model="claude-opus-4-8",
    -    )
    -    print(message.content)
    -
    -asyncio.run(main())
    -
    -
    - -

    E2.1 Opções do construtor

    -
    - - - - - - - - - - - -
    OpçãoTipoPadrão / EnvDescrição
    api_keystrANTHROPIC_API_KEYChave da API (header x-api-key).
    auth_tokenstr—Token Bearer (ex.: Workload Identity Federation) como alternativa à API key.
    base_urlstrANTHROPIC_BASE_URLSobrescreve a URL base (ex.: gateway/proxy).
    timeoutfloat · httpx.Timeout600 s (10 min)Timeout global; aceita granularidade por fase.
    max_retriesint2Retentativas automáticas com backoff exponencial.
    default_headersdict—Headers padrão em todas as requisições.
    default_querydict—Query params padrão em todas as requisições.
    http_clientDefaultHttpxClient · DefaultAioHttpClienthttpxCliente HTTP customizado (proxies, transporte, backend).
    - -

    E2.2 Backend aiohttp (melhor concorrência assíncrona)

    -
    import os, asyncio
    -from anthropic import AsyncAnthropic, DefaultAioHttpClient
    -
    -async def main() -> None:
    -    async with AsyncAnthropic(
    -        api_key=os.environ.get("ANTHROPIC_API_KEY"),
    -        http_client=DefaultAioHttpClient(),
    -    ) as client:
    -        message = await client.messages.create(
    -            max_tokens=1024,
    -            messages=[{"role": "user", "content": "Olá, Claude"}],
    -            model="claude-opus-4-8",
    -        )
    -        print(message.content)
    -
    -asyncio.run(main())
    - -

    E2.3 Gerenciando recursos HTTP

    -

    Por padrão, as conexões são fechadas quando o cliente é coletado pelo GC. Para controle explícito, use - .close() ou um context manager:

    -
    from anthropic import Anthropic
    -
    -with Anthropic() as client:
    -    message = client.messages.create(
    -        max_tokens=1024,
    -        messages=[{"role": "user", "content": "Olá, Claude"}],
    -        model="claude-opus-4-8",
    -    )
    -# cliente HTTP fechado automaticamente ao sair do bloco
    - -
    - -
    -

    E3. Mensagens e usage

    -

    O método central é client.messages.create(...) → retorna um objeto Message (modelo Pydantic). - O texto fica em message.content (lista de blocos); o consumo de tokens, em message.usage.

    -
    message = client.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Explique a teoria das cordas em 1 parágrafo."}],
    -)
    -print(message.content[0].text)
    -print(message.usage)   # Usage(input_tokens=25, output_tokens=13, ...)
    -print(message.stop_reason)
    -print(message._request_id)  # id da requisição (ver E13)
    -
    Tipos: os parâmetros aninhados são TypedDict (ex.: MessageParam, - ContentBlockParam); as respostas são modelos Pydantic (Message, TextBlock, - ToolUseBlock, ThinkingBlock, Usage). Veja a Parte D (D3) para o schema REST completo de parâmetros.
    - -
    - -
    -

    E4. Streaming (duas abordagens)

    -

    O SDK oferece duas formas de streaming via SSE — escolha conforme a necessidade:

    -
    - - - - - -
    AbordagemO que retornaQuando usar
    messages.create(..., stream=True)Iterável de eventos brutos (não monta o objeto final). Menos memória.Quando você só quer os deltas e cuida da acumulação.
    messages.stream(...) (context manager)Helper com .text_stream, acumulação e .get_final_message().Quando quer o texto incremental E o objeto Message final pronto.
    - -

    E4.1 Iterável de eventos (stream=True)

    -
    -
    - - -
    -
    -
    stream = client.messages.create(
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -    model="claude-opus-4-8",
    -    stream=True,
    -)
    -for event in stream:
    -    print(event.type)   # message_start, content_block_delta, ...
    -
    -
    -
    stream = await client.messages.create(
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -    model="claude-opus-4-8",
    -    stream=True,
    -)
    -async for event in stream:
    -    print(event.type)
    -
    -
    - -

    E4.2 Helper com acumulação (messages.stream)

    -
    import asyncio
    -from anthropic import AsyncAnthropic
    -
    -client = AsyncAnthropic()
    -
    -async def main() -> None:
    -    async with client.messages.stream(
    -        max_tokens=1024,
    -        messages=[{"role": "user", "content": "Diga olá!"}],
    -        model="claude-opus-4-8",
    -    ) as stream:
    -        async for text in stream.text_stream:    # apenas os deltas de texto
    -            print(text, end="", flush=True)
    -        print()
    -        message = await stream.get_final_message()  # objeto Message acumulado
    -        print(message.to_json())
    -
    -asyncio.run(main())
    -

    O stream() retorna um MessageStreamManager; o objeto de stream expõe também eventos - específicos do SDK além de .text_stream. Veja a Parte A (A5) para os tipos de evento SSE.

    - -
    - -
    -

    E5. Ferramentas como funções Python (@beta_tool + tool_runner)

    -

    Além de definir ferramentas manualmente (ver Parte C), o SDK gera o schema da - ferramenta a partir da assinatura e do docstring de uma função Python via o decorador @beta_tool, e - executa o laço de tool use automaticamente com client.beta.messages.tool_runner(...).

    -
    import json
    -from anthropic import Anthropic, beta_tool
    -
    -client = Anthropic()
    -
    -@beta_tool
    -def get_weather(location: str) -> str:
    -    """Obtém o clima de um local.
    -
    -    Args:
    -        location: cidade e estado, ex.: San Francisco, CA
    -    Returns:
    -        String JSON com local, temperatura e condição.
    -    """
    -    return json.dumps({"location": location, "temperature": "68°F", "condition": "Sunny"})
    -
    -# tool_runner cuida automaticamente das chamadas de ferramenta
    -runner = client.beta.messages.tool_runner(
    -    max_tokens=1024,
    -    model="claude-opus-4-8",
    -    tools=[get_weather],
    -    messages=[{"role": "user", "content": "Como está o tempo em SF?"}],
    -)
    -for message in runner:
    -    print(message)
    -

    A cada iteração é feita uma requisição à API; se o Claude quiser chamar uma ferramenta dada, ela é executada - automaticamente e o resultado volta ao modelo na próxima iteração.

    - -
    - -
    -

    E6. Message Batches no SDK (client.messages.batches)

    -

    Conceito e limites na Parte A (A12) e o lado REST na Parte D (D5). - No SDK, cada requisição tem um custom_id e os mesmos params da Messages API.

    -
    batch = client.messages.batches.create(
    -    requests=[
    -        {"custom_id": "req-1", "params": {
    -            "model": "claude-opus-4-8", "max_tokens": 1024,
    -            "messages": [{"role": "user", "content": "Olá, mundo"}]}},
    -        {"custom_id": "req-2", "params": {
    -            "model": "claude-opus-4-8", "max_tokens": 1024,
    -            "messages": [{"role": "user", "content": "Oi de novo, amigo"}]}},
    -    ]
    -)
    -
    -# Quando batch.processing_status == "ended", itere os resultados (stream JSONL):
    -for entry in client.messages.batches.results(batch.id):
    -    if entry.result.type == "succeeded":
    -        print(entry.custom_id, entry.result.message.content)
    -
    - - - - - - - - - -
    MétodoCaminho RESTRetorno
    batches.create(requests=[...])POST /v1/messages/batchesMessageBatch
    batches.retrieve(id)GET /v1/messages/batches/{id}MessageBatch
    batches.list(**params)GET /v1/messages/batchesSyncPage[MessageBatch]
    batches.cancel(id)POST /v1/messages/batches/{id}/cancelMessageBatch
    batches.delete(id)DELETE /v1/messages/batches/{id}DeletedMessageBatch
    batches.results(id)GET /v1/messages/batches/{id}/resultsJSONLDecoder[MessageBatchIndividualResponse]
    - -
    - -
    -

    E7. Contagem de tokens (count_tokens e usage)

    -

    Veja o consumo real de qualquer resposta em message.usage, ou estime antes de enviar com - messages.count_tokens(...):

    -
    # Uso real, após a resposta
    -message = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
    -                                 messages=[{"role": "user", "content": "Olá"}])
    -print(message.usage)            # Usage(input_tokens=25, output_tokens=13)
    -
    -# Estimativa antes do envio
    -count = client.messages.count_tokens(
    -    model="claude-opus-4-8",
    -    messages=[{"role": "user", "content": "Hello, world"}],
    -)
    -print(count.input_tokens)       # 10  (retorna MessageTokensCount)
    - -
    - -
    -

    E8. Upload de arquivos (client.beta.files)

    -

    Parâmetros que correspondem a uploads aceitam várias formas: um objeto PathLike (ex.: - pathlib.Path), uma tupla (filename, content, content_type), ou um objeto file-like - BinaryIO. No cliente assíncrono, PathLike é lido de forma assíncrona automaticamente.

    -
    from pathlib import Path
    -from anthropic import Anthropic
    -
    -client = Anthropic()
    -
    -# Por caminho
    -f = client.beta.files.upload(file=Path("/caminho/relatorio.pdf"))
    -
    -# Por bytes (tupla)
    -client.beta.files.upload(file=("nota.txt", b"meus bytes", "text/plain"))
    -
    -# Referenciando o arquivo numa mensagem (header beta obrigatório)
    -resp = client.beta.messages.create(
    -    model="claude-opus-4-8",
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": [
    -        {"type": "text", "text": "Resuma este documento."},
    -        {"type": "document", "source": {"type": "file", "file_id": f.id}},
    -    ]}],
    -    betas=["files-api-2025-04-14"],
    -)
    -
    - - - - - - - - -
    MétodoCaminho RESTRetorno
    beta.files.upload(file=...)POST /v1/filesFileMetadata
    beta.files.list(**params)GET /v1/filesSyncPage[FileMetadata]
    beta.files.retrieve_metadata(file_id)GET /v1/files/{id}FileMetadata
    beta.files.download(file_id)GET /v1/files/{id}/contentBinaryAPIResponse
    beta.files.delete(file_id)DELETE /v1/files/{id}DeletedFile
    -

    Profundidade de visão/PDF/documentos na Parte B (Files, PDF, Vision).

    - -
    - -
    -

    E9. Models API no SDK (client.models)

    -
    # Listar modelos disponíveis (paginado — ver E10)
    -for m in client.models.list(limit=20):
    -    print(m.id, m.display_name)
    -
    -# Recuperar um modelo específico e suas capacidades
    -info = client.models.retrieve("claude-opus-4-8")
    -print(info.max_input_tokens, info.max_output_tokens)
    -print(info.capabilities)   # ModelCapabilities: thinking, effort, context_management, ...
    -
    - - - - - -
    MétodoCaminhoRetorno
    models.list(**params)GET /v1/modelsSyncPage[ModelInfo]
    models.retrieve(model_id)GET /v1/models/{model_id}ModelInfo
    -

    Tipos: ModelInfo, ModelCapabilities, CapabilitySupport, - ThinkingCapability, EffortCapability, ContextManagementCapability. - Tabela canônica de modelos na Parte A (A3).

    - -
    - -
    -

    E10. Paginação automática

    -

    Métodos list são paginados. A forma idiomática é iterar diretamente — o SDK busca as páginas - seguintes conforme necessário (SyncPage / AsyncPage):

    -
    -
    - - -
    -
    -
    all_batches = []
    -for batch in client.messages.batches.list(limit=20):  # busca páginas automaticamente
    -    all_batches.append(batch)
    -
    -
    -
    all_batches = []
    -async for batch in client.messages.batches.list(limit=20):
    -    all_batches.append(batch)
    -
    -
    -

    Para controle granular de páginas:

    -
    first_page = client.messages.batches.list(limit=20)
    -if first_page.has_next_page():
    -    print(first_page.next_page_info())
    -    next_page = first_page.get_next_page()
    -    print(len(next_page.data))
    -
    -# Ou trabalhe diretamente com os dados da página
    -print(first_page.last_id)
    -for batch in first_page.data:
    -    print(batch.id)
    - -
    - -
    -

    E11. Tratamento de erros e hierarquia de exceções

    -

    Quando o SDK não consegue conectar, ou a API retorna 4xx/5xx, uma subclasse de APIError é levantada.

    -
    import anthropic
    -from anthropic import Anthropic
    -
    -client = Anthropic()
    -try:
    -    message = client.messages.create(
    -        max_tokens=1024,
    -        messages=[{"role": "user", "content": "Olá, Claude"}],
    -        model="claude-opus-4-8",
    -    )
    -except anthropic.APIConnectionError as e:
    -    print("Servidor inacessível")
    -    print(e.__cause__)              # exceção subjacente (httpx)
    -except anthropic.RateLimitError as e:
    -    print("429 recebido; aplicar backoff.")
    -except anthropic.APIStatusError as e:
    -    print("Outro status fora de 2xx:", e.status_code)
    -    print(e.response)
    -
    - - - - - - - - - - - - -
    Status HTTPExceção
    400BadRequestError
    401AuthenticationError
    403PermissionDeniedError
    404NotFoundError
    409ConflictError
    422UnprocessableEntityError
    429RateLimitError
    ≥ 500InternalServerError
    N/A (rede)APIConnectionError (e APITimeoutError)
    -

    Todas herdam de APIError; APIStatusError agrupa as que têm status_code e - response. Ver Parte D (D8) para o formato de erro REST e request-id.

    - -
    - -
    -

    E12. Retries, timeouts e requisições longas

    -

    E12.1 Retries

    -

    Por padrão, certos erros são retentados 2 vezes com backoff exponencial curto: - erros de conexão, 408, 409, 429 e ≥ 500.

    -
    from anthropic import Anthropic
    -
    -# Padrão para todas as requisições
    -client = Anthropic(max_retries=0)   # padrão é 2
    -
    -# Por requisição
    -client.with_options(max_retries=5).messages.create(
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -    model="claude-opus-4-8",
    -)
    -

    E12.2 Timeouts

    -

    Por padrão, as requisições expiram após 10 minutos. Aceita float ou - httpx.Timeout; em timeout, lança APITimeoutError (e a requisição é retentada).

    -
    import httpx
    -from anthropic import Anthropic
    -
    -client = Anthropic(timeout=20.0)  # 20 s (padrão = 10 min)
    -
    -# Granular por fase
    -client = Anthropic(timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0))
    -
    -# Por requisição
    -client.with_options(timeout=5.0).messages.create(
    -    max_tokens=1024, model="claude-opus-4-8",
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -
    Requisições longas: evite max_tokens alto sem streaming — - conexões ociosas podem cair. O SDK lança ValueError se uma requisição não-streaming for - estimada em mais de ~10 min; passar stream=True ou ajustar timeout desativa esse erro. - O SDK ativa TCP keep-alive para reduzir quedas por ociosidade (sobrescrevível via http_client).
    - -
    - -
    -

    E13. Resposta crua, streaming de corpo e Request ID

    -

    E13.1 Request ID

    -

    Todo objeto de resposta expõe ._request_id (do header request-id) — útil para logar - falhas e reportar à Anthropic. É a única propriedade _ pública.

    -
    message = client.messages.create(max_tokens=1024, model="claude-opus-4-8",
    -    messages=[{"role": "user", "content": "Olá, Claude"}])
    -print(message._request_id)  # ex.: req_018EeWyXxfu5pfWkrYcMdjWG
    -

    E13.2 with_raw_response (headers + corpo já lido)

    -
    response = client.messages.with_raw_response.create(
    -    max_tokens=1024, model="claude-opus-4-8",
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -)
    -print(response.headers.get("request-id"))
    -message = response.parse()   # objeto que messages.create() retornaria
    -print(message.content)
    -

    E13.3 with_streaming_response (corpo sob demanda)

    -

    Diferente de with_raw_response (que lê o corpo inteiro de imediato), - with_streaming_response exige context manager e só lê ao chamar .read(), .text(), - .json(), .iter_bytes(), .iter_text(), .iter_lines() ou .parse().

    -
    with client.messages.with_streaming_response.create(
    -    max_tokens=1024, model="claude-opus-4-8",
    -    messages=[{"role": "user", "content": "Olá, Claude"}],
    -) as response:
    -    print(response.headers.get("request-id"))
    -    for line in response.iter_lines():
    -        print(line)
    - -
    - -
    -

    E14. Sistema de tipos (request/response)

    -
      -
    • Requisições: parâmetros aninhados são TypedDict — autocompletar e checagem no editor.
    • -
    • Respostas: modelos Pydantic, com .to_json() e .to_dict().
    • -
    -
    message = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá"}])
    -json_str = message.to_json()   # string JSON
    -data = message.to_dict()       # dict
    -
    -# Distinguir campo null vs ausente
    -if message.some_field is None:
    -    if "some_field" not in message.model_fields_set:
    -        print("campo ausente na resposta")
    -    else:
    -        print("campo veio como null")
    -
    -# Propriedades não documentadas
    -extra = message.model_extra     # dict com campos extras
    -
    VS Code: defina python.analysis.typeCheckingMode como - basic para ver erros de tipo cedo.
    - -
    - -
    -

    E15. Logging, requisições não documentadas e cliente HTTP custom

    -

    E15.1 Logging

    -

    O SDK usa o módulo logging padrão. Habilite com a variável de ambiente:

    -
    export ANTHROPIC_LOG=debug   # ou info
    -

    E15.2 Endpoints/params não documentados

    -
    # Endpoint não documentado (respeita retries/timeout do cliente)
    -import httpx
    -response = client.post("/foo", cast_to=httpx.Response, body={"my_param": True})
    -print(response.json())
    -
    -# Param/header/query extra (sobrescrevem os documentados de mesmo nome!)
    -client.messages.create(
    -    model="claude-opus-4-8", max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá"}],
    -    extra_headers={"X-Custom": "1"},
    -    extra_query={"debug": "true"},
    -    extra_body={"experimental": {"flag": True}},
    -)
    -
    Segurança: extra_headers/extra_query/extra_body - sobrescrevem parâmetros documentados de mesmo nome — use apenas com dados confiáveis.
    -

    E15.3 Cliente HTTP customizado (proxies, transporte)

    -
    import httpx
    -from anthropic import Anthropic, DefaultHttpxClient
    -
    -client = Anthropic(
    -    base_url="http://meu.servidor.example.com:8083",  # ou env ANTHROPIC_BASE_URL
    -    http_client=DefaultHttpxClient(
    -        proxy="http://meu.proxy.example.com",
    -        transport=httpx.HTTPTransport(local_address="0.0.0.0"),
    -    ),
    -)
    -# Por requisição:
    -client.with_options(http_client=DefaultHttpxClient())
    -
    Use DefaultHttpxClient / DefaultAsyncHttpxClient - (e não httpx.Client cru) para preservar timeouts e limites de conexão padrão do SDK.
    -

    E15.4 Header de versão

    -

    O SDK envia automaticamente anthropic-version: 2023-06-01. Sobrescrever via - default_headers ou extra_headers pode causar comportamento indefinido — evite salvo necessidade real.

    - -
    - -
    -

    E16. Namespace beta

    -

    Recursos beta ficam sob client.beta.*. Para habilitar uma feature beta, inclua o - beta header apropriado - no campo betas ao criar a mensagem.

    -
    resp = client.beta.messages.create(
    -    model="claude-opus-4-8", max_tokens=1024,
    -    messages=[{"role": "user", "content": "..."}],
    -    betas=["files-api-2025-04-14"],   # ex.: Files API
    -)
    -
    - - - - - - - - - - - -
    Namespace betaPrincipais métodos
    client.beta.messages · .batchescreate, count_tokens, tool_runner; batches create/retrieve/list/cancel/delete/results
    client.beta.modelslist, retrieve
    client.beta.filesupload, list, retrieve_metadata, download, delete
    client.beta.agents · .versionscreate/retrieve/update/list/archive (Managed Agents — ver Parte D)
    client.beta.sessions · .events/.resources/.threadscreate/retrieve/update/list/delete/archive; eventos list/send/stream
    client.beta.vaults · .credentialscreate/retrieve/update/list/delete/archive; mcp_oauth_validate
    client.beta.memory_stores · .memoriescreate/retrieve/update/list/delete
    client.beta.skills · client.beta.user_profiles · client.beta.environmentsCRUD de skills, perfis de usuário e ambientes
    -

    Tipos beta espelham os estáveis com prefixo Beta (ex.: BetaMessage, BetaUsage, - BetaModelInfo, FileMetadata).

    - -
    - -
    -

    E17. Clientes de plataforma (Bedrock, Vertex, Foundry, AWS)

    -

    Os cinco clientes vêm no pacote base anthropic (alguns exigem extras). Detalhes de cada plataforma - na Parte D (D9).

    -
    - - - - - - - - -
    ProvedorClasse (import de anthropic)Extra
    Bedrock (novo)AnthropicBedrockMantleanthropic[bedrock]
    Bedrock (InvokeModel legado)AnthropicBedrockanthropic[bedrock]
    Vertex AIAnthropicVertexanthropic[vertex]
    Microsoft FoundryAnthropicFoundry—
    Claude Platform on AWS BetaAnthropicAWSanthropic[aws]
    -
    # Exemplos de inicialização
    -from anthropic import AnthropicBedrockMantle, AnthropicVertex, AnthropicAWS
    -
    -bedrock = AnthropicBedrockMantle()           # novo padrão p/ Bedrock
    -vertex  = AnthropicVertex(region="us-east5", project_id="meu-projeto")
    -aws     = AnthropicAWS(workspace_id="...")   # ou env ANTHROPIC_AWS_WORKSPACE_ID (beta)
    -
    -msg = bedrock.messages.create(
    -    model="anthropic.claude-opus-4-8",       # IDs com prefixo de plataforma — ver Parte D
    -    max_tokens=1024,
    -    messages=[{"role": "user", "content": "Olá"}],
    -)
    -
    Recomendação: use AnthropicBedrockMantle em projetos novos; - AnthropicBedrock permanece para apps existentes que usam a API InvokeModel do Bedrock.
    - -
    - - - - -
    -

    Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk): referência exaustiva

    -

    Cobertura completa e fiel do SDK oficial @anthropic-ai/sdk, extraída de - platform.claude.com/docs/en/api/sdks/typescript - e do repositório oficial. Espelha a Parte E (SDK Python) para o ecossistema - JS/TS: instalação e runtimes suportados, cliente e todas as opções, mensagens e tipos, streaming - (iterável e por event handlers), helpers de ferramentas (Zod/JSON + ToolError), - helpers de MCP, batches, contagem de tokens, upload de arquivos (toFile), modelos e paginação, - hierarquia de erros, retries/timeouts (incluindo a fórmula dinâmica), respostas cruas, logging, - requisições não documentadas, fetch/proxy customizado, namespace beta, pacotes de plataforma - e o aviso de uso no navegador. Todos os exemplos usam os modelos atuais - (claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5).

    -
    - -
    -

    F1. Instalação e runtimes suportados

    -
    npm install @anthropic-ai/sdk
    -# ou: pnpm add @anthropic-ai/sdk · yarn add @anthropic-ai/sdk · bun add @anthropic-ai/sdk
    -

    Requer TypeScript ≥ 4.9. Runtimes oficialmente suportados:

    -
    - - - - - - - - - - - - -
    RuntimeSuporte
    Node.js20 LTS+ (versões não-EOL)
    Denov1.28.0+
    Bun1.0+
    Cloudflare WorkersSim
    Vercel Edge RuntimeSim
    Nitrov2.6+
    Jest28+ com ambiente "node" ("jsdom" não suportado)
    Navegador (browser)Desabilitado por padrão — habilite com dangerouslyAllowBrowser: true (ver F18)
    React NativeNão suportado
    -
    SemVer: o pacote segue SemVer, mas mudanças que afetam apenas tipos - estáticos, internos públicos não documentados, ou de impacto mínimo, podem sair como minor.
    - -
    - -
    -

    F2. Inicializando o cliente e opções

    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic({
    -  apiKey: process.env["ANTHROPIC_API_KEY"], // padrão; pode ser omitido
    -});
    -
    -const message = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: "Olá, Claude" }],
    -});
    -console.log(message.content);
    -

    F2.1 Opções do construtor

    -
    - - - - - - - - - - - - - - - -
    OpçãoTipoPadrão / EnvDescrição
    apiKeystringANTHROPIC_API_KEYChave da API (header x-api-key).
    authTokenstringANTHROPIC_AUTH_TOKENToken Bearer (ex.: WIF) como alternativa à API key.
    baseURLstringhttps://api.anthropic.com · ANTHROPIC_BASE_URLSobrescreve a URL base.
    timeoutnumber (ms)600000 (10 min; dinâmico p/ max_tokens alto — ver F12)Timeout da requisição.
    maxRetriesnumber2Retentativas automáticas com backoff.
    defaultHeadersobject—Headers padrão em todas as requisições.
    defaultQueryobject—Query params padrão.
    fetchOptionsRequestInit—Opções repassadas ao fetch (proxy, agent — ver F15).
    fetchfunçãoglobalThis.fetchImplementação de fetch customizada.
    logLevelstring'warn' · ANTHROPIC_LOGdebug | info | warn | error | off.
    loggerLoggerglobalThis.consoleLogger custom (pino, winston, bunyan…).
    dangerouslyAllowBrowserbooleanfalseHabilita execução no navegador (ver F18).
    - -
    - -
    -

    F3. Mensagens, tipos e usage

    -

    A biblioteca inclui definições TypeScript para todos os params de requisição e campos de resposta — - importáveis via o namespace Anthropic.*. Documentação de cada método/param aparece no hover do editor.

    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic();
    -
    -const params: Anthropic.MessageCreateParams = {
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: "Olá, Claude" }],
    -};
    -const message: Anthropic.Message = await client.messages.create(params);
    -
    -console.log(message.content[0]);   // ContentBlock (ex.: TextBlock)
    -console.log(message.usage);        // { input_tokens: 25, output_tokens: 13 }
    -console.log(message.stop_reason);  // "end_turn" | "max_tokens" | "tool_use" | ...
    -console.log(message._request_id);  // ver F13
    - -
    - -
    -

    F4. Streaming (iterável e por event handlers)

    -

    Duas abordagens, como no Python: create({stream:true}) retorna um async iterable de eventos - (menos memória); messages.stream(...) adiciona event handlers e acumulação.

    -

    F4.1 Iterável de eventos (stream: true)

    -
    const stream = await client.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: "Olá, Claude" }],
    -  stream: true,
    -});
    -for await (const event of stream) {
    -  console.log(event.type);   // message_start, content_block_delta, ...
    -}
    -// Para cancelar: break no loop, ou stream.controller.abort()
    -

    F4.2 Helper com event handlers (messages.stream)

    -
    const stream = client.messages
    -  .stream({
    -    model: "claude-opus-4-8",
    -    max_tokens: 1024,
    -    messages: [{ role: "user", content: "Diga olá!" }],
    -  })
    -  .on("text", (text) => process.stdout.write(text))      // delta de texto
    -  .on("streamEvent", (event) => { /* evento bruto SSE */ })
    -  .on("contentBlock", (block) => { /* bloco completo */ })
    -  .on("message", (msg) => { /* mensagem parcial acumulada */ })
    -  .on("finalMessage", (msg) => { /* mensagem final */ });
    -
    -const message = await stream.finalMessage();   // Promise<Message>
    -console.log(message);
    -
    Handlers disponíveis: text, streamEvent, - contentBlock, message, finalMessage. O objeto de stream também é - async iterable (for await … of stream). Tipos de evento SSE na Parte A (A5).
    - -
    - -
    -

    F5. Helpers de ferramentas (Zod / JSON Schema + ToolError)

    -

    O SDK JS facilita criar e executar ferramentas com esquemas Zod ou JSON Schema, executadas - via client.beta.messages.toolRunner() — que passa os inputs do modelo à função certa e devolve o - resultado ao modelo automaticamente.

    -
    import Anthropic from "@anthropic-ai/sdk";
    -import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
    -import { z } from "zod";
    -
    -const anthropic = new Anthropic();
    -
    -const weatherTool = betaZodTool({
    -  name: "get_weather",
    -  description: "Obtém o clima atual de um local",
    -  inputSchema: z.object({ location: z.string() }),
    -  run: (input) => `O tempo em ${input.location} está nublado, 16°C`,
    -});
    -
    -const finalMessage = await anthropic.beta.messages.toolRunner({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1000,
    -  messages: [{ role: "user", content: "Como está o tempo em São Paulo?" }],
    -  tools: [weatherTool],
    -});
    -console.log(finalMessage.content);
    -

    F5.1 Erros de ferramenta (ToolError)

    -

    Para reportar um erro ao modelo, lance ToolError de dentro do run — diferente de um - Error comum, ele aceita content blocks (texto, imagem) na resposta de erro. Um Error - comum é convertido num bloco de texto.

    -
    import { ToolError } from "@anthropic-ai/sdk/lib/tools/BetaRunnableTool";
    -
    -const screenshotTool = betaZodTool({
    -  name: "take_screenshot",
    -  inputSchema: z.object({ url: z.string() }),
    -  run: async (input) => {
    -    if (!isValidUrl(input.url)) throw new ToolError(`URL inválida: ${input.url}`);
    -    const result = await takeScreenshot(input.url);
    -    if (result.error) {
    -      throw new ToolError([
    -        { type: "text", text: `Falha ao carregar: ${result.error}` },
    -        { type: "image", source: { type: "base64", data: result.screenshot, media_type: "image/png" } },
    -      ]);
    -    }
    -    return { type: "image", source: { type: "base64", data: result.screenshot, media_type: "image/png" } };
    -  },
    -});
    -

    Também é possível definir ferramentas manualmente via input_schema (JSON Schema) em - messages.create({tools:[...]}) — ver Parte C.

    - -
    - -
    -

    F6. Helpers de MCP (Model Context Protocol)

    -

    O SDK JS converte tipos MCP para tipos da Claude API, reduzindo boilerplate ao usar ferramentas, - prompts e recursos de servidores MCP locais. (Para servidores MCP remotos por URL - com suporte só a ferramentas, prefira o parâmetro mcp_servers — ver Parte C (MCP).)

    -
    import Anthropic from "@anthropic-ai/sdk";
    -import { mcpTools, mcpMessages, mcpResourceToContent, mcpResourceToFile }
    -  from "@anthropic-ai/sdk/helpers/beta/mcp";
    -import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    -import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
    -
    -const anthropic = new Anthropic();
    -const transport = new StdioClientTransport({ command: "mcp-server", args: [] });
    -const mcpClient = new Client({ name: "my-client", version: "1.0.0" });
    -await mcpClient.connect(transport);
    -
    -// Prompts MCP → mensagens
    -const { messages } = await mcpClient.getPrompt({ name: "my-prompt" });
    -await anthropic.beta.messages.create({
    -  model: "claude-opus-4-8", max_tokens: 1024, messages: mcpMessages(messages),
    -});
    -
    -// Ferramentas MCP com toolRunner
    -const { tools } = await mcpClient.listTools();
    -await anthropic.beta.messages.toolRunner({
    -  model: "claude-opus-4-8", max_tokens: 1024,
    -  messages: [{ role: "user", content: "Use as ferramentas disponíveis" }],
    -  tools: mcpTools(tools, mcpClient),
    -});
    -
    -// Recurso MCP como conteúdo / como arquivo
    -const resource = await mcpClient.readResource({ uri: "file:///doc.txt" });
    -mcpResourceToContent(resource);
    -await anthropic.beta.files.upload({ file: mcpResourceToFile(resource) });
    -
    Erros: as funções de conversão lançam UnsupportedMCPValueError - se um valor MCP não for suportado (tipo de conteúdo/MIME inválido, recurso não-http/https).
    - -
    - -
    -

    F7. Message Batches (client.messages.batches)

    -
    const batch = await client.messages.batches.create({
    -  requests: [
    -    { custom_id: "req-1", params: {
    -        model: "claude-opus-4-8", max_tokens: 1024,
    -        messages: [{ role: "user", content: "Olá, mundo" }] } },
    -    { custom_id: "req-2", params: {
    -        model: "claude-opus-4-8", max_tokens: 1024,
    -        messages: [{ role: "user", content: "Oi de novo, amigo" }] } },
    -  ],
    -});
    -
    -// Quando batch.processing_status === "ended":
    -const results = await client.messages.batches.results(batch.id);
    -for await (const entry of results) {
    -  if (entry.result.type === "succeeded") console.log(entry.result.message.content);
    -}
    -

    Conceito e limites na Parte A (A12); schema REST na Parte D (D5).

    - -
    - -
    -

    F8. Contagem de tokens (countTokens)

    -
    const count = await client.messages.countTokens({
    -  model: "claude-opus-4-8",
    -  messages: [{ role: "user", content: "Hello, world" }],
    -});
    -console.log(count.input_tokens);
    -
    -// Uso real após a resposta:
    -const message = await client.messages.create(/* ... */);
    -console.log(message.usage); // { input_tokens: 25, output_tokens: 13 }
    - -
    - -
    -

    F9. Upload de arquivos (toFile e variantes)

    -

    Parâmetros de upload aceitam: um File (ou objeto equivalente), uma Response do - fetch, um fs.ReadStream, ou o retorno do helper toFile. - Defina o content-type explicitamente — a Files API não o infere.

    -
    import fs from "fs";
    -import Anthropic, { toFile } from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic();
    -
    -// fs.ReadStream
    -await client.beta.files.upload({
    -  file: await toFile(fs.createReadStream("/caminho/data.json"), undefined, { type: "application/json" }),
    -});
    -// Web File API
    -await client.beta.files.upload({ file: new File(["meus bytes"], "file.txt", { type: "text/plain" }) });
    -// Response do fetch
    -await client.beta.files.upload({ file: await fetch("https://site/arquivo") });
    -// Buffer / Uint8Array
    -await client.beta.files.upload({ file: await toFile(Buffer.from("meus bytes"), "file", { type: "text/plain" }) });
    -

    Profundidade de visão/PDF/documentos na Parte B; endpoints REST na Parte D (D7).

    - -
    - -
    -

    F10. Models API e paginação automática

    -
    // Recuperar
    -const model = await client.models.retrieve("claude-opus-4-8");
    -
    -// Listar com auto-paginação (busca páginas conforme necessário)
    -for await (const m of client.models.list({ limit: 20 })) console.log(m.id);
    -
    -// Uma página por vez + navegação manual
    -let page = await client.messages.batches.list({ limit: 20 });
    -for (const item of page.data) console.log(item);
    -while (page.hasNextPage()) { page = await page.getNextPage(); }
    -
    -// Iterar páginas
    -for await (const p of client.models.list().iterPages()) console.log(p.data);
    -

    Tabela canônica de modelos na Parte A (A3).

    - -
    - -
    -

    F11. Tratamento de erros

    -
    const message = await client.messages
    -  .create({ model: "claude-opus-4-8", max_tokens: 1024,
    -            messages: [{ role: "user", content: "Olá, Claude" }] })
    -  .catch((err) => {
    -    if (err instanceof Anthropic.APIError) {
    -      console.log(err.status);  // 400
    -      console.log(err.name);    // BadRequestError
    -      console.log(err.headers); // { server: 'nginx', ... }
    -    } else { throw err; }
    -  });
    -
    - - - - - - - - - - - - - -
    StatusClasse
    400BadRequestError
    401AuthenticationError
    403PermissionDeniedError
    404NotFoundError
    409ConflictError
    422UnprocessableEntityError
    429RateLimitError
    ≥ 500InternalServerError
    redeAPIConnectionError
    timeoutAPIConnectionTimeoutError
    -

    Todas herdam de Anthropic.APIError. Formato de erro REST na Parte D (D8).

    - -
    - -
    -

    F12. Retries e timeouts (incl. fórmula dinâmica)

    -

    F12.1 Retries

    -

    Padrão: 2 retentativas com backoff (conexão, 408, 409, 429, ≥500).

    -
    const client = new Anthropic({ maxRetries: 0 });   // padrão é 2
    -// por requisição:
    -await client.messages.create({ /* ... */ }, { maxRetries: 5 });
    -

    F12.2 Timeouts

    -

    Padrão: 10 minutos. Porém, se max_tokens for grande e você não estiver - usando streaming, o timeout default é calculado dinamicamente (até ~60 min):

    -
    // fórmula do default dinâmico (não-streaming, max_tokens grande):
    -const minimum = 10 * 60;
    -const calculated = (60 * 60 * maxTokens) / 128_000;
    -const timeoutMs = (calculated < minimum ? minimum : calculated) * 1000;
    -
    -const client = new Anthropic({ timeout: 20 * 1000 }); // 20 s (override do default)
    -await client.messages.create({ /* ... */ }, { timeout: 5 * 1000 }); // por requisição
    -

    Em timeout lança APIConnectionTimeoutError (e a requisição é retentada). Para requisições longas, - prefira streaming; passar stream:true ou timeout desativa o erro de "requisição > 10 min".

    - -
    - -
    -

    F13. Request ID e resposta crua (asResponse / withResponse)

    -
    // Request ID (header request-id) — para logar/correlacionar com o suporte
    -const message = await client.messages.create({ /* ... */ });
    -console.log(message._request_id); // req_018Ee...
    -
    -// .asResponse(): retorna o Response cru assim que os headers chegam (não consome o corpo)
    -const response = await client.messages.create({ /* ... */ }).asResponse();
    -console.log(response.headers.get("request-id"));
    -
    -// .withResponse(): consome o corpo e devolve { data, response }
    -const { data, response: raw } = await client.messages.create({ /* ... */ }).withResponse();
    -console.log(raw.headers.get("request-id"), data.content);
    - -
    - -
    -

    F14. Logging

    -

    Configure por variável de ambiente ANTHROPIC_LOG ou pela opção logLevel (que sobrescreve - a env). Níveis: debug ▸ info ▸ warn (padrão) ▸ error ▸ off. - No nível debug, todas as requisições/respostas HTTP são logadas (alguns headers de auth são redigidos).

    -
    // via opção
    -const client = new Anthropic({ logLevel: "debug" });
    -
    -// logger custom (pino, winston, bunyan, consola, signale, @std/log)
    -import pino from "pino";
    -const logger = pino();
    -new Anthropic({ logger: logger.child({ name: "Anthropic" }), logLevel: "debug" });
    -
    ANTHROPIC_LOG=debug node script.js
    - -
    - -
    -

    F15. Requisições não documentadas, fetch e proxies

    -

    F15.1 Endpoints/params não documentados

    -
    // endpoint não documentado (respeita retries/opções do cliente)
    -await client.post("/some/path", { body: { some_prop: "foo" }, query: { arg: "bar" } });
    -
    -// param extra: use @ts-expect-error (não validado em runtime; enviado as-is)
    -client.messages.create({
    -  model: "claude-opus-4-8", max_tokens: 1024, messages: [/* ... */],
    -  // @ts-expect-error baz ainda não é público
    -  baz: "opção não documentada",
    -});
    -

    F15.2 fetch customizado e fetchOptions

    -
    import Anthropic from "@anthropic-ai/sdk";
    -import myFetch from "my-fetch";
    -
    -const client = new Anthropic({
    -  fetch: myFetch,                 // ou globalThis.fetch = myFetch
    -  fetchOptions: { /* RequestInit */ },
    -});
    -

    F15.3 Proxies por runtime

    -
    -
    - - - -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -import * as undici from "undici";
    -
    -const proxyAgent = new undici.ProxyAgent("http://localhost:8888");
    -const client = new Anthropic({ fetchOptions: { dispatcher: proxyAgent } });
    -
    -
    -
    import Anthropic from "@anthropic-ai/sdk";
    -
    -const client = new Anthropic({ fetchOptions: { proxy: "http://localhost:8888" } });
    -
    -
    -
    import Anthropic from "npm:@anthropic-ai/sdk";
    -
    -const httpClient = Deno.createHttpClient({ proxy: { url: "http://localhost:8888" } });
    -const client = new Anthropic({ fetchOptions: { client: httpClient } });
    -
    -
    - -
    - -
    -

    F16. Namespace beta

    -
    const response = await client.beta.messages.create({
    -  model: "claude-opus-4-8",
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: [
    -    { type: "text", text: "Resuma este documento." },
    -    { type: "document", source: { type: "file", file_id: "file_abc123" } },
    -  ]}],
    -  betas: ["files-api-2025-04-14"],   // habilita a feature beta via header
    -});
    -

    Ative cada feature beta incluindo o beta header em betas: [...]. Espelha o namespace beta do Python (E16).

    - -
    - -
    -

    F17. Pacotes de plataforma (npm separados)

    -

    Diferente do Python (clientes no pacote base), no JS cada plataforma é um pacote npm separado:

    -
    - - - - - - - -
    PlataformaPacote npmCliente
    Amazon Bedrock@anthropic-ai/bedrock-sdkAnthropicBedrockMantle (novo) · AnthropicBedrock (path bedrock-runtime/InvokeModel legado)
    Google Vertex AI@anthropic-ai/vertex-sdkAnthropicVertex
    Microsoft Foundry@anthropic-ai/foundry-sdkAnthropicFoundry
    Claude Platform on AWS Beta@anthropic-ai/aws-sdkAnthropicAws (workspaceId ou ANTHROPIC_AWS_WORKSPACE_ID)
    -
    import AnthropicBedrock from "@anthropic-ai/bedrock-sdk";
    -import AnthropicVertex from "@anthropic-ai/vertex-sdk";
    -
    -const bedrock = new AnthropicBedrock({ awsRegion: "us-east-1" });
    -const vertex  = new AnthropicVertex({ projectId: "meu-projeto", region: "us-east5" });
    -
    -const msg = await bedrock.messages.create({
    -  model: "anthropic.claude-opus-4-8",  // IDs com prefixo de plataforma — ver Parte D
    -  max_tokens: 1024,
    -  messages: [{ role: "user", content: "Olá" }],
    -});
    -

    Detalhes por plataforma (IDs, auth) na Parte D (D9).

    - -
    - -
    -

    F18. Uso no navegador (dangerouslyAllowBrowser)

    -
    Perigo: habilitar dangerouslyAllowBrowser: true expõe sua - chave secreta no código client-side. Qualquer usuário com acesso ao navegador pode inspecionar e extrair as - credenciais. Use apenas em cenários controlados: ferramentas internas com usuários confiáveis, - ou desenvolvimento/depuração com credenciais efêmeras e rotacionadas — nunca com a chave de produção.
    -
    const client = new Anthropic({ apiKey: "...", dangerouslyAllowBrowser: true });
    -

    Padrão recomendado: faça as chamadas a partir de um backend e exponha apenas um endpoint seu ao navegador.

    - -
    -
    -

    Apêndice

    -

    Notebooks do cookbook oficial, glossário consolidado e histórico deste guia.

    -
    -
    -

    Cookbook — notebooks & exemplos oficiais

    -

    Exemplos executáveis mantidos pela Anthropic. Use sempre os modelos atuais - (claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5) ao rodar.

    - -
    -
    -

    Glossário

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    TermoDefinição
    Divulgação progressivaEstratégia das Skills de carregar metadados sempre, instruções ao acionar e recursos sob demanda.
    Managed AgentHarness gerenciado (Agent, Environment, Session, Events) para tarefas longas/assíncronas.
    MCP tunnelsForma outbound-only de expor servidores MCP de rede privada ao Claude, via cloudflared + proxy.
    SigV4Assinatura de requisição AWS usada por Bedrock e Claude Platform on AWS.
    SKILL.mdArquivo com frontmatter YAML (name, description) que define uma Agent Skill; carregado por divulgação progressiva.
    WIF (Workload Identity Federation)Autenticação por token OIDC de curta duração via POST /v1/oauth/token (grant jwt-bearer).
    ZDR (Zero Data Retention)Arranjo em que dados não são armazenados em repouso após a resposta da API.
    @anthropic-ai/sdkPacote npm oficial do SDK JavaScript/TypeScript da Anthropic.
    @beta_toolDecorador que gera o schema da ferramenta a partir da assinatura/docstring de uma função Python.
    _request_idID da requisição (header request-id); única propriedade _ pública.
    adaptive thinkingModo de raciocínio em que o modelo decide quando/quanto pensar; recomendado para Opus 4.8 (thinking: {type:"adaptive"}).
    agent_toolset_20260401Toolset pré-construído de Managed Agents: bash, operações de arquivo, web search/fetch.
    allowed_callersArray que define quem chama a ferramenta: "direct" (modelo) e/ou "code_execution_20260120" (sandbox).
    Anthropic / AsyncAnthropicClasses de cliente síncrono e assíncrono do SDK Python.
    anthropic-betaHeader que habilita features beta (ex. managed-agents-2026-04-01, files-api-2025-04-14).
    anthropic-versionCabeçalho obrigatório de versão da API; valor atual: 2023-06-01.
    ANTHROPIC_ENVIRONMENT_KEYChave que autoriza o worker self-hosted a consumir a fila de trabalho do environment.
    ANTHROPIC_LOGVariável de ambiente para logging (debug | info).
    AnthropicBedrockMantleCliente recomendado para Amazon Bedrock em projetos novos.
    APIConnectionTimeoutErrorExceção lançada quando uma requisição expira (timeout) no SDK JS.
    asResponse() / withResponse()Acessam o Response cru do fetch (headers); withResponse devolve { data, response }.
    betasLista de beta headers passada em client.beta.messages.create para habilitar features beta.
    betaZodToolHelper que define uma ferramenta a partir de um schema Zod, com função run() executada pelo toolRunner.
    budget_tokensOrçamento fixo de tokens de pensamento no modo manual (thinking.type: "enabled").
    cache_controlMarca breakpoint de prompt caching ({"type":"ephemeral"}, opcional "ttl":"1h").
    cache_creation_input_tokensTokens escritos no cache; se ele e cache_read_input_tokens são 0, não houve cache.
    cache_miss_reasonMotivo do cache miss, retornado com a beta cache-diagnosis-2026-04-07.
    cache_read_input_tokensTokens lidos do cache (cobrados a 0,1× do input base).
    citationsHabilita citações verificáveis ({"enabled": true}) em document/search_result.
    clear_thinking_20251015Edit que remove blocos de pensamento antigos do contexto.
    clear_tool_uses_20250919Edit que remove resultados de ferramenta antigos do contexto.
    compact_20260112Edit que resume o histórico antigo (compaction) em vez de removê-lo.
    containerParâmetro da Messages API usado para referenciar Skills (skill_id/type/version) e reusar contêineres de code execution.
    context windowJanela de contexto: total de tokens referenciáveis (Opus 4.8 / Sonnet 4.6: 1M; Haiku 4.5: 200k).
    context_managementControla edição/compactação de contexto via edits (betas context-management-2025-06-27 / compact-2026-01-12).
    count_tokensEndpoint /v1/messages/count_tokens que estima input_tokens antes do envio.
    custom_idIdentificador único (1–64 chars) de cada request num Message Batch.
    dangerouslyAllowBrowserHabilita o SDK no navegador (expõe a chave — usar só em cenários controlados).
    DefaultHttpxClient / DefaultAioHttpClientClientes HTTP do SDK (httpx padrão; aiohttp para concorrência assíncrona).
    defer_loadingPropriedade que exclui a ferramenta do prompt inicial, carregando-a sob demanda via tool search; preserva o prompt cache.
    displayComo o pensamento volta na resposta: summarized ou omitted (padrão no Opus 4.8).
    documentBloco de conteúdo para PDF/texto/conteúdo customizado; suporta citations e cache_control.
    eager_input_streamingHabilita fine-grained tool streaming (sem buffering/validação de JSON) em ferramentas de usuário.
    effortEm output_config.effort: controla o gasto de tokens (low, medium, high, xhigh, max). Padrão = high. xhigh disponível em Opus 4.8/4.7, Sonnet 5, Fable 5, Mythos 5; max em todos com adaptive thinking (inclui Sonnet 5 e Sonnet 4.6).
    fetchOptionsRequestInit repassado ao fetch (proxy/agent/dispatcher por runtime).
    file_idIdentificador de arquivo da Files API (beta files-api-2025-04-14) referenciável por source.type: "file".
    imageBloco de conteúdo de imagem com source base64/url/file.
    inference_geoControle de residência de inferência por requisição: global (default) ou us.
    input_examplesExemplos de input válidos para guiar o Claude; não disponível em ferramentas server-side.
    iterPages()Itera páginas inteiras (JS); hasNextPage()/getNextPage() para navegação manual.
    max_retriesRetentativas automáticas (padrão 2) para erros de conexão/408/409/429/≥500.
    max_tokensMáximo de tokens a gerar numa resposta; limitado pelo teto do modelo (Opus 4.8 / Sonnet 4.6: 128k; Haiku 4.5: 64k). Na Batch API, Opus 4.8/4.7/4.6 e Sonnet 4.6 chegam a 300k com o header beta output-300k-2026-03-24.
    maxRetries (JS)Opção do cliente/requisição; padrão 2.
    MCP connectorRecurso que conecta a Messages API a servidores MCP remotos sem cliente MCP separado (beta mcp-client-2025-11-20).
    mcp_toolsetEntrada no array tools que configura quais ferramentas de um servidor MCP habilitar.
    mcpTools / mcpMessagesHelpers que convertem tipos MCP (ferramentas/prompts/recursos) para tipos da Claude API.
    messages.stream()Context manager de streaming com .text_stream e get_final_message() (acumula o Message final).
    messages.stream().on(...)Streaming com event handlers (text, streamEvent, contentBlock, message, finalMessage) + finalMessage().
    ModelInfoMetadados de modelo na Models API: id, display_name, created_at, max_input_tokens, capabilities.
    output_config.formatJSON outputs (structured outputs): força a resposta a seguir um JSON Schema.
    pause_turnMotivo de parada que indica que um turno de ferramenta server-side foi pausado; reenvie a conversa para continuar.
    processing_statusEstado de um Message Batch: in_progress → ended.
    redacted_thinkingBloco de pensamento criptografado por segurança; reenvie sem modificar.
    search_resultBloco de resultado de busca para RAG com citações nativas (source/title/content).
    search_result_locationLocalização de citação que aponta para search_result_index e blocos.
    server_tool_useBloco que aparece quando uma ferramenta server-side roda; id prefixado por srvtoolu_. Não exige tool_result.
    service_tierTier de capacidade: standard, priority ou batch.
    signatureCampo opaco com o pensamento completo criptografado, usado para verificar/reconstruir blocos reenviados.
    sk-ant-admin...Chave da Admin API (gerencia membros, workspaces, chaves).
    snapshot fixoCada model ID mapeia para pesos imutáveis; a partir da 4.6 os IDs são sem data, mas ainda assim pinned (não evergreen).
    speed: "fast"Fast mode (beta): saída até 2,5× mais rápida em Opus 4.8 a 6× o preço; header fast-mode-2026-02-01.
    stop_reasonMotivo do término da geração: end_turn, max_tokens, stop_sequence, tool_use, pause_turn, refusal, model_context_window_exceeded.
    strictPropriedade que força (grammar-constrained sampling) os inputs da ferramenta a casarem com o JSON Schema.
    strict: trueStrict tool use: valida os inputs de uma ferramenta contra seu input_schema via sampling guiado por gramática.
    svac_ / fdis_ / fdrl_Prefixos de service account, federation issuer e federation rule (WIF).
    SyncPage / AsyncPageObjetos de página com auto-paginação (has_next_page, get_next_page, .data, .last_id).
    systemPrompt de sistema — instruções/persona enviadas como campo de topo, não como turno de messages.
    task_budgetTeto de tokens para a tarefa inteira (várias requisições); beta task-budgets-2026-03-13.
    thinkingConfiguração de raciocínio estendido: adaptive (modelo decide), enabled (manual com budget_tokens) ou disabled.
    toFileHelper do SDK JS para criar uploads a partir de ReadStream/Buffer/Uint8Array com content-type explícito.
    tool_choiceControla a escolha de ferramentas: auto, any, tool ou none.
    tool_resultBloco na mensagem do usuário que devolve o resultado de uma ferramenta client-side, casado por tool_use_id. Pode ter is_error: true.
    tool_runnerclient.beta.messages.tool_runner — executa o laço de tool use automaticamente.
    tool_useBloco de conteúdo na resposta do assistente que representa a requisição do Claude para chamar uma ferramenta (com id, name, input). Acompanha stop_reason: "tool_use".
    ToolErrorErro lançável de dentro de uma tool que aceita content blocks (texto/imagem) na resposta de erro.
    toolRunnerclient.beta.messages.toolRunner — executa o laço de tool use automaticamente (JS).
    UsageObjeto de contagem de tokens: input/output, cache_creation/read, server_tool_use, service_tier, inference_geo.
    whsec_Segredo de assinatura de webhook de Managed Agents (header X-Webhook-Signature).
    with_options()Retorna um cliente com overrides por requisição (max_retries, timeout, http_client...).
    with_raw_responseAcessa headers/corpo crus; .parse() devolve o objeto tipado.
    with_streaming_responseLê o corpo sob demanda via context manager (.iter_lines, .read, .json...).
    wrkspc_Prefixo de ID de workspace.
    x-api-keyCabeçalho de autenticação com a chave do Claude Console.
    -
    -
    -

    Histórico deste guia

    -
      -
    • 2026-05-24 — Versão completa, produzida por um time de 4 agentes Claude Opus 4.7 - em paralelo (orquestração + revisão Claude). Parte A (Fundamentos, Modelos, Mensagens, streaming, - stop_reason, structured outputs, effort, contexto, embeddings, batch), Parte B (adaptive/extended - thinking, prompt caching, cache diagnostics, context editing, compaction, visão, PDF, Files, citations), - Parte C (tool use e todas as ferramentas, Agent Skills, MCP) e Parte D (SDKs, referência REST completa, - Message Batches, Models/Files API, Managed Agents, governança/WIF/compliance, Bedrock/Vertex/Foundry). - Apêndice com cookbook, glossário e este histórico.
    • -
    • 2026-05-24 (Parte E + setup) — Adicionada a Parte E — SDK Python - (anthropic), referência exaustiva extraída da página oficial do SDK Python e do - api.md do repositório (clientes sync/async e opções de construtor, streaming, @beta_tool/ - tool_runner, batches, paginação, hierarquia de erros, retries/timeouts, respostas cruas, tipos, - logging, namespace beta e clientes de plataforma). Incluído o bloco Setup em 4 passos e o cookbook - expandido a partir do repositório claude-cookbooks.
    • -
    • 2026-05-24 (Parte F + foco Python/JS) — Adicionada a Parte F — SDK - JavaScript/TypeScript (@anthropic-ai/sdk), referência exaustiva paralela à do Python - (runtimes suportados, opções do cliente, streaming por event handlers, helpers de ferramentas Zod/JSON + - ToolError, helpers de MCP, batches, toFile, paginação, erros, fórmula dinâmica de - timeout, asResponse/withResponse, logging, proxies por runtime, namespace beta, - pacotes de plataforma e dangerouslyAllowBrowser). A tabela de SDKs foi focada em - Python e JavaScript/TypeScript (as demais linguagens oficiais são citadas apenas como referência).
    • -
    • 2026-05-24 (política de modelos) — Restrito aos modelos gerais atuais: - claude-opus-4-7 e claude-sonnet-4-6 (geração 4.6+: o ID puro, sem data, - é o snapshot fixo — não é ponteiro evergreen) e - claude-haiku-4-5 (geração pré-4.6: alias do snapshot datado claude-haiku-4-5-20251001). - Todas as tabelas oficiais que citavam gerações anteriores foram reescritas.
    • -
    • 2026-05-24 (verificação de versionamento) — Corrigida a linha de snapshot da tabela - de modelos: o Opus 4.7 não usa um snapshot datado ...-20251101 (essa data - pertence ao Opus 4.5 legado); na geração 4.6+ o ID dateless é o próprio snapshot canônico. Confirmado em - models/overview e models/model-ids-and-versions.
    • -
    • 2026-06-03 (migração Opus 4.8) — A linha Opus do guia migrou de - claude-opus-4-7 para claude-opus-4-8 (recomendado atual; o 4.7 passou a - Legacy). Specs centrais confirmadas idênticas em models/overview: - 1M de contexto, 128k de saída, adaptive thinking (sem extended), $5/$25 por MTok; no 4.8 o - effort assume high por padrão em todas as superfícies. Créditos de produção e - notas datadas de 2026-05-24 preservados como registro histórico.
    • -
    • 2026-06-10 (varredura de atualização) — Verificação contra a documentação oficial. - Adicionado callout no catálogo de modelos: Claude Fable 5 (claude-fable-5, - GA em 2026-06-09 — $10/$50 por MTok, 1M de contexto, 128k de saída, adaptive thinking sempre ativo, - tokenizer do Opus 4.7, stop_reason "refusal" + fallbacks beta, retenção - obrigatória de 30 dias, cache mínimo de 512 tokens) e Claude Mythos 5 em - disponibilidade limitada; Opus 4.8 segue ativo e recomendado (o guia permanece centrado - nele). Registradas as aposentadorias de Sonnet 4 / Opus 4 (2026-06-15) e Opus 4.1 (2026-08-05) e o campo - usage.output_tokens_details.thinking_tokens (desde 2026-05-27). Corrigido o code execution: - GA sem header beta desde 2026-02-17 (o header legado code-execution-2025-08-25 - segue aceito por compatibilidade) e code_execution_20260120 disponível em - Opus 4.5+ e Sonnet 4.5+ (não Haiku 4.5), conforme a página oficial da ferramenta. - Marcadores de verificação atualizados para 2026-06-10.
    • -
    • 2026-06-11 (delta sweep) — Re-verificação contra os release notes oficiais da API. - Incorporado: stop_details.category ganha o valor "reasoning_extraction" no - Fable 5 (09/06 — bloqueio por engenharia reversa/duplicação de outputs sob os ToS); advisor tool aceita - tools[].max_tokens (02/06); a não-cobrança de refusals sem output gerado é política de toda a - Claude API desde 02/06 (não exclusiva do Fable 5); Managed Agents ganhou scheduled deployments, credenciais - de variável de ambiente em vaults e o campo session_thread_id nos eventos - session.thread_* (09/06).
    • -
    • 2026-06-16 (micro-sweep de versões) — SDKs Anthropic subiram para - 0.109.2 (Python) / 0.104.2 (TS), ambos em 15/06: removem os modelos - aposentados da API e dos SDKs (limpeza da retirada de 15/06). A 0.109.1 (09/06) já - havia adicionado a refusal category frontier_llm. Sem endpoint, parâmetro ou modelo - novo — apenas manutenção.
    • -
    • 2026-06-19 (micro-sweep de versões) — SDKs Anthropic subiram para - 0.111.0 (Python) / 0.105.0 (TS). A 0.110.0 (18/06) adicionou - o suporte tipado ao tool code_execution_20260120 — a capacidade já era - GA e está documentada na §4.5 — além de corrigir o merge de headers x-stainless-helper - e o tipo de evento de stream no Bedrock; a TS 0.105.0 também passou a parsear o JSON - parcial de tool input de forma lazy. A 0.111.0 (18/06) apenas marca requests de - fallback de recusa com fallback-refusal-middleware. Sem endpoint, parâmetro ou modelo - novo — apenas manutenção.
    • -
    • 2026-06-25 (varredura de freshness) — SDK anthropic em - 0.112.0 (Python, 24/06). Correção factual: a saída máxima do - Sonnet 4.6 é 128k (não 64k) na Messages API — alinhado a - models/overview; também documentado o teto de 300k na Batch API via header - output-300k-2026-03-24. O Claude Fable 5 segue GA (09/06) porém - indisponível no momento (confirmar status atual). Sem endpoint, parâmetro ou - modelo novo.
    • -
    • 2026-06-29 (varredura de freshness — changelogs oficiais reverificados) — SDK - anthropic 0.113.0 (Python, 29/06; adiciona web fetch/support tools - 20260318) e @anthropic-ai/sdk 0.107.0 (Node). Sampling - depreciado: temperature/top_p/top_k retornam 400 - com valor não-default em Opus 4.7/4.8 e Fable 5. Tokenizer novo (~30% mais tokens) em - Opus 4.7+/Fable 5. Depreciações de modelo: Opus 4.1 (claude-opus-4-1-20250805) - deprecado 05/06, retirement 05/08/2026 → Opus 4.8; Sonnet 4 e Opus 4 - (*-20250514) já retired em 15/06/2026; fast mode do Opus 4.7 removido - em 24/07/2026. Confirmado: Fable 5 = GA porém temporariamente indisponível para - usuários regulares; Sonnet 4.6 = 128k e Haiku 4.5 = 64k de saída máxima. Fonte: - platform.claude.com/docs/.../model-deprecations.
    • -
    • 2026-07-05 (varredura de freshness) — Claude Sonnet 5 - (claude-sonnet-5) lançado em GA em 2026-06-30: passa a ser o Sonnet - recomendado e default de Free/Pro no claude.ai; 1M ctx, 128k saída, adaptive thinking ligado por - padrão, effort nos 5 níveis (low…max), tokenizer novo, cutoff Jan 2026. Preço intro - $2/$10 por MTok até 31/08/2026, depois $3/$15. O - Sonnet 4.6 foi rebaixado a "Legacy" na doc oficial (ainda suportado). Fable 5: - após suspensão global por controles de exportação dos EUA (12–30/06), foi reimplantado a partir - de 01/07/2026 com classificador de segurança reforçado (fallback automático p/ Opus 4.8) — model - ID/preço/specs inalterados; portanto o "indisponível" das entradas anteriores está resolvido. - SDKs: anthropic 0.116.0 (Python, 02/07) e @anthropic-ai/sdk - 0.110.0 (Node, 02/07 — 0.108.0 adicionou suporte a claude-sonnet-5; 0.109.0 - trouxe Managed Agents com streaming de eventos/overrides/webhooks; 0.110.0 introduziu o beta header - agent-memory-2026-07-22). Fonte: anthropic.com/news/claude-sonnet-5, - anthropic.com/news/redeploying-fable-5, PyPI e GitHub releases.
    • -
    -

    Fontes primárias: platform.claude.com/docs - (export llms-full.txt) e github.com/anthropics/anthropic-cookbook. - Verificado em 2026-07-05 — para fatos perecíveis (modelos, datas, preços, limites, headers beta), - consulte sempre a fonte oficial.

    -
    -
    -
    - -
    -
    -
    -
    Guia Claude API Anthropic · PT-BR
    -

    - Referência técnica construída a partir da documentação oficial pública em - 2026-06-11 (versões de SDK reconferidas em 2026-06-19). Para informações sempre atualizadas, consulte - platform.claude.com/docs. - Para fatos perecíveis (modelos, datas, preços, limites), a documentação oficial é a fonte autoritativa. -

    -
    -
    -
    Crédito de produção
    -
    Produzido por um time de 4 agentes Claude Opus 4.7
    -
    em paralelo · orquestração + revisão Claude · 2026-05-24
    -
    - anthropic - PT-BR - SOTA -
    -
    -
    -
    Navegação rápida
    - - - - -
    -
    -
    - - - - + + + + + +Guia Claude API (Anthropic) — Referência completa · Opus 4.8 · Sonnet 5 · Haiku 4.5 + + + + + + + + +
    +
    +
    Guia Claude API Anthropic · PT-BR · Referência completa
    +
    + Verificado em 2026-07-12 + anthropic · @anthropic-ai/sdk + Opus 4.8 · Sonnet 5 · Haiku 4.5 + +
    +
    +
    + +
    + + +
    + +
    +

    Guia Claude API (Anthropic) — Referência completa

    +

    + Documentação técnica exaustiva, em português brasileiro, da API da Anthropic (Claude), + focada nos modelos gerais mais recentes — Claude Opus 4.8, Claude Sonnet 5 + e Claude Haiku 4.5 (com Sonnet 4.6 como legado ainda suportado). Cobre a Messages API, streaming (SSE), raciocínio + (adaptive & extended thinking), tool use (todas as ferramentas client- e server-side), + multimodal (visão, PDF, Files), prompt caching, context editing, batch, structured outputs, + citations, embeddings, Agent Skills, MCP, Managed Agents, a referência REST/SDK completa, + governança (Admin, WIF, rate limits, compliance) e execução nas plataformas de nuvem + (Amazon Bedrock, Google Vertex AI, Microsoft Foundry). +

    +
    + anthropic · Python ≥ 3.9 + @anthropic-ai/sdk · Node ≥ 20 + Opus 4.8 · Sonnet 5 · Haiku 4.5 + anthropic-version: 2023-06-01 + Verificado em 2026-07-12 +
    +
    + +
    +

    Sobre este guia

    +

    + Este é um guia técnico exaustivo, em português brasileiro, da API da Anthropic — + a interface para construir aplicações sobre os modelos Claude. O guia é deliberadamente restrito + aos modelos gerais mais recentes (Opus 4.8, Sonnet 5 e Haiku 4.5; Sonnet 4.6 consta como legado); modelos de + gerações anteriores foram omitidos por design. Para fatos perecíveis — IDs de modelo, preços, + limites, datas e headers beta — a documentação oficial em platform.claude.com é + sempre a fonte autoritativa. +

    +

    O conteúdo está organizado em seis partes e um apêndice:

    +
      +
    • Parte A — Fundamentos, Modelos & Mensagens: primeira chamada, autenticação, + SDKs, a tabela de modelos, a Messages API, streaming, stop_reason, structured outputs, + effort, janelas de contexto, embeddings e batch.
    • +
    • Parte B — Raciocínio, Caching, Contexto & Multimodal: adaptive e extended thinking, + prompt caching, context editing, compaction, visão, PDF, Files, citations e search results.
    • +
    • Parte C — Ferramentas, Skills & MCP: tool use ponta a ponta, todas as ferramentas + (bash, computer use, code execution, text editor, memory, web search/fetch, tool search), + recursos avançados, Agent Skills e Model Context Protocol (MCP).
    • +
    • Parte D — Referência REST/SDK, Agentes Gerenciados, Governança & Nuvem: + SDKs oficiais, o schema REST completo, Message Batches, Models/Files API, Managed Agents, + Admin/Compliance/WIF e execução em Bedrock/Vertex/Foundry.
    • +
    • Parte E — SDK Python (anthropic) em profundidade: clientes + síncrono/assíncrono e todas as opções de construtor, streaming, ferramentas como funções + (@beta_tool/tool_runner), batches, paginação, hierarquia de erros, + retries/timeouts, respostas cruas, tipos, logging, namespace beta e clientes de plataforma.
    • +
    • Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk) em profundidade: + runtimes suportados (Node, Deno, Bun, Workers, navegador), opções do cliente, streaming por + event handlers, helpers de ferramentas (Zod/JSON + ToolError) e de MCP, batches, + toFile, paginação, erros, retries/timeouts, respostas cruas, logging, proxies, namespace + beta e pacotes de plataforma.
    • +
    • Apêndice: cookbook (notebooks oficiais), glossário e histórico do guia.
    • +
    +
    + Como ler: cada capítulo expõe Python (anthropic), TypeScript + (@anthropic-ai/sdk) e REST/cURL em paralelo, preservando os exemplos oficiais. + Use o botão Tema no topo para alternar claro/escuro; o sumário à esquerda acompanha sua leitura. +
    +
    + Legível por humanos e por IA: o documento é um único HTML autossuficiente, com + âncoras estáveis por seção, tabelas semânticas e blocos de código rotulados por linguagem, + para ser facilmente indexado, citado e consumido por assistentes. +
    + +
    + Escopo e cobertura — o que é exaustivo vs. resumido (explícito): +
      +
    • Cobertura exaustiva: a Messages API e todos os recursos da API + (streaming, adaptive/extended thinking, prompt caching, context editing, multimodal, citations, + structured outputs, batch, embeddings, tool use e todas as ferramentas, Agent Skills, MCP), + mais o SDK Python (anthropic) e o + SDK JavaScript/TypeScript (@anthropic-ai/sdk) em profundidade — + tudo restrito aos modelos atuais (Opus 4.8, Sonnet 5, Haiku 4.5; Sonnet 4.6 legado).
    • +
    • Resumido (não detalhado página a página, com link canônico para aprofundar): + as subpáginas individuais de Managed Agents (cobertas em nível de + visão geral e superfície REST/governança, não uma a uma — veja a lista completa em + Fontes oficiais) e a integração legada do Amazon Bedrock + (InvokeModel/Converse; este guia foca a integração atual via Messages API) — + ver claude-on-amazon-bedrock-legacy.
    • +
    • Apenas referência (citados, não detalhados): os SDKs oficiais de + Java, Go, C#, Ruby e PHP — o foco deste guia é Python e JS/TS.
    • +
    • Fatos perecíveis: IDs de modelo, preços, limites e headers beta foram verificados + em 2026-06-10 contra platform.claude.com; para qualquer um deles a + documentação oficial ao vivo é sempre a fonte autoritativa.
    • +
    +
    +
    + +
    +

    TL;DR · Cartão de referência rápida

    + +

    Setup em 4 passos (do zero à primeira resposta)

    +
      +
    1. Obtenha uma chave de API: crie/entre numa conta e gere uma chave em + platform.claude.com/settings/keys + (Claude Console). Garanta que há crédito/billing ativo na organização.
    2. +
    3. Exporte a chave como variável de ambiente (os SDKs a leem automaticamente): +
      export ANTHROPIC_API_KEY="sua-chave-aqui" (Linux/macOS) · + setx ANTHROPIC_API_KEY "sua-chave-aqui" (Windows).
    4. +
    5. Instale o SDK: pip install anthropic (Python ≥ 3.9) ou + npm install @anthropic-ai/sdk (Node ≥ 20).
    6. +
    7. Faça a primeira chamada (código abaixo) e siga para + escolher o modelo e o SDK em profundidade: + Python ou JavaScript/TypeScript.
    8. +
    + +

    Referência rápida dos valores essenciais:

    +
    + + + + + + + + + + + +
    ItemValor
    Base URLhttps://api.anthropic.com
    Endpoint principalPOST /v1/messages
    AutenticaçãoHeader x-api-key: $ANTHROPIC_API_KEY
    Versão da APIHeader anthropic-version: 2023-06-01 (obrigatório)
    Features betaHeader anthropic-beta: <flag> (quando aplicável)
    SDK Pythonpip install anthropic · anthropic.Anthropic()
    SDK TypeScriptnpm install @anthropic-ai/sdk · new Anthropic()
    +
    +

    Modelos gerais atuais (detalhes e preços em A3. Modelos Claude):

    +
    + + + + + + + + +
    ModeloID de APIContextoSaída máx.RaciocínioMelhor para
    Claude Opus 4.8claude-opus-4-81M tokens128KAdaptive thinking + effortTarefas complexas, coding, agentes
    Claude Sonnet 5 recomendadoclaude-sonnet-51M tokens128KAdaptive thinking + effortEquilíbrio capacidade/custo (Sonnet atual)
    Claude Sonnet 4.6 Legacyclaude-sonnet-4-61M tokens128KeffortGeração Sonnet anterior (suportada)
    Claude Haiku 4.5claude-haiku-4-5200K tokens64KExtended thinkingBaixa latência e custo
    +
    +
    +
    + + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()  # lê ANTHROPIC_API_KEY do ambiente
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude!"}],
    +)
    +print(message.content[0].text)
    +
    +
    +
    import Anthropic from '@anthropic-ai/sdk';
    +
    +const client = new Anthropic(); // lê ANTHROPIC_API_KEY do ambiente
    +const message = await client.messages.create({
    +  model: 'claude-opus-4-8',
    +  max_tokens: 1024,
    +  messages: [{ role: 'user', content: 'Olá, Claude!' }],
    +});
    +console.log(message.content[0].text);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{"role": "user", "content": "Olá, Claude!"}]
    +  }'
    +
    +
    +
    + Política de modelos deste guia: citamos apenas os modelos gerais mais recentes + (Opus 4.8, Sonnet 5, Haiku 4.5), mantendo o Sonnet 4.6 como legado ainda suportado. Gerações anteriores foram intencionalmente omitidas. +
    +
    + +
    +

    Fontes oficiais

    +

    Este guia foi construído a partir da documentação oficial pública da Anthropic em + platform.claude.com/docs (verificada em 2026-06-10), do export + llms-full.txt e do repositório oficial de cookbooks. Sempre que houver divergência + entre este guia e a documentação em produção, a documentação oficial é a fonte autoritativa. + As 115 páginas oficiais consultadas:

    + + +
    + + + +
    +

    Parte A — Fundamentos, Modelos & API de Mensagens

    +

    Esta parte cobre o essencial para começar com a API da Anthropic: visão geral da plataforma, primeira chamada e autenticação, SDKs, a tabela definitiva dos modelos atuais (Claude Opus 4.8, Sonnet 4.6 e Haiku 4.5), a anatomia da API de Mensagens, geração de texto e streaming (SSE), o campo stop_reason, structured outputs, o parâmetro effort, fast mode, janelas de contexto e contagem de tokens, embeddings, suporte multilíngue e o processamento em lote (Message Batches API).

    +
    + + +
    +

    1. Visão geral da plataforma Claude & primeira chamada

    +

    Claude é a família de modelos de linguagem da Anthropic, com desempenho de ponta em linguagem, raciocínio, análise e coding. Há duas formas de construir com Claude, cada uma para um caso de uso diferente:

    + +
    + + + + + +
     Messages APIClaude Managed Agents
    O que éAcesso direto de prompting ao modeloHarness de agente pré-construído e configurável, executado em infraestrutura gerenciada
    Melhor paraLoops de agente customizados e controle finoTarefas de longa duração e trabalho assíncrono
    + +

    O caminho recomendado para um desenvolvedor novo é: (1) fazer a primeira chamada à API, (2) entender a Messages API, (3) escolher o modelo certo (ver seção 3), e (4) explorar ferramentas e recursos avançados.

    + +

    Autenticação e primeira chamada

    +

    A autenticação usa um cabeçalho x-api-key com sua chave do Claude Console, e todo request exige o cabeçalho de versão anthropic-version: 2023-06-01. A URL base é https://api.anthropic.com e o endpoint principal é POST /v1/messages.

    + +
    Dica: exporte a chave como variável de ambiente — export ANTHROPIC_API_KEY='sua-chave-aqui' — e adicione a linha ao seu perfil de shell (~/.zshrc ou ~/.bashrc) para persistir entre sessões. Os SDKs leem essa variável automaticamente.
    + +
    +
    + + + +
    +
    +
    import anthropic
    +
    +# Lê ANTHROPIC_API_KEY do ambiente automaticamente
    +client = anthropic.Anthropic()
    +
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1000,
    +    messages=[
    +        {
    +            "role": "user",
    +            "content": "O que devo pesquisar para achar avanços recentes em energia renovável?",
    +        }
    +    ],
    +)
    +print(message.content[0].text)
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic();
    +
    +const message = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1000,
    +  messages: [
    +    {
    +      role: "user",
    +      content: "O que devo pesquisar para achar avanços recentes em energia renovável?",
    +    },
    +  ],
    +});
    +console.log(message.content);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1000,
    +    "messages": [
    +      {"role": "user", "content": "O que devo pesquisar para achar avanços recentes em energia renovável?"}
    +    ]
    +  }'
    +
    +
    + +

    A resposta é um objeto message com id, role: "assistant", um array content de blocos (aqui um bloco text), o model usado, o stop_reason (ver seção 6) e o objeto usage com input_tokens / output_tokens:

    + +
    Resposta JSON (200) +
    {
    +  "id": "msg_01HCDu5LRGeP2o7s2xGmxyx8",
    +  "type": "message",
    +  "role": "assistant",
    +  "content": [
    +    { "type": "text", "text": "Aqui estão estratégias de busca eficazes..." }
    +  ],
    +  "model": "claude-opus-4-8",
    +  "stop_reason": "end_turn",
    +  "stop_sequence": null,
    +  "usage": { "input_tokens": 21, "output_tokens": 305 }
    +}
    +
    + + +
    + + +
    +

    2. SDKs & instalação (visão rápida)

    +

    A Anthropic mantém SDKs oficiais em Python, TypeScript, Java, Go, Ruby, C# e PHP, além de uma CLI (ant). Esta seção cobre o mínimo para rodar; a referência completa de SDKs está na Parte D.

    + +
    + + + + + + +
    LinguagemPacoteInstalaçãoVersão mínima
    Pythonanthropicpip install anthropicPython 3.9+
    TypeScript@anthropic-ai/sdknpm install @anthropic-ai/sdkTS 4.9+ / Node 20+
    CLIantbrew install anthropics/tap/ant—
    + +

    Em Python o cliente é anthropic.Anthropic() (síncrono) ou anthropic.AsyncAnthropic() (assíncrono). Em TypeScript é new Anthropic(). Ambos leem ANTHROPIC_API_KEY do ambiente; alternativamente passe api_key=... / { apiKey: ... } no construtor. Recursos beta são acessados pelo namespace beta (ex.: client.beta.messages.create(..., betas=["nome-da-feature"])).

    + +
    Nota: os SDKs oferecem retries e tratamento de timeouts embutidos. Para max_tokens altos, prefira o modo streaming (ver seção 5) para evitar timeouts de HTTP.
    + + +
    + + +
    +

    3. Modelos Claude (Opus 4.8 · Sonnet 5 · Haiku 4.5)

    +

    Esta é a seção canônica de modelos do guia — as demais partes a referenciam. A geração atual de uso geral é Opus 4.8, Sonnet 5 e Haiku 4.5. Use apenas estes IDs em código novo; claude-sonnet-4-6 passou a Legacy (ainda funcional e suportado) com a chegada do Sonnet 5.

    + +
    Novo (2026-06-30): Claude Sonnet 5. A Anthropic lançou Claude Sonnet 5 (claude-sonnet-5) em GA em 2026-06-30. Ele substitui o Sonnet 4.6 como o modelo Sonnet recomendado e é o default para os planos Free/Pro no claude.ai; disponível também em Claude API, Claude Code, Amazon Bedrock, Vertex AI e Microsoft Foundry. Contexto de 1M tokens, saída máxima de 128k, adaptive thinking ligado por padrão (thinking.type:"adaptive" é o default; enabled manual retorna 400 — para desligar use thinking:{"type":"disabled"}), suporta os 5 níveis de effort (low·medium·high·xhigh·max) — inclusive max, o nível mais alto (xhigh não é o teto). Usa o tokenizer novo (geração pós-4.7). Cutoff confiável Jan 2026. Na doc oficial, o Sonnet 4.6 foi movido para "Legacy models" (segue suportado). news/claude-sonnet-5 · models/overview
    + +
    Checklist de migração claude-sonnet-4-6 → claude-sonnet-5 (trocar o ID não é drop-in — há mudanças de comportamento que falham/silenciam sem aviso): +
      +
    1. Thinking manual quebra: thinking:{type:"enabled", budget_tokens:N} retorna 400 no Sonnet 5. Troque por thinking:{type:"adaptive"} + output_config.effort (ou {type:"disabled"}).
    2. +
    3. Sampling params quebram: temperature/top_p/top_k não-default retornam 400 (em toda requisição). Remova-os e controle variedade por prompting.
    4. +
    5. Raciocínio some da UI (silencioso): thinking.display passa a "omitted" por padrão — se sua UI mostra o raciocínio, defina display:"summarized" explicitamente.
    6. +
    7. Tokenizer novo (~30% mais tokens): revise/aumente max_tokens para não truncar (stop_reason:"max_tokens"), sobretudo em high/xhigh/max.
    8. +
    9. Recalibre effort: Sonnet 5 em medium ≈ Sonnet 4.6 em high — geralmente dá para baixar um nível e economizar.
    10. +
    11. Custo: preço intro $2/$10 até 31/08/2026 (depois $3/$15) — re-baseie projeções considerando a data-limite e o tokenizer.
    12. +
    +
    + +

    Tabela comparativa

    +
    + + + + + + + + + + + + + + + + +
    CaracterísticaClaude Opus 4.8Claude Sonnet 5Claude Sonnet 4.6 LegacyClaude Haiku 4.5
    DescriçãoO modelo GA mais capaz, para raciocínio complexo e coding agênticoA melhor combinação de velocidade e inteligência (Sonnet recomendado)Geração Sonnet anterior — legada, ainda suportadaO modelo mais rápido, com inteligência quase de fronteira
    ID de APIclaude-opus-4-8claude-sonnet-5claude-sonnet-4-6claude-haiku-4-5
    Snapshot fixoclaude-opus-4-8 o ID puro já é o snapshot (geração 4.6+)claude-sonnet-5 o ID puro já é o snapshotclaude-sonnet-4-6 o ID puro já é o snapshot (geração 4.6+)claude-haiku-4-5-20251001 alias: claude-haiku-4-5
    Janela de contexto1M tokens1M tokens1M tokens200k tokens
    Máx. de saída (Messages API)128k tokens128k tokens128k tokens64k tokens
    ModalidadesTexto + imagem → texto; PDFTexto + imagem → texto; PDFTexto + imagem → texto; PDFTexto + imagem → texto; PDF
    Adaptive thinkingSim (modo recomendado)Sim (default ligado)SimNão
    Extended thinking (manual)NãoNãoSimSim
    effortlow·medium·high·xhigh·maxlow·medium·high·xhigh·maxlow·medium·high·maxNão suportado
    Latência comparativaModeradaRápidaRápidaA mais rápida
    Knowledge cutoff (confiável)Jan 2026Jan 2026Ago 2025Fev 2025
    + +
    + IDs dateless são snapshots fixos (geração 4.6+). A partir da geração 4.6, o ID + sem data — claude-opus-4-8, claude-sonnet-4-6 — é o snapshot + canônico e imutável: ele mapeia para um único conjunto de pesos fixos e não é um + ponteiro evergreen. Uma versão atualizada sempre sai sob um ID novo. Modelos de gerações anteriores + (como o Haiku 4.5) trazem a data no ID — claude-haiku-4-5-20251001 — e + expõem um alias curto (claude-haiku-4-5) que resolve para o snapshot datado mais recente + daquela versão menor. Os pesos são fixos por ID, mas a infraestrutura de serviço (roteador, classificadores, + sampling) pode evoluir e causar diferenças mínimas de comportamento. + model-ids-and-versions +
    + +

    Preços por MTok (milhão de tokens, USD)

    +

    Todos os preços abaixo são da API de primeira parte (Claude API), em rota global (padrão). A janela completa de 1M tokens (Opus 4.8, Sonnet 5 e Sonnet 4.6) é cobrada na mesma taxa por token em todo o contexto — um request de 900k tokens custa por token o mesmo que um de 9k.

    +
    + + + + + + + + + +
    ModeloEntradaSaídaCache write 5mCache write 1hCache hit (leitura)
    Claude Opus 4.8$5$25$6.25$10$0.50
    Claude Sonnet 5 intro$2 → $3$10 → $15$2.50$4$0.20
    Claude Sonnet 4.6 Legacy$3$15$3.75$6$0.30
    Claude Haiku 4.5$1$5$1.25$2$0.10
    +
    Sonnet 5 — preço introdutório. Até 2026-08-31, o claude-sonnet-5 tem preço promocional de $2 / $10 por MTok (entrada/saída); a partir de 2026-09-01 passa ao preço padrão de $3 / $15 (mesma faixa do Sonnet 4.6). As colunas de cache acima usam o preço padrão como base ($3 de entrada). Confirme sempre em pricing antes de projetar custo. pricing
    +

    O cache write de 5 minutos custa 1,25× o preço de entrada base; o de 1 hora custa 2×; a leitura de cache (hit) custa 0,1× (10%) do preço de entrada. Pela Batch API os tokens saem com 50% de desconto (ver seção 12):

    +
    + + + + + + + +
    ModeloBatch entradaBatch saída
    Claude Opus 4.8$2.50$12.50
    Claude Sonnet 5 (preço padrão)$1.50$7.50
    Claude Sonnet 4.6 Legacy$1.50$7.50
    Claude Haiku 4.5$0.50$2.50
    + +
    Atenção (tokenizer): Opus 4.7, Opus 4.8, Sonnet 5 e Fable 5 usam um tokenizer novo em relação a gerações anteriores (Opus 4.6 e Sonnet 4.6 mantêm o antigo), o que contribui para o desempenho — mas produz mais tokens para o mesmo texto (~1,0–1,35× conforme o texto; da ordem de ~30% a mais nos piores casos). Recalibre max_tokens e re-baseie estimativas de custo ao migrar (inclusive ao trocar Sonnet 4.6 → Sonnet 5); a API de token counting aceita model:"claude-sonnet-5" ou model:"claude-fable-5" para medir com o novo tokenizer.
    + +
    Opus 4.8 — atual e recomendado (verificado 2026-06-03): o claude-opus-4-8 é o Opus atual e sucessor direto do 4.7 (agora Legacy). As specs centrais são idênticas às do 4.7 (confirmado em models/overview): janela de 1M tokens, saída de 128k, adaptive thinking (sem extended), preço $5 / $25 por MTok. Diferença de comportamento: no 4.8 o effort assume high por padrão em todas as superfícies (Claude API e Claude Code) — defina-o explicitamente para usar outro nível. O suporte a ferramentas e headers beta (computer use, code execution, web fetch, fast mode, inference_geo) é herdado da superfície do 4.7; para betas de borda, confirme sempre na documentação oficial.
    + +
    Atualização 2026-07-05: a Anthropic lançou o Claude Fable 5 (claude-fable-5, GA em 2026-06-09) — o modelo mais capaz amplamente lançado da Anthropic: $10 / $50 por MTok, contexto de 1M tokens, saída máxima de 128k e adaptive thinking sempre ativo — thinking: {"type": "disabled"}, budget manual (enabled + budget_tokens) e prefill do turno assistant retornam 400; thinking.display assume "omitted" por padrão. Usa o tokenizer do Opus 4.7 (~30% mais tokens que gerações pré-4.7 para o mesmo texto), traz classificadores de segurança com stop_reason: "refusal" (sem cobrança se nada for gerado — política de toda a Claude API desde 02/06/2026, não exclusiva do Fable 5) e o parâmetro fallbacks Beta, exige retenção de 30 dias (não elegível a ZDR) e tem cache mínimo de 512 tokens. Disponibilidade: o Fable 5 (e o Mythos 5) ficaram suspensos globalmente entre 12/06 e 30/06/2026 por controles de exportação dos EUA; a exigência de licença foi retirada em 30/06 e o modelo foi reimplantado ("redeployed") a partir de 01/07/2026 com um classificador de segurança reforçado (requests bloqueados são redirecionados automaticamente para o Opus 4.8). Model ID, preço e specs permanecem os mesmos — confirme o status atual em models/overview. O Claude Mythos 5 (claude-mythos-5) está em disponibilidade limitada. O Opus 4.8 segue ativo e recomendado como o modelo mais capaz; o Sonnet 5 (GA 2026-06-30) é agora o Sonnet recomendado (ver callout acima), com Sonnet 4.6 rebaixado a Legacy e Haiku 4.5 para baixa latência. Deprecações: Sonnet 4 e Opus 4 aposentam em 2026-06-15; Opus 4.1 (anúncio de 2026-06-05) aposenta em 2026-08-05. Desde 2026-05-27, a API reporta usage.output_tokens_details.thinking_tokens no message_delta final. + models/overview · redeploying-fable-5 · model-deprecations +
    + +

    Fable 5 e Mythos 5 no comparativo

    +

    O Claude Fable 5 (claude-fable-5) é, segundo a doc oficial, "Anthropic's most capable widely released model" — a célula de descrição da tabela o classifica como "Next-generation intelligence for long-running agents". Entrou em GA em 09/06/2026. O Claude Mythos 5 (claude-mythos-5) "shares Claude Fable 5's specs and pricing", mas não traz os classificadores de segurança do Fable 5; é o sucessor do claude-mythos-preview e só é acessível por convite dentro do Project Glasswing (fluxos defensivos de cibersegurança). A tabela abaixo estende a tabela-mestra da seção 3 com essas duas colunas — o Sonnet 4.6 Legacy segue na tabela principal e na lista de modelos legados.

    + +
    + + + + + + + + + + + + + + + + + +
    CaracterísticaClaude Fable 5Claude Mythos 5 Convite (Glasswing)Claude Opus 4.8Claude Sonnet 5Claude Haiku 4.5
    DescriçãoInteligência de nova geração para agentes de longa duraçãoMesmas specs/preço do Fable 5, sem os classificadores de segurança; dedicado a fluxos defensivos de cibersegurançaPara raciocínio complexo e coding agêntico de nível enterpriseMelhor combinação de velocidade e inteligência (Sonnet recomendado)O modelo mais rápido, com inteligência quase de fronteira
    ID / alias de APIclaude-fable-5claude-mythos-5 sucessor do claude-mythos-previewclaude-opus-4-8claude-sonnet-5ID claude-haiku-4-5-20251001 · alias claude-haiku-4-5
    AWS Bedrock IDanthropic.claude-fable-5Glasswinganthropic.claude-opus-4-8anthropic.claude-sonnet-5anthropic.claude-haiku-4-5-20251001-v1:0
    Google Cloud IDclaude-fable-5Glasswingclaude-opus-4-8claude-sonnet-5claude-haiku-4-5@20251001
    DisponibilidadeGA 09/06/2026 — Claude API, Claude Platform on AWS, Amazon Bedrock, Google Cloud, Microsoft FoundryLimitada — Project Glasswing, apenas clientes aprovados; contato via time de conta Anthropic/AWS/Google Cloud, sem self-serveGAGAGA
    Janela de contexto1M tokens1M tokens1M tokens1M tokens200k tokens
    Máx. de saída (Messages API)128k tokens128k tokens128k tokens128k tokens64k tokens
    Preço (entrada / saída, MTok)$10 / $50$10 / $50 = Fable 5$5 / $25$3 / $15 intro $2/$10$1 / $5
    Extended thinking (manual)NãoNãoNãoNãoSim
    Adaptive thinkingSim (sempre ativo)Sim (sempre ativo)SimSim (default ligado)Não
    Latência comparativaMais lenta (Slower)Mais lenta (Slower)ModeradaRápidaA mais rápida
    Knowledge cutoff (confiável)Jan 2026Jan 2026Jan 2026Jan 2026Fev 2025
    + +
    Adaptive thinking sempre ativo — não dá para desligar nem passar budget manual. No Fable 5 e no Mythos 5 o adaptive thinking é o único modo (aplica-se sempre que o parâmetro thinking fica unset). A doc é explícita: thinking:{"type":"disabled"} não é suportado, e o modo manual thinking:{"type":"enabled", budget_tokens:N} é rejeitado com 400 (o mesmo vale para Sonnet 5, Opus 4.8 e Opus 4.7). Para regular a profundidade do raciocínio, use o parâmetro effort (low·medium·high·xhigh·max; default high). Ainda: nesses modelos, valores não-default de temperature, top_p e top_k também retornam 400 em toda requisição — controle variedade por prompting. E thinking.display assume "omitted" por padrão: defina "summarized" se sua UI mostra o raciocínio.
    + +
    Exemplo — confirmar limites via Models API antes de rotear para o Fable 5:
    +
    +
    + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +
    +# Confirma em runtime que o ID existe e lê os limites atuais
    +# (max_input_tokens, max_tokens) em vez de hard-codar 1_000_000 / 128_000.
    +model = client.models.retrieve("claude-fable-5")
    +print(model.id, model.max_input_tokens, model.max_tokens)
    +
    +resp = client.messages.create(
    +    model="claude-fable-5",
    +    max_tokens=8192,
    +    # Fable 5 usa adaptive thinking SEMPRE ativo:
    +    #   - omita 'thinking' (adaptive é o default), ou
    +    #   - passe thinking={"type": "adaptive"};
    +    # thinking={"type": "disabled"} não é suportado e
    +    # thinking={"type": "enabled", ...} retorna 400.
    +    # Regule a profundidade pelo effort (default 'high').
    +    output_config={"effort": "high"},
    +    messages=[{"role": "user", "content": "Resuma os riscos do plano X."}],
    +)
    +print(resp.content)
    +
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic();
    +
    +// Confirma o ID e lê os limites atuais em runtime.
    +const model = await client.models.retrieve("claude-fable-5");
    +console.log(model.id, model.max_input_tokens, model.max_tokens);
    +
    +const resp = await client.messages.create({
    +  model: "claude-fable-5",
    +  max_tokens: 8192,
    +  // Adaptive thinking é sempre ativo no Fable 5: omita 'thinking'
    +  // ou use { type: "adaptive" }. 'disabled' não é suportado e
    +  // { type: "enabled", ... } retorna 400. Regule pelo effort.
    +  output_config: { effort: "high" },
    +  messages: [{ role: "user", content: "Resuma os riscos do plano X." }],
    +});
    +console.log(resp.content);
    +
    +
    +
    + +
    Quando considerar Fable 5 / Mythos 5 em vez de Opus 4.8. A doc oficial recomenda começar com Opus 4.8 para coding agêntico complexo e trabalho enterprise; use Fable 5 apenas quando a carga exigir a maior capacidade disponível em agentes de longa duração — lembrando que o custo por MTok é 2× o do Opus 4.8 (entrada e saída) e a latência é a mais alta do catálogo ativo (Slower). O Mythos 5 não é auto-atendimento: restrito ao Project Glasswing (fluxos defensivos de cibersegurança), exige aprovação prévia e é solicitado pelo time de conta Anthropic, AWS ou Google Cloud — não tente usar claude-mythos-5 em produção sem essa aprovação. Fable 5 e Mythos 5 carregam retenção de 30 dias e não são elegíveis a ZDR (ambos são Covered Models); o comportamento de refusals/fallbacks/billing do Fable 5 está detalhado no callout de atualização acima.
    + + + +

    Quando usar cada modelo

    +
      +
    • Opus 4.8 — tarefas complexas, raciocínio profundo e coding agêntico de longo horizonte. Comece com effort: "xhigh" para coding/agentes; é o padrão recomendado para os casos mais difíceis.
    • +
    • Sonnet 5 recomendado — equilíbrio de velocidade, custo e inteligência para a maioria das cargas de produção (coding, agentes, fluxos enterprise); é o Sonnet atual e sucessor do 4.6. Adaptive thinking vem ligado por padrão; defina effort explicitamente (todos os 5 níveis, low…max) conforme o trade-off latência/qualidade. Ao migrar do 4.6, recalibre o effort: segundo a Anthropic, Sonnet 5 em medium ≈ Sonnet 4.6 em high, e Sonnet 5 em high ≈ Sonnet 4.6 em max — ou seja, você pode baixar um nível e manter qualidade equivalente, reduzindo custo/latência.
    • +
    • Sonnet 4.6 Legacy — geração Sonnet anterior, ainda funcional e suportada; prefira o Sonnet 5 em código novo. Migração é trocar o ID (claude-sonnet-4-6 → claude-sonnet-5) — reveja max_tokens por causa do tokenizer novo e note que thinking.display passa a "omitted" por padrão no Sonnet 5.
    • +
    • Haiku 4.5 — baixa latência e baixo custo: classificação, lookups rápidos, subagentes e volumes altos onde ganhos marginais de qualidade não compensam latência/custo.
    • +
    + +

    Aliases vs. snapshots & política de deprecação

    +

    Todo ID de modelo identifica um snapshot fixo: enquanto o ID existir, os pesos não mudam. A partir da geração 4.6 os IDs adotam um formato sem data (claude-{nome}-{maior}-{menor}, ex.: claude-sonnet-4-6, claude-opus-4-8) que ainda assim é um snapshot fixo — não um ponteiro "evergreen". Quando há uma versão atualizada, ela é lançada sob um novo ID.

    +
    Nota: em modelos anteriores à 4.6, IDs incluíam a data (claude-haiku-4-5-20251001) e havia aliases de conveniência (ex.: claude-haiku-4-5) que apontavam para o snapshot datado mais recente. Para 4.6+, o ID sem data é o snapshot — não é um alias. Por isso, na tabela acima, Sonnet 4.6 não tem ID datado separado.
    +

    Os pesos do modelo são fixos por ID, mas a infraestrutura de serviço (roteador, classificadores de segurança, lógica de sampling) pode mudar; isso ocasionalmente produz pequenas diferenças observáveis mesmo com ID e pesos inalterados. Cada ID tem seu próprio cronograma de deprecação e retirada — consulte a página de model deprecations antes de migrar.

    + + +
    + + +
    +

    3.1 Endpoint Models API (descoberta programática)

    +

    A Models API permite listar os modelos disponíveis e resolver um alias para um ID, retornando limites e capacidades de cada modelo. É útil para roteamento dinâmico e para descobrir features suportadas em runtime, sem hard-coding.

    + +
    + + + + + +
    OperaçãoMétodo / rotaDescrição
    List ModelsGET /v1/modelsLista modelos (mais recentes primeiro). Paginação por after_id/before_id, limit 1–1000 (padrão 20).
    Get a ModelGET /v1/models/{model_id}Retorna info de um modelo específico; aceita ID ou alias.
    + +

    Cada item (ModelInfo) traz: id, display_name, created_at (RFC 3339), type: "model", e os campos-chave para roteamento:

    +
      +
    • max_input_tokens — tamanho máximo da janela de contexto de entrada.
    • +
    • max_tokens — valor máximo do parâmetro max_tokens para esse modelo.
    • +
    • capabilities — objeto com flags { supported: boolean } por capacidade: batch, citations, code_execution, image_input, pdf_input, structured_outputs, context_management (com estratégias datadas), effort (níveis low/medium/high/xhigh/max) e thinking (tipos adaptive e enabled).
    • +
    + +
    +
    + + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +
    +# Lista modelos (paginação automática)
    +for model in client.models.list(limit=20):
    +    print(model.id, model.display_name)
    +
    +# Resolve um alias / inspeciona limites e capacidades
    +info = client.models.retrieve("claude-opus-4-8")
    +print(info.max_input_tokens, info.max_tokens)
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic();
    +
    +for await (const model of client.models.list({ limit: 20 })) {
    +  console.log(model.id, model.display_name);
    +}
    +
    +const info = await client.models.retrieve("claude-opus-4-8");
    +console.log(info.max_input_tokens, info.max_tokens);
    +
    +
    +
    curl https://api.anthropic.com/v1/models \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "x-api-key: $ANTHROPIC_API_KEY"
    +
    +curl https://api.anthropic.com/v1/models/claude-opus-4-8 \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "x-api-key: $ANTHROPIC_API_KEY"
    +
    +
    + + +
    + + +
    +

    4. API de Mensagens — anatomia

    +

    A Messages API (POST /v1/messages) é o coração da integração. Os parâmetros centrais de um request são:

    +
    + + + + + + + + + + +
    ParâmetroTipoDescrição
    modelstring (obrigatório)ID do modelo (ex.: claude-opus-4-8).
    max_tokensinteger (obrigatório)Máximo de tokens a gerar. Limitado pelo max_tokens do modelo (ver seção 3).
    messagesarray (obrigatório)Histórico de turnos. Cada item tem role (user ou assistant) e content (string ou array de blocos).
    systemstring ou arrayPrompt de sistema — instruções, persona, regras. Não é um turno de messages; é um campo de topo.
    temperaturenumber (0–1)Aleatoriedade da amostragem. Mais baixo → mais determinístico. ⚠️ Depreciado em Opus 4.7/4.8 e Fable 5 — ver aviso abaixo.
    stop_sequencesarray de stringsSequências que, ao serem geradas, encerram a resposta (stop_reason: "stop_sequence").
    streambooleantrue para streaming via SSE (ver seção 5).
    + +

    Conversas multiturno (API stateless)

    +

    A Messages API é stateless: você sempre envia o histórico completo a cada chamada. Para continuar uma conversa, anexe a resposta do assistant e o novo turno do user ao array messages. Turnos anteriores não precisam ter vindo de fato do Claude — você pode inserir mensagens assistant sintéticas.

    + +
    +
    + + + +
    +
    +
    message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    system="Você é um tutor paciente de física.",
    +    messages=[
    +        {"role": "user", "content": "Olá, Claude"},
    +        {"role": "assistant", "content": "Olá! Como posso ajudar?"},
    +        {"role": "user", "content": "Você pode me descrever LLMs?"},
    +    ],
    +)
    +print(message.content[0].text)
    +
    +
    +
    const message = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  system: "Você é um tutor paciente de física.",
    +  messages: [
    +    { role: "user", content: "Olá, Claude" },
    +    { role: "assistant", content: "Olá! Como posso ajudar?" },
    +    { role: "user", content: "Você pode me descrever LLMs?" },
    +  ],
    +});
    +console.log(message.content[0].text);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "system": "Você é um tutor paciente de física.",
    +    "messages": [
    +      {"role": "user", "content": "Olá, Claude"},
    +      {"role": "assistant", "content": "Olá! Como posso ajudar?"},
    +      {"role": "user", "content": "Você pode me descrever LLMs?"}
    +    ]
    +  }'
    +
    +
    + +

    Prefill ("colocando palavras na boca do Claude")

    +

    Historicamente, era possível pré-preencher o início da resposta colocando uma mensagem assistant na última posição de messages para moldar a saída (ex.: forçar um formato).

    +
    Cuidado: o prefill não é suportado em claude-opus-4-8 nem em claude-sonnet-4-6 — requests com prefill nesses modelos retornam erro 400. Para moldar o formato da resposta, use structured outputs (JSON outputs) ou instruções no system prompt.
    + +

    Entradas de visão (resumo)

    +

    Os blocos de content podem ser de tipo image além de text. A fonte da imagem pode ser base64, url ou file (referência a um arquivo da Files API). Tipos de mídia suportados: image/jpeg, image/png, image/gif, image/webp. O detalhamento de visão, PDFs e Files API está na Parte B.

    + + +
    + + +
    +

    5. Geração de texto & streaming (SSE)

    +

    Com "stream": true, a resposta é entregue incrementalmente via Server-Sent Events (SSE). Os SDKs oferecem helpers idiomáticos: em Python, client.messages.stream(...) com iteração sobre stream.text_stream; em TypeScript, o método .stream({...}) com o evento .on("text", ...).

    + +
    Transporte: a Messages API usa HTTP request-response; o streaming é SSE (stream: true) sobre a mesma conexão HTTP — um único endpoint (POST /v1/messages) atende mensagens, tools, thinking e caching, mudando só o corpo. Não há transporte WebSocket para a Messages API. WebSocket aparece apenas no transporte de servidores MCP (streamable-HTTP/WebSocket), uma camada de ferramentas separada da chamada ao modelo.
    + +
    +
    + + + +
    +
    +
    with client.messages.stream(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá"}],
    +) as stream:
    +    for text in stream.text_stream:
    +        print(text, end="", flush=True)
    +
    +    # Acumula tudo e retorna o Message completo (igual ao .create())
    +    final = stream.get_final_message()
    +
    +
    +
    const stream = client.messages.stream({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Olá" }],
    +});
    +
    +for await (const event of stream) {
    +  if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
    +    process.stdout.write(event.delta.text);
    +  }
    +}
    +
    +const final = await stream.finalMessage();
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "messages": [{"role": "user", "content": "Olá"}],
    +    "max_tokens": 256,
    +    "stream": true
    +  }'
    +
    +
    + +
    Dica: mesmo quando você não precisa processar texto incremental, use streaming para requests com max_tokens grande. get_final_message() (Python) / finalMessage() (TS) mantêm a conexão HTTP viva e acumulam tudo, evitando timeouts.
    + +

    Fluxo e tipos de eventos

    +

    Cada SSE traz um nome de evento (event: ...) e dados JSON com um campo type correspondente. O fluxo de um stream é:

    +
      +
    1. message_start — objeto Message com content vazio.
    2. +
    3. Uma série de blocos de conteúdo, cada um com content_block_start → um ou mais content_block_delta → content_block_stop. Cada bloco tem um index que corresponde à sua posição no array content final.
    4. +
    5. Um ou mais message_delta — mudanças de topo no Message (ex.: stop_reason, usage).
    6. +
    7. Um message_stop final.
    8. +
    +

    Podem aparecer eventos ping em qualquer ponto, e eventos error (ex.: overloaded_error, equivalente a HTTP 529 fora do streaming). Conforme a política de versionamento, novos tipos de evento podem surgir — trate tipos desconhecidos com tolerância.

    + +
    + + + + + + + +
    Tipo de deltaEm que blocoObservação
    text_deltatextFragmento de texto: {"type":"text_delta","text":"olá frien"}.
    input_json_deltatool_useFragmentos parciais de JSON no campo partial_json; acumule e parseie ao receber content_block_stop.
    thinking_deltathinkingConteúdo de raciocínio (extended/adaptive thinking).
    signature_deltathinkingAssinatura criptográfica enviada antes do content_block_stop, verifica a integridade do bloco de thinking.
    + +
    Atenção: os contadores em usage dentro de eventos message_delta são cumulativos. O stop_reason é null em message_start e só aparece preenchido em message_delta.
    + +
    Exemplo de stream SSE completo +
    event: message_start
    +data: {"type":"message_start","message":{"id":"msg_...","type":"message","role":"assistant","content":[],"model":"claude-opus-4-8","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":25,"output_tokens":1}}}
    +
    +event: content_block_start
    +data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
    +
    +event: ping
    +data: {"type":"ping"}
    +
    +event: content_block_delta
    +data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Olá"}}
    +
    +event: content_block_stop
    +data: {"type":"content_block_stop","index":0}
    +
    +event: message_delta
    +data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":15}}
    +
    +event: message_stop
    +data: {"type":"message_stop"}
    +
    + + +
    + + +
    +

    6. O campo stop_reason

    +

    Toda resposta bem-sucedida da Messages API inclui stop_reason, indicando por que o Claude parou de gerar. Ao contrário de erros (que indicam falhas no request), stop_reason faz parte de uma resposta válida. Sempre cheque esse campo na sua lógica de tratamento.

    + +
    + + + + + + + + + + +
    ValorSignificadoComo tratar
    end_turnClaude terminou naturalmente (o mais comum).Processe a resposta completa.
    max_tokensAtingiu o limite de max_tokens do request — resposta truncada.Reenvie com max_tokens maior, ou continue a geração.
    stop_sequenceEncontrou uma das suas stop_sequences personalizadas.O campo stop_sequence indica qual sequência disparou.
    tool_useClaude está chamando uma ferramenta e espera que você a execute.Execute a ferramenta e devolva o tool_result (ver Parte C).
    pause_turnO loop de sampling do servidor atingiu o limite de iterações ao executar server tools (web search/fetch). Padrão: 10 iterações.Continue a conversa reenviando a resposta como está (anexe o assistant e chame de novo).
    refusalClaude recusou por motivos de segurança.HTTP 200, mas a saída pode não seguir o schema. Reformule o pedido.
    model_context_window_exceededAtingiu o limite da janela de contexto do modelo antes do max_tokens.A resposta é válida, mas limitada pela janela. Veja a nota abaixo.
    + +
    Nota: model_context_window_exceeded está disponível por padrão em modelos Claude 4.5 e mais recentes. Em modelos anteriores, habilite com o header beta model-context-window-exceeded-2025-08-26. Ele permite pedir o máximo possível de tokens sem conhecer o tamanho exato da entrada.
    + +

    Pegadinha — respostas vazias com end_turn: às vezes o Claude retorna conteúdo vazio (2–3 tokens) com end_turn, tipicamente após tool_result. Causas comuns: (1) adicionar um bloco text logo após um tool_result (o Claude aprende a esperar input do usuário após cada uso de ferramenta), e (2) reenviar a resposta já concluída sem nada novo. Soluções: nunca adicione texto imediatamente após tool_result; e, se persistir, anexe um novo turno user ("Por favor, continue") em vez de reenviar a resposta vazia.

    + +
    +
    + + +
    +
    +
    def handle_response(response):
    +    if response.stop_reason == "tool_use":
    +        return handle_tool_use(response)
    +    elif response.stop_reason in ("max_tokens", "model_context_window_exceeded"):
    +        return handle_truncation(response)
    +    elif response.stop_reason == "pause_turn":
    +        return handle_pause(response)
    +    elif response.stop_reason == "refusal":
    +        return handle_refusal(response)
    +    else:  # end_turn e demais
    +        return response.content[0].text
    +
    +
    +
    function handleResponse(response) {
    +  switch (response.stop_reason) {
    +    case "tool_use": return handleToolUse(response);
    +    case "max_tokens":
    +    case "model_context_window_exceeded": return handleTruncation(response);
    +    case "pause_turn": return handlePause(response);
    +    case "refusal": return handleRefusal(response);
    +    default: { // end_turn e demais
    +      const block = response.content.find((b) => b.type === "text");
    +      return block?.text;
    +    }
    +  }
    +}
    +
    +
    + +
    Dica: em streaming, stop_reason é null no message_start e é fornecido no message_delta (não em outros eventos). Ao truncar por max_tokens durante tool_use, verifique se o último bloco é um tool_use incompleto e reenvie com max_tokens maior.
    + + +
    + + +
    +

    6.1. Fallback em recusas: parâmetro fallbacks e Beta Fallback credit

    +

    Os classificadores de segurança do Claude Fable 5 podem recusar um pedido — você recebe uma resposta HTTP 200 normal com stop_reason: "refusal" (ver seção 6), não um erro. O mesmo pedido costuma ser aceito por outro modelo. O server-side fallback automatiza esse retry dentro de uma única chamada de API: você lista até 3 modelos de fallback no parâmetro fallbacks e, quando o modelo pedido recusa, a API roda o próximo da cadeia no mesmo request. Uma única resposta é devolvida, e o campo model de topo indica qual modelo efetivamente respondeu — o usuário recebe a resposta em um único round trip.

    + +
    Beta Header: requer anthropic-beta: server-side-fallback-2026-06-01 (verificado em 2026-07-12). A data precisa ser exatamente essa; sob qualquer outro valor server-side-fallback-* a API rejeita fallbacks com erro 400. Disponível na Claude API e na Claude Platform on AWS. Não disponível em Amazon Bedrock, Google Cloud nem Microsoft Foundry — nessas plataformas use o SDK middleware (client-side, ver abaixo). O parâmetro fallbacks também é rejeitado na Message Batches API: um item de batch que inclua fallbacks retorna resultado com erro por item.
    + +

    6.1.1. Regras da lista fallbacks

    +
      +
    • Só é acionado quando o modelo pedido recusa por classificador de segurança. Rate limit, overload ou erro de servidor no modelo pedido são devolvidos como estão, sem disparar fallback.
    • +
    • As entradas são tentadas na ordem. Cada uma deve ser distinta das demais e do modelo pedido.
    • +
    • Cada entrada precisa ser um alvo permitido do modelo pedido — com o beta header ativo, essa lista é publicada em allowed_fallback_models na entrada do modelo no Models API.
    • +
    • Cada entrada nomeia um model e pode sobrescrever max_tokens e thinking só para aquela tentativa.
    • +
    • O request precisa ser válido como request direto para todos os modelos citados. Se um fallback não suportar um recurso usado no request, a API rejeita o request de saída (antes de tentar).
    • +
    + +

    6.1.2. Exemplo de uso

    +
    +
    + + + +
    +
    +
    response = client.beta.messages.create(
    +    model="claude-fable-5",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Hello, Claude"}],
    +    fallbacks=[{"model": "claude-opus-4-8"}],   # até 3 modelos, tentados em ordem
    +    betas=["server-side-fallback-2026-06-01"],
    +)
    +
    +# Uma entrada "fallback_message" em usage.iterations indica que um modelo de
    +# fallback rodou; combine com stop_reason para confirmar que ele serviu a resposta.
    +fallback_ran = any(
    +    it.type == "fallback_message" for it in response.usage.iterations or []
    +)
    +served_by_fallback = fallback_ran and response.stop_reason != "refusal"
    +
    +print(response.model)              # modelo que efetivamente respondeu
    +print(served_by_fallback)
    +
    +
    +
    const response = await client.beta.messages.create({
    +  model: "claude-fable-5",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Hello, Claude" }],
    +  fallbacks: [{ model: "claude-opus-4-8" }],   // até 3 modelos, tentados em ordem
    +  betas: ["server-side-fallback-2026-06-01"]
    +});
    +
    +const { stop_reason, model, usage } = response;
    +const servedByFallback =
    +  (usage.iterations ?? []).some((it) => it.type === "fallback_message") &&
    +  stop_reason !== "refusal";
    +
    +console.log(model, servedByFallback);
    +
    +
    +
    curl --fail-with-body -sS https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "anthropic-beta: server-side-fallback-2026-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-fable-5",
    +    "max_tokens": 1024,
    +    "fallbacks": [{"model": "claude-opus-4-8"}],
    +    "messages": [{"role": "user", "content": "Hello, Claude"}]
    +  }' | jq -r '.model'
    +
    +
    + +

    A resposta traz um bloco de conteúdo fallback marcando a fronteira entre modelos, e usage.iterations registra cada tentativa (tipo message para quem recusou, fallback_message para quem serviu). Numa recusa antes de qualquer output, o bloco fallback é o primeiro bloco de conteúdo:

    +
    {
    +  "id": "msg_01XFUDYJgAACzvnptvVoYEL",
    +  "model": "claude-opus-4-8",
    +  "content": [
    +    { "type": "fallback", "from": { "model": "claude-fable-5" }, "to": { "model": "claude-opus-4-8" } },
    +    { "type": "text", "text": "Hi! How can I help you today?" }
    +  ],
    +  "stop_reason": "end_turn",
    +  "stop_details": null,
    +  "usage": {
    +    "input_tokens": 412,
    +    "output_tokens": 264,
    +    "iterations": [
    +      { "type": "message",          "model": "claude-fable-5",  "input_tokens": 535, "output_tokens": 0 },
    +      { "type": "fallback_message", "model": "claude-opus-4-8", "input_tokens": 412, "output_tokens": 264 }
    +    ]
    +  }
    +}
    + +
    + + + + + + +
    CampoDescrição
    model (topo)Modelo que produziu a mensagem retornada — o pedido original ou um dos fallbacks.
    content[].type: "fallback"Marca cada ponto de transição entre modelos. from.model ecoa o modelo que você pediu quando o hop que recusa é o próprio modelo pedido; to.model é sempre o ID resolvido do modelo que continua.
    usage.iterations[]Registro por tentativa: type: "message" para tentativas que recusaram, type: "fallback_message" para a que serviu. Se toda a cadeia recusar, a resposta é a recusa do último modelo (com uma entrada message por hop anterior e um fallback_message para o último). Os tokens de cada tentativa não são somados no usage de topo — o topo descreve só a tentativa que gerou a resposta.
    + +
    Billing: você paga apenas pelo modelo que efetivamente serve a resposta. Uma tentativa que recusou antes de gerar output custa nada e não consome rate limit. Cada tentativa que roda é cobrada às taxas do modelo que a rodou e conta no rate limit daquele modelo — usage.iterations é o registro por tentativa do que você paga. Se o fallback estiver sob rate limit/overload, a tentativa de fallback não é feita e a recusa anterior é devolvida; nesse caso stop_details.recommended_model pode sugerir um modelo para tentar diretamente (é uma dica, e é null quando não há recomendação). Dimensione o rate limit do modelo de fallback para o volume de recusas esperado, ou os fallbacks degradam para recusas sob carga.
    + +
    Sticky routing: depois que uma conversa cai em fallback, a API registra por ~1h (escopo: sua organização) qual modelo serviu — via hash de conteúdo do prefixo da conversa + modelo (o conteúdo em si não é armazenado). Requests seguintes da mesma conversa que incluam fallbacks vão direto a esse modelo, sem tentar de novo o pedido original. Um turno servido por sticky routing não carrega bloco fallback (nenhum modelo recusou naquele turno): identifique-o pela entrada fallback_message em usage.iterations, pela ausência de entrada message do modelo pedido e pelo campo model. É best-effort (seu código deve tolerar o modelo original ser tentado de novo a qualquer momento) e, na release atual, só se aplica a requests não-streaming.
    + +

    6.1.3. Fallback credit — evitar pagar o prompt cache duas vezes

    +

    Prompt caches são por modelo. Quando o Fable 5 recusa e você tenta em outro modelo, o prefixo já cacheado para o Fable 5 tem de ser escrito do zero no cache do novo modelo — e cache write custa mais que cache read. O fallback credit remove esse custo extra: a recusa carrega um token de crédito, você ecoa o token no retry, e o retry é cobrado como se a conversa já estivesse no novo modelo desde o início.

    +

    O server-side fallbacks e o SDK middleware já aplicam o fallback credit automaticamente — você só precisa disto quando implementa o retry você mesmo, sobre HTTP cru ou lógica de retry customizada.

    + +
    Beta Header: ative com anthropic-beta: fallback-credit-2026-06-01 (verificado em 2026-07-12); o header server-side-fallback-2026-06-01 também concede os mesmos campos. Diferente do server-side fallback, o fallback credit está disponível também em Amazon Bedrock, Google Cloud e Microsoft Foundry (além da Claude API e Claude Platform on AWS). Tokens retornados em resultados de Message Batches não podem ser redimidos — a redenção só vale para requests diretos à Messages API.
    + +

    Fluxo de redenção (retry manual):

    +
      +
    1. Envie o request que pode ser recusado com o header fallback-credit-2026-06-01.
    2. +
    3. Na recusa, leia dois campos de stop_details: fallback_credit_token (string opaca que representa o crédito) e fallback_has_prefill_claim (boolean que indica a forma do corpo de retry). Ambos são null quando não há crédito.
    4. +
    5. Monte o retry a partir do corpo do request recusado, troque model para o modelo de fallback e adicione o token no parâmetro de topo fallback_credit_token. Envie com o mesmo header beta.
    6. +
    + +
    +
    + + +
    +
    +
    request = {"max_tokens": 1024, "messages": [{"role": "user", "content": "Hello, Claude"}]}
    +
    +resp = client.beta.messages.create(
    +    model="claude-fable-5", betas=["fallback-credit-2026-06-01"], **request
    +)
    +
    +details = resp.stop_details
    +if resp.stop_reason == "refusal" and details and details.fallback_credit_token:
    +    # Corpo do retry = corpo recusado, inalterado, + o token no topo.
    +    body = request | {"fallback_credit_token": details.fallback_credit_token}
    +    # Prefira a forma de continuação, a menos que a claim seja explicitamente False.
    +    if details.fallback_has_prefill_claim is not False:
    +        # Continua a resposta parcial: anexa 1 mensagem assistant ecoando o content.
    +        body["messages"] = [*request["messages"],
    +                            {"role": "assistant", "content": [b.model_dump() for b in resp.content]}]
    +    resp = client.beta.messages.create(
    +        model="claude-opus-4-8", betas=["fallback-credit-2026-06-01"], **body
    +    )
    +
    +print(resp.model)
    +
    +
    +
    # 1) Request inicial (pode ser recusado)
    +response=$(curl --fail-with-body -sS https://api.anthropic.com/v1/messages \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: fallback-credit-2026-06-01" -H "content-type: application/json" \
    +  -d '{"model":"claude-fable-5","max_tokens":1024,
    +       "messages":[{"role":"user","content":"Hello, Claude"}]}')
    +
    +# 2) A recusa carrega um token de uso único em stop_details
    +token=$(jq -r '.stop_details.fallback_credit_token // empty' <<<"${response}")
    +
    +# 3) Retry no modelo de fallback com o token (mesmo corpo)
    +if [[ -n "${token}" ]]; then
    +  response=$(curl --fail-with-body -sS https://api.anthropic.com/v1/messages \
    +    -H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \
    +    -H "anthropic-beta: fallback-credit-2026-06-01" -H "content-type: application/json" \
    +    -d "$(jq -n --arg t "${token}" '{model:"claude-opus-4-8",max_tokens:1024,
    +         messages:[{"role":"user","content":"Hello, Claude"}],fallback_credit_token:$t}')")
    +fi
    +jq -c '{stop_reason, model}' <<<"${response}"
    +
    +
    + +
    Pegadinha — match exato: a redenção compara o retry com o request recusado. Os campos que moldam o prompt precisam bater exatamente: system, messages, tools, tool_choice, thinking, cache_control (e output_config, mcp_servers, context_management, container quando usados) — além dos mesmos anthropic-beta headers. O que não molda o prompt pode mudar: model, max_tokens, stop_sequences, temperature, top_p, top_k, stream, metadata, service_tier. A forma de continuação (fallback_has_prefill_claim: true) é a única exceção ao match de messages: acrescenta exatamente uma mensagem assistant no fim. Ao redimir, não remova os blocos thinking/redacted_thinking dos turnos anteriores — o servidor os trata sozinho. (Só quando você não vai redimir crédito é que pode removê-los do histórico antes do retry; outros modelos os ignoram.) O token expira 5 minutos após a recusa.
    + +

    Caso especial — recusa após server tools: se a recusa ocorre depois que server tools (web search, code execution etc.) já rodaram dentro do mesmo request, a API retorna a recusa em vez de avançar para um fallback. Com o header fallback-credit-2026-06-01 ativo, essa recusa carrega um token de crédito redimível continuando a resposta parcial — preservando o trabalho de tool já executado (as tool calls concluídas não rodam nem são cobradas de novo). Aplica-se só a server tools iterando dentro de um único request; conversas com ferramentas client-side fazem fallback normalmente.

    + +
    Dica: prefira o fallbacks server-side (Claude API / Claude Platform on AWS) ou o SDK middleware sempre que possível — ambos aplicam o fallback credit automaticamente, gerenciam os blocos fallback/thinking e fixam a conversa (via BetaFallbackState) no modelo que aceitou. Nunca configure os dois no mesmo request. Reserve o retry manual com fallback-credit-2026-06-01 para HTTP cru ou lógica de retry customizada, inclusive em Bedrock, Google Cloud e Foundry, onde o server-side fallbacks não existe.
    + + +
    + + +
    +

    7. Structured outputs GA

    +

    Structured outputs restringem a resposta do Claude a um schema, garantindo saída válida e parseável via constrained decoding. São dois recursos complementares, usáveis isolada ou conjuntamente:

    +
      +
    • JSON outputs (output_config.format): força a resposta em um formato JSON específico (o que o Claude diz).
    • +
    • Strict tool use (strict: true em uma ferramenta): garante validação de schema nos nomes e inputs de ferramentas (como o Claude chama suas funções).
    • +
    + +
    Nota: GA na Claude API para Claude Opus 4.8, Sonnet 5, Sonnet 4.6 e Haiku 4.5 (entre outros). O antigo parâmetro beta output_format migrou para output_config.format e o header beta não é mais necessário — o caminho antigo segue funcionando por um período de transição.
    + +

    JSON outputs

    +

    Defina um JSON Schema e inclua-o em output_config.format com type: "json_schema". A resposta vem como JSON válido em response.content[0].text.

    + +
    +
    + + + +
    +
    +
    response = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Extraia os dados deste e-mail: John Smith (john@example.com), interesse no plano Enterprise, quer demo terça às 14h."}],
    +    output_config={
    +        "format": {
    +            "type": "json_schema",
    +            "schema": {
    +                "type": "object",
    +                "properties": {
    +                    "name": {"type": "string"},
    +                    "email": {"type": "string"},
    +                    "plan_interest": {"type": "string"},
    +                    "demo_requested": {"type": "boolean"},
    +                },
    +                "required": ["name", "email", "plan_interest", "demo_requested"],
    +                "additionalProperties": False,
    +            },
    +        }
    +    },
    +)
    +print(response.content[0].text)  # JSON válido garantido
    +
    +
    +
    const response = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Extraia os dados deste e-mail: John Smith (john@example.com)..." }],
    +  output_config: {
    +    format: {
    +      type: "json_schema",
    +      schema: {
    +        type: "object",
    +        properties: {
    +          name: { type: "string" },
    +          email: { type: "string" },
    +          plan_interest: { type: "string" },
    +          demo_requested: { type: "boolean" },
    +        },
    +        required: ["name", "email", "plan_interest", "demo_requested"],
    +        additionalProperties: false,
    +      },
    +    },
    +  },
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  -H "content-type: application/json" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -d '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{"role": "user", "content": "Extraia os dados deste e-mail..."}],
    +    "output_config": {
    +      "format": {
    +        "type": "json_schema",
    +        "schema": {
    +          "type": "object",
    +          "properties": {
    +            "name": {"type": "string"},
    +            "email": {"type": "string"},
    +            "plan_interest": {"type": "string"},
    +            "demo_requested": {"type": "boolean"}
    +          },
    +          "required": ["name", "email", "plan_interest", "demo_requested"],
    +          "additionalProperties": false
    +        }
    +      }
    +    }
    +  }'
    +
    +
    + +
    Dica: os SDKs têm helpers que aceitam definições nativas e validam automaticamente: em Python, client.messages.parse(..., output_format=ModeloPydantic) retorna response.parsed_output; em TypeScript, zodOutputFormat(schema) ou jsonSchemaOutputFormat(schema) com client.messages.parse(...).
    + +

    Strict tool use & uso combinado

    +

    Marque uma ferramenta com strict: true para que seus inputs sejam validados contra o input_schema por sampling guiado por gramática. JSON outputs e strict tool use resolvem problemas diferentes e funcionam juntos no mesmo request — útil em fluxos agênticos onde você precisa de chamadas de ferramenta confiáveis e de uma saída final estruturada.

    + +

    Limitações de JSON Schema & complexidade

    +

    Structured outputs suportam um subconjunto do JSON Schema. Recursos como enum (tipos simples), const, anyOf/allOf (com restrições), $ref/$defs internos, default, e formatos de string (date-time, date, email, uri, uuid, etc.) são suportados. Não são suportados: schemas recursivos, $ref externo, restrições numéricas (minimum/maximum/multipleOf), restrições de string (minLength/maxLength) e additionalProperties diferente de false. Usar um recurso não suportado gera erro 400.

    +
    + + + + + + +
    Limite explícitoValorDescrição
    Ferramentas strict por request20Máx. de tools com strict: true.
    Parâmetros opcionais24Total de parâmetros não-required em todos os schemas strict + JSON output.
    Parâmetros com union types16Total que usa anyOf ou arrays de tipo (custo de compilação exponencial).
    +

    Caching de gramática: a primeira request com um schema tem latência extra de compilação; gramáticas compiladas são cacheadas por 24h desde o último uso (mudanças em name/description não invalidam o cache, mas mudar a estrutura ou o conjunto de tools sim). Há um timeout de compilação de 180s.

    + +
    Atenção: structured outputs são incompatíveis com Citations (retorna 400 se combinado com output_config.format) e com prefilling de mensagem. São compatíveis com batch, token counting e streaming. Em ZDR, prompts/respostas não são retidos, mas o JSON schema é cacheado por até 24h — não inclua PHI/dados sensíveis em nomes de propriedade, enum, const ou pattern.
    + + +
    + + +
    +

    8. Effort & Fast mode

    +

    O parâmetro effort

    +

    O parâmetro effort (em output_config.effort) controla quão "disposto" o Claude está a gastar tokens, equilibrando completude e eficiência. Não exige header beta e afeta todos os tokens da resposta — texto, chamadas de ferramenta e o thinking (quando ativo). É suportado em Claude Fable 5, Opus 4.8, Opus 4.7, Sonnet 5 e Sonnet 4.6 (entre outros), com padrão high — o Haiku 4.5 não suporta. No Sonnet 5 (modelo recomendado), effort é o controle primário da profundidade de raciocínio, com thinking adaptativo ligado por padrão.

    + +
    + + + + + + + + +
    NívelDescriçãoDisponível em
    maxCapacidade máxima absoluta, sem restrição de tokens.Fable 5, Opus 4.8/4.7/4.6, Sonnet 5, Sonnet 4.6
    xhighCapacidade estendida para trabalho de longo horizonte (agentes/coding > 30 min, budgets na casa dos milhões).Fable 5, Opus 4.8/4.7, Sonnet 5 (não em Sonnet 4.6)
    highAlta capacidade. Equivale a não setar o parâmetro (é o padrão da API).Todos os suportados
    mediumEquilíbrio com economia moderada de tokens.Todos os suportados
    lowMais eficiente; economia significativa com alguma redução de capacidade.Todos os suportados
    + +
    +
    + + + +
    +
    +
    response = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=4096,
    +    messages=[{"role": "user", "content": "Analise trade-offs entre microsserviços e monólito."}],
    +    output_config={"effort": "medium"},
    +)
    +print(response.content[0].text)
    +
    +
    +
    const response = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 4096,
    +  messages: [{ role: "user", content: "Analise trade-offs entre microsserviços e monólito." }],
    +  output_config: { effort: "medium" },
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 4096,
    +    "messages": [{"role": "user", "content": "Analise trade-offs entre microsserviços e monólito."}],
    +    "output_config": {"effort": "medium"}
    +  }'
    +
    +
    + +
    Dica: para Opus 4.8, comece em xhigh para coding/agentes e use high como mínimo para cargas sensíveis a inteligência; reserve max para problemas de fronteira. Para Sonnet 4.6, defina effort explicitamente (recomendado medium) — caso contrário pode haver latência inesperada. Em xhigh/max no Opus 4.8, dê um max_tokens generoso (comece em 64k).
    + +

    effort e thinking: em Opus 4.8 e Sonnet 5 o thinking é adaptativo e ligado por padrão, e o effort é o controle recomendado da profundidade — nesses dois modelos o thinking manual (type: "enabled", budget_tokens) retorna 400 (use thinking: {type: "adaptive"} ou {type: "disabled"} para desligar). Em Sonnet 4.6 e Opus 4.6, budget_tokens ainda é aceito porém deprecado. effort também funciona sem thinking, controlando o gasto geral. (Detalhes de thinking na Parte B.)

    + +

    Fast mode Beta (research preview)

    +

    O fast mode entrega geração de tokens de saída até 2,5× mais rápida rodando o mesmo modelo com uma configuração de inferência mais veloz (mesmos pesos, mesma inteligência). Ativa-se com speed: "fast" e o header beta fast-mode-2026-02-01, via namespace beta. Suportado em Claude Opus 4.8.

    + +
    +
    + + + +
    +
    +
    response = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=4096,
    +    speed="fast",
    +    betas=["fast-mode-2026-02-01"],
    +    messages=[{"role": "user", "content": "Refatore este módulo para injeção de dependência"}],
    +)
    +print(response.usage.speed)  # "fast" ou "standard"
    +
    +
    +
    const response = await client.beta.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 4096,
    +  speed: "fast",
    +  betas: ["fast-mode-2026-02-01"],
    +  messages: [{ role: "user", content: "Refatore este módulo para injeção de dependência" }],
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "anthropic-beta: fast-mode-2026-02-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 4096,
    +    "speed": "fast",
    +    "messages": [{"role": "user", "content": "Refatore este módulo para injeção de dependência"}]
    +  }'
    +
    +
    + +
    Atenção: fast mode custa 6× as taxas padrão do Opus em toda a janela de contexto: $30/MTok entrada · $150/MTok saída. O ganho é em tokens de saída por segundo (OTPS), não em time to first token. Tem rate limit dedicado (HTTP 429 com header retry-after) e não está disponível com a Batch API nem no Claude Platform on AWS. O usage.speed da resposta indica qual velocidade foi usada.
    + + +
    + + +
    +

    9. Janelas de contexto & contagem de tokens

    +

    A "janela de contexto" é todo o texto que o modelo consegue referenciar ao gerar uma resposta, incluindo a própria resposta — uma "memória de trabalho". Opus 4.8 e Sonnet 4.6 têm 1M tokens; Haiku 4.5 (e modelos com janela menor) têm 200k tokens. Um único request pode incluir até 600 imagens/páginas de PDF (100 em modelos de 200k).

    + +
    Nota: mais contexto não é automaticamente melhor. À medida que o número de tokens cresce, precisão e recall degradam — fenômeno conhecido como context rot. Curar o que entra no contexto importa tanto quanto quanto cabe.
    + +

    Contexto com thinking: tokens de thinking contam para a janela e são cobrados como saída, mas blocos de thinking de turnos anteriores são automaticamente removidos do cálculo da janela pela API — você não precisa removê-los manualmente. A exceção: durante um ciclo de tool_use, o bloco de thinking que acompanha o tool_use deve ser devolvido junto com os tool_result correspondentes (a API usa assinaturas criptográficas para verificar a integridade).

    + +

    Context awareness: Sonnet 4.6 e Haiku 4.5 rastreiam o "token budget" restante ao longo da conversa, recebendo no início <budget:token_budget>1000000</budget:token_budget> e, após cada chamada de ferramenta, um aviso de capacidade restante. Isso melhora a execução em tarefas longas. Para janelas que se aproximam do limite, a estratégia recomendada é a compaction server-side (Parte B); context editing oferece estratégias finas adicionais.

    + +

    Overflow: nos modelos atuais, se input_tokens + max_tokens exceder a janela, a API aceita o request e, se a geração atingir o limite, para com stop_reason: "model_context_window_exceeded" (ver seção 6). Em gerações anteriores a API retornava erro de validação.

    + +

    Contagem de tokens (conceito)

    +

    O endpoint POST /v1/messages/count_tokens conta os tokens de entrada antes de enviar o request, ajudando a gerenciar rate limits/custos, decidir roteamento de modelo e otimizar o tamanho do prompt. Aceita a mesma lista estruturada de inputs (system, tools, imagens, PDFs) e retorna { "input_tokens": N }. Todos os modelos ativos suportam contagem de tokens.

    + +
    +
    + + + +
    +
    +
    response = client.messages.count_tokens(
    +    model="claude-opus-4-8",
    +    system="Você é um cientista",
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +print(response.input_tokens)  # ex.: 14
    +
    +
    +
    const response = await client.messages.countTokens({
    +  model: "claude-opus-4-8",
    +  system: "Você é um cientista",
    +  messages: [{ role: "user", content: "Olá, Claude" }],
    +});
    +console.log(response.input_tokens);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages/count_tokens \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "system": "Você é um cientista",
    +    "messages": [{"role": "user", "content": "Olá, Claude"}]
    +  }'
    +
    +
    + +
    Atenção: a contagem é uma estimativa — o número real de tokens pode diferir por uma pequena margem. A contagem pode incluir tokens adicionados pela Anthropic para otimizações de sistema, mas você não é cobrado por tokens adicionados pelo sistema; o faturamento reflete apenas seu conteúdo.
    + + +
    + + +
    +

    10. Embeddings

    +

    Embeddings são representações numéricas de texto que permitem medir similaridade semântica — base para busca, recomendação, RAG e detecção de anomalias. A Anthropic não oferece um modelo de embedding próprio; a documentação recomenda Voyage AI como parceiro (modelos de propósito geral, multilíngues e específicos de domínio como finanças, jurídico e código).

    + +
    + + + + + + + +
    Modelo (Voyage 4)ContextoDimensãoFoco
    voyage-4-large32.0001024 (padrão), 256, 512, 2048Melhor qualidade geral/multilíngue
    voyage-432.0001024 (padrão), 256, 512, 2048Equilíbrio qualidade/eficiência
    voyage-4-lite32.0001024 (padrão), 256, 512, 2048Menor latência e custo
    voyage-code-332.0001024 (padrão), …Recuperação de código
    + +
    +
    + + +
    +
    +
    import voyageai
    +
    +vo = voyageai.Client()  # usa VOYAGE_API_KEY do ambiente
    +
    +# Use input_type para distinguir documento de consulta (melhora a recuperação)
    +docs = vo.embed(["Texto exemplo 1", "Texto exemplo 2"],
    +                model="voyage-4", input_type="document").embeddings
    +query = vo.embed(["Minha pergunta"], model="voyage-4", input_type="query").embeddings[0]
    +
    +
    +
    curl https://api.voyageai.com/v1/embeddings \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $VOYAGE_API_KEY" \
    +  -d '{
    +    "input": ["Texto exemplo 1", "Texto exemplo 2"],
    +    "model": "voyage-4"
    +  }'
    +
    +
    + +
    Dica: em tarefas de recuperação (RAG), sempre use input_type ("query" vs "document") — não omita. Os embeddings da Voyage são normalizados a comprimento 1, então similaridade por produto escalar e cosseno são equivalentes (o produto escalar é mais rápido). Quantização (output_dtype) e dimensões Matryoshka permitem reduzir armazenamento/custo.
    + + +
    + + +
    +

    11. Suporte multilíngue

    +

    Claude tem forte desempenho cross-lingual em relação ao inglês, com destaque em tarefas zero-shot. Para um guia em português, vale notar que o português (Brasil) está entre os idiomas de melhor desempenho relativo ao inglês — na avaliação MMLU traduzida por tradutores humanos, fica acima de 96% em relação ao baseline inglês nos modelos recentes, ao lado de espanhol, italiano e francês. O desempenho varia por idioma, sendo mais forte em línguas amplamente faladas, mas Claude mantém capacidade significativa mesmo em idiomas com menos recursos digitais.

    + +
    Dica (boas práticas multilíngues): +
      +
    • Forneça contexto de idioma claro: embora o Claude detecte automaticamente, declarar explicitamente a língua de entrada/saída melhora a confiabilidade. Para mais fluência, peça "fala idiomática, como um falante nativo".
    • +
    • Use o script nativo em vez de transliteração.
    • +
    • Considere contexto cultural e regional — comunicação eficaz costuma exigir mais do que tradução literal.
    • +
    +
    +

    Claude processa entrada e gera saída na maioria das línguas que usam caracteres Unicode padrão. Preserve acentuação (UTF-8) ponta a ponta.

    + + +
    + + +
    +

    12. Processamento em lote (Message Batches API)

    +

    A Message Batches API processa grandes volumes de requests de Mensagens de forma assíncrona, com 50% de desconto em entrada e saída e maior throughput. Ideal quando você não precisa de resposta imediata: avaliações em larga escala, moderação de conteúdo, análise de dados e geração em massa.

    + +

    Fluxo: (1) você cria um batch enviando uma lista de requests no parâmetro requests; (2) o sistema processa cada request independentemente e de forma assíncrona; (3) você faz polling do status e recupera os resultados ao término. Cada request tem um custom_id (1–64 caracteres, ^[a-zA-Z0-9_-]{1,64}$) e um objeto params com os parâmetros padrão da Messages API. Todos os modelos ativos suportam batches, e qualquer request da Messages API pode ser incluído (visão, tool use, system, multiturno, features beta — podendo misturar tipos no mesmo batch).

    + +
    +
    + + + +
    +
    +
    from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
    +from anthropic.types.messages.batch_create_params import Request
    +
    +batch = client.messages.batches.create(
    +    requests=[
    +        Request(
    +            custom_id="req-1",
    +            params=MessageCreateParamsNonStreaming(
    +                model="claude-opus-4-8", max_tokens=1024,
    +                messages=[{"role": "user", "content": "Olá, mundo"}],
    +            ),
    +        ),
    +        Request(
    +            custom_id="req-2",
    +            params=MessageCreateParamsNonStreaming(
    +                model="claude-opus-4-8", max_tokens=1024,
    +                messages=[{"role": "user", "content": "Olá de novo, amigo"}],
    +            ),
    +        ),
    +    ]
    +)
    +print(batch.id, batch.processing_status)
    +
    +# Recupera resultados (stream, eficiente em memória) ao término
    +for result in client.messages.batches.results(batch.id):
    +    if result.result.type == "succeeded":
    +        print(result.custom_id, "ok")
    +    elif result.result.type == "errored":
    +        print(result.custom_id, result.result.error)
    +
    +
    +
    const batch = await client.messages.batches.create({
    +  requests: [
    +    {
    +      custom_id: "req-1",
    +      params: { model: "claude-opus-4-8", max_tokens: 1024,
    +                messages: [{ role: "user", content: "Olá, mundo" }] },
    +    },
    +    {
    +      custom_id: "req-2",
    +      params: { model: "claude-opus-4-8", max_tokens: 1024,
    +                messages: [{ role: "user", content: "Olá de novo, amigo" }] },
    +    },
    +  ],
    +});
    +
    +for await (const result of await client.messages.batches.results(batch.id)) {
    +  if (result.result.type === "succeeded") console.log(result.custom_id, "ok");
    +}
    +
    +
    +
    curl https://api.anthropic.com/v1/messages/batches \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "requests": [
    +      {"custom_id": "req-1", "params": {"model": "claude-opus-4-8", "max_tokens": 1024,
    +        "messages": [{"role": "user", "content": "Olá, mundo"}]}},
    +      {"custom_id": "req-2", "params": {"model": "claude-opus-4-8", "max_tokens": 1024,
    +        "messages": [{"role": "user", "content": "Olá de novo, amigo"}]}}
    +    ]
    +  }'
    +
    +
    + +

    O processing_status começa em in_progress e vira ended quando todos os requests terminam; o objeto traz request_counts com contadores por estado (processing, succeeded, errored, canceled, expired). Os resultados ficam em results_url — prefira streamar em vez de baixar tudo de uma vez. Há quatro tipos de resultado:

    +
    + + + + + + + +
    TipoSignificadoCobrança
    succeededRequest bem-sucedido; inclui o resultado da mensagem.Cobrado
    erroredErro (request inválido ou erro interno). invalid_request_error exige corrigir o corpo; outros podem ser repetidos.Não cobrado
    canceledUsuário cancelou o batch antes deste request ser enviado.Não cobrado
    expiredBatch atingiu a expiração de 24h antes do envio.Não cobrado
    + +
    Atenção — limites: um batch é limitado a 100.000 requests ou 256 MB (o que vier primeiro). A maioria completa em menos de 1h; resultados ficam disponíveis quando tudo termina ou após 24h (o que vier primeiro) — batches que não completam em 24h expiram. Resultados ficam acessíveis para download por 29 dias. Batches têm escopo de Workspace. Cada request precisa de max_tokens ≥ 1 (max_tokens: 0 não é suportado em batch). A validação dos params é assíncrona — teste o formato com a Messages API primeiro.
    + +
    Dica: como batches podem levar mais de 5 minutos, use o cache de 1 hora (prompt caching) para melhores taxas de acerto ao processar batches com contexto compartilhado. Não é ZDR-elegível.
    + + +
    + + + + +
    +

    Parte B — Raciocínio, Caching, Contexto & Multimodal

    +

    Esta parte cobre como controlar o raciocínio do Claude (adaptive thinking, extended thinking, efforto, raciocínio com ferramentas e orçamentos de tarefa), como reduzir custo e latência com prompt caching e diagnósticos de cache, como gerenciar janelas de contexto longas (context editing e compaction) e como enviar conteúdo multimodal (imagens, PDFs, Files API) com citações verificáveis e resultados de busca para RAG.

    +
    + + +
    +

    1. Adaptive thinking (raciocínio adaptativo)

    +

    O adaptive thinking deixa o Claude decidir dinamicamente se vai raciocinar e quanto vai raciocinar, com base na complexidade de cada requisição — em vez de você fixar um orçamento de tokens de pensamento. É o modo recomendado de usar extended thinking nos modelos atuais e o único modo suportado no Claude Opus 4.8.

    + + +

    1.1. Quando usar

    +

    Adaptive thinking costuma superar o extended thinking de orçamento fixo em muitas cargas — sobretudo em tarefas bimodais (mistura de perguntas simples e difíceis) e em fluxos agênticos de horizonte longo, pois o modelo gasta raciocínio só onde compensa. Nenhum header beta é necessário. Se você precisa de latência previsível ou de controle preciso do custo de raciocínio, o extended thinking manual com budget_tokens ainda funciona no Claude Sonnet 4.6 (ver capítulo 2).

    + +

    1.2. Suporte por modelo

    +

    O modo de raciocínio e o suporte a effort variam por modelo. Para a tabela completa de capacidades dos modelos, veja Modelos Claude (Parte A).

    +
    + + + + + + +
    ModeloAdaptive thinkingeffortObservação
    claude-opus-4-8único modosim (inclui xhigh)Raciocínio desligado por padrão; ative com thinking: {type: "adaptive"}. type: "enabled" com budget_tokens é rejeitado com erro 400. Não expõe extended thinking manual.
    claude-sonnet-4-6suportadosimAceita adaptive + effort e também o modo manual enabled (ainda funcional).
    claude-haiku-4-5nãonãoUsa extended thinking manual: thinking: {type: "enabled", budget_tokens: N}. Não tem adaptive nem effort.
    +
    Atenção: o parâmetro effort está disponível em claude-opus-4-8, claude-sonnet-5 (ambos com xhigh e max) e claude-sonnet-4-6 (até max, sem xhigh); com adaptive thinking é o controle de profundidade recomendado, mas effort também funciona sem thinking, controlando o gasto geral da resposta. No claude-haiku-4-5 não há adaptive nem effort: controle o raciocínio apenas via budget_tokens (ver capítulo 2).
    + +

    1.3. Como usar

    +

    Defina thinking.type como "adaptive". No nível padrão de effort (high), o Claude quase sempre raciocina; em níveis mais baixos pode pular o raciocínio em perguntas simples.

    +
    +
    + + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +
    +response = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=16000,
    +    thinking={"type": "adaptive"},
    +    messages=[
    +        {
    +            "role": "user",
    +            "content": "Explique por que a soma de dois números pares é sempre par.",
    +        }
    +    ],
    +)
    +
    +for block in response.content:
    +    if block.type == "thinking":
    +        print(f"\nPensamento: {block.thinking}")
    +    elif block.type == "text":
    +        print(f"\nResposta: {block.text}")
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic();
    +
    +const response = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 16000,
    +  thinking: { type: "adaptive" },
    +  messages: [
    +    { role: "user", content: "Explique por que a soma de dois números pares é sempre par." },
    +  ],
    +});
    +
    +for (const block of response.content) {
    +  if (block.type === "thinking") console.log(`\nPensamento: ${block.thinking}`);
    +  else if (block.type === "text") console.log(`\nResposta: ${block.text}`);
    +}
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 16000,
    +    "thinking": { "type": "adaptive" },
    +    "messages": [
    +      { "role": "user", "content": "Explique por que a soma de dois números pares é sempre par." }
    +    ]
    +  }'
    +
    +
    + +

    1.4. Adaptive thinking com o parâmetro effort

    +

    Combine thinking: {type:"adaptive"} com output_config.effort para guiar (orientação soft) quanto o Claude raciocina. O effort só existe junto de adaptive thinking — portanto em claude-opus-4-8 e claude-sonnet-4-6; o claude-haiku-4-5 não o suporta (use budget_tokens). Para o panorama de capacidades por modelo, veja Modelos Claude (Parte A).

    +
    + + + + + + + + +
    effortComportamento de raciocínio
    maxSempre raciocina, sem restrição de profundidade. Em claude-opus-4-8 e claude-sonnet-4-6.
    xhighSempre raciocina profundamente com exploração estendida. Disponível em claude-opus-4-8.
    high (padrão)Sempre raciocina. Raciocínio profundo em tarefas complexas.
    mediumRaciocínio moderado; pode pular pensamento em perguntas muito simples.
    lowMinimiza o raciocínio; pula o pensamento em tarefas simples onde a velocidade importa.
    +
    +
    + + + +
    +
    +
    response = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=16000,
    +    thinking={"type": "adaptive"},
    +    output_config={"effort": "medium"},
    +    messages=[{"role": "user", "content": "Qual é a capital da França?"}],
    +)
    +print(response.content[0].text)
    +
    +
    +
    const response = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 16000,
    +  thinking: { type: "adaptive" },
    +  output_config: { effort: "medium" },
    +  messages: [{ role: "user", content: "Qual é a capital da França?" }],
    +});
    +console.log(response.content[0].text);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 16000,
    +    "thinking": { "type": "adaptive" },
    +    "output_config": { "effort": "medium" },
    +    "messages": [ { "role": "user", "content": "Qual é a capital da França?" } ]
    +  }'
    +
    +
    + +

    1.5. Considerações importantes

    +
      +
    • Interleaved thinking automático: o modo adaptive ativa automaticamente o raciocínio intercalado entre chamadas de ferramenta — ideal para fluxos agênticos. No Opus 4.8, o raciocínio entre ferramentas sempre vive dentro de blocos thinking.
    • +
    • Validação mais flexível: turnos anteriores do assistente não precisam começar com um bloco thinking (no modo manual a API exige isso).
    • +
    • Prompt caching: requisições consecutivas com o mesmo modo (adaptive) preservam os breakpoints de cache. Alternar entre adaptive e enabled/disabled quebra os breakpoints das mensagens (system prompt e definições de ferramenta continuam em cache).
    • +
    • Display padrão no Opus 4.8: thinking.display assume "omitted" por padrão (mudança silenciosa em relação ao comportamento anterior). Para receber o resumo do pensamento, defina display: "summarized" explicitamente. Veja o capítulo 2.
    • +
    • Controle de custo: use max_tokens como limite rígido do total de saída (pensamento + texto). Em high/max o modelo pode esgotar max_tokens; se vir stop_reason: "max_tokens", aumente max_tokens ou reduza o effort.
    • +
    +
    Dica: o disparo do raciocínio é promptável. Se o Claude raciocina demais (ou de menos), oriente no system prompt — por exemplo: “Use raciocínio estendido apenas quando melhorar de forma significativa a qualidade da resposta; na dúvida, responda diretamente.” Meça o impacto antes de levar para produção.
    +
    + + +
    +

    2. Extended thinking (raciocínio estendido) e blocos de pensamento

    +

    O extended thinking dá ao Claude uma fase de raciocínio interno antes da resposta final. Você pode controlá-lo de forma adaptativa (cap. 1) ou manual com um orçamento de tokens. Este capítulo detalha o modo manual, a exibição/criptografia dos blocos de pensamento e a preservação dos blocos entre turnos.

    + + +

    2.1. Modos de raciocínio

    +
    + + + + + + +
    ModoConfigDisponibilidadeQuando usar
    Adaptivethinking: {type: "adaptive"}claude-opus-4-8 (único modo), claude-sonnet-4-6. Não em claude-haiku-4-5.O Claude decide quando/quanto raciocinar. Use effort para guiar.
    Manualthinking: {type: "enabled", budget_tokens: N}claude-sonnet-4-6 (ainda funcional) e claude-haiku-4-5 (único modo de raciocínio do Haiku). Rejeitado em claude-opus-4-8 (400).Quando você precisa de controle preciso do gasto de tokens de pensamento.
    DisabledOmitir thinking ou {type: "disabled"}Todos os modelosQuando não precisa de raciocínio e quer a menor latência.
    + +

    2.2. Modo manual (orçamento fixo)

    +

    No modo manual você define budget_tokens — o número alvo de tokens que o Claude pode usar para raciocinar. Deve ser menor que max_tokens (o max_tokens cobre pensamento + texto da resposta). Exemplo no Sonnet 4.6:

    +
    +
    + + + +
    +
    +
    response = client.messages.create(
    +    model="claude-sonnet-4-6",
    +    max_tokens=16000,
    +    thinking={"type": "enabled", "budget_tokens": 10000},
    +    messages=[{"role": "user", "content": "Quantos números primos há entre 100 e 200?"}],
    +)
    +
    +
    +
    const response = await client.messages.create({
    +  model: "claude-sonnet-4-6",
    +  max_tokens: 16000,
    +  thinking: { type: "enabled", budget_tokens: 10000 },
    +  messages: [{ role: "user", content: "Quantos números primos há entre 100 e 200?" }],
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-sonnet-4-6",
    +    "max_tokens": 16000,
    +    "thinking": { "type": "enabled", "budget_tokens": 10000 },
    +    "messages": [ { "role": "user", "content": "Quantos números primos há entre 100 e 200?" } ]
    +  }'
    +
    +
    +
    Nota: no Claude Opus 4.8 o modo manual enabled é rejeitado (erro 400). Use sempre adaptive + effort nesse modelo.
    + +

    2.3. Thinking resumido (summarized)

    +

    Com extended thinking ativo, a Messages API retorna um resumo do raciocínio completo (não o texto bruto de pensamento), preservando os ganhos de inteligência e prevenindo uso indevido. Pontos-chave:

    +
      +
    • Você é cobrado pelos tokens completos de pensamento gerados, não pelos tokens do resumo. A contagem de tokens de saída faturada não bate com os tokens visíveis na resposta.
    • +
    • A sumarização é feita por um modelo diferente do que você chamou; o modelo de raciocínio não vê o resumo.
    • +
    • O resumo preserva as ideias-chave com latência adicional mínima e é streamável.
    • +
    + +

    2.4. Controlando a exibição: thinking.display

    +

    O campo display controla como o conteúdo de pensamento volta na resposta:

    +
    + + + + + +
    ValorComportamentoPadrão em
    "summarized"Blocos contêm o texto resumido do pensamento.Sonnet 4.6 e modelos Claude 4 anteriores (default nessas gerações)
    "omitted"Blocos voltam com thinking vazio; o campo signature ainda carrega o pensamento completo criptografado para continuidade multi-turno.Default em claude-opus-4-8, claude-opus-4-7, claude-sonnet-5, claude-fable-5 e claude-mythos-5
    +
    Atenção (mudança silenciosa): nos modelos mais novos — claude-opus-4-8, claude-opus-4-7, claude-sonnet-5, claude-fable-5 e claude-mythos-5 — display é "omitted" por padrão (era "summarized" em Opus 4.6 / Sonnet 4.6): os blocos de pensamento aparecem no stream, mas com thinking vazio. Quem migra de Sonnet 4.6 para Sonnet 5 esperando ver o raciocínio precisa definir explicitamente display: "summarized". display é inválido com thinking.type: "disabled". Mesmo com "omitted", você continua sendo cobrado pelos tokens completos de pensamento — omitir reduz latência, não custo.
    +
    # Restaurar resumo do pensamento no Opus 4.8:
    +thinking = {"type": "adaptive", "display": "summarized"}
    +
    +# Omitir (default no Opus 4.8) — menor time-to-first-text-token no streaming:
    +thinking = {"type": "adaptive", "display": "omitted"}
    + +

    2.5. Criptografia e signature

    +

    O conteúdo completo de pensamento é criptografado e devolvido no campo signature, usado para verificar que os blocos foram gerados pelo Claude quando você os reenvia. Considerações:

    +
      +
    • No streaming, a signature chega via signature_delta dentro de um content_block_delta, logo antes do content_block_stop.
    • +
    • signature é um campo opaco — não interprete nem faça parsing.
    • +
    • Valores de signature são compatíveis entre plataformas (Claude API, Amazon Bedrock e Vertex AI).
    • +
    +
    Nota: só é estritamente necessário reenviar blocos de pensamento quando se usa ferramentas com extended thinking (ver capítulo 3). Caso reenvie, passe tudo exatamente como recebeu.
    + +

    2.6. Redacted thinking

    +

    Ocasionalmente o raciocínio interno é sinalizado pelos sistemas de segurança e volta criptografado como um bloco redacted_thinking (em vez de thinking). Ele é decriptado quando reenviado ao modelo. Trate-o como um bloco normal: reenvie-o sem modificação em conversas multi-turno; ele não afeta a qualidade das respostas.

    + +

    2.7. Preservação de blocos de pensamento entre turnos

    +

    Se você reenvia blocos de pensamento, o que a API mantém em contexto depende do modelo:

    +
    + + + + + + +
    ModeloBlocos de pensamento de turnos anteriores
    claude-opus-4-8Mantidos em contexto por padrão (todos os turnos).
    claude-sonnet-4-6Mantidos em contexto por padrão (todos os turnos).
    claude-haiku-4-5Removidos (stripped) por padrão.
    +

    Use context editing para configurar esse comportamento. O faturamento de tokens de pensamento mantidos em contexto conta como tokens de input nos turnos seguintes.

    + +

    2.8. max_tokens, janela de contexto e stop_reason

    +

    O max_tokens limita o total de saída (pensamento + texto). Se o raciocínio mais a resposta atingirem o limite, a resposta volta com stop_reason: "max_tokens" e o texto pode ficar truncado. Em effort alto, deixe folga em max_tokens. Sobre o tamanho da janela e a contabilidade de tokens, veja janelas de contexto; sobre os demais valores de término, veja stop_reason (Parte A).

    +
    + + +
    +

    3. Raciocínio com uso de ferramentas (extended thinking + tool use)

    +

    Ao combinar raciocínio com tool use, há uma regra central: você deve reenviar os blocos de pensamento do turno do assistente — sem modificá-los — junto com o bloco tool_use, para que o Claude continue o raciocínio de onde parou ao receber o tool_result.

    + + +

    3.1. O ciclo com preservação de pensamento

    +
      +
    1. Você envia a mensagem do usuário com thinking ativo e as tools definidas.
    2. +
    3. O assistente responde com um ou mais blocos thinking seguidos de um bloco tool_use (stop_reason: "tool_use").
    4. +
    5. Você executa a ferramenta e devolve um turno user com o bloco tool_result.
    6. +
    7. No próximo turno do assistente, você reenvia o turno anterior do assistente incluindo os blocos de pensamento intactos (com sua signature).
    8. +
    +
    Atenção: não edite, reordene nem remova os blocos de pensamento ao reenviá-los. A API valida a signature; alterações causam erro. No claude-opus-4-8 (e no modo adaptive em geral), o interleaved thinking é automático — o Claude pode raciocinar entre múltiplas chamadas de ferramenta.
    + +

    3.2. Exemplo: continuação após tool_result

    +
    +
    + + + +
    +
    +
    tools = [{
    +    "name": "get_weather",
    +    "description": "Obtém o clima atual de uma cidade.",
    +    "input_schema": {
    +        "type": "object",
    +        "properties": {"city": {"type": "string"}},
    +        "required": ["city"],
    +    },
    +}]
    +
    +# 1) Primeira chamada — Claude raciocina e pede a ferramenta
    +first = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=16000,
    +    thinking={"type": "adaptive"},
    +    tools=tools,
    +    messages=[{"role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?"}],
    +)
    +
    +# 2) Execute a ferramenta e devolva o turno do assistente INTACTO (com os blocos thinking)
    +tool_use = next(b for b in first.content if b.type == "tool_use")
    +second = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=16000,
    +    thinking={"type": "adaptive"},
    +    tools=tools,
    +    messages=[
    +        {"role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?"},
    +        {"role": "assistant", "content": first.content},  # blocos thinking + tool_use preservados
    +        {
    +            "role": "user",
    +            "content": [{
    +                "type": "tool_result",
    +                "tool_use_id": tool_use.id,
    +                "content": "Chuva forte prevista para a tarde.",
    +            }],
    +        },
    +    ],
    +)
    +print(second.content[-1].text)
    +
    +
    +
    const tools = [{
    +  name: "get_weather",
    +  description: "Obtém o clima atual de uma cidade.",
    +  input_schema: {
    +    type: "object",
    +    properties: { city: { type: "string" } },
    +    required: ["city"],
    +  },
    +}];
    +
    +const first = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 16000,
    +  thinking: { type: "adaptive" },
    +  tools,
    +  messages: [{ role: "user", content: "Devo levar guarda-chuva em São Paulo hoje?" }],
    +});
    +
    +const toolUse = first.content.find((b) => b.type === "tool_use");
    +const second = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 16000,
    +  thinking: { type: "adaptive" },
    +  tools,
    +  messages: [
    +    { role: "user", content: "Devo levar guarda-chuva em São Paulo hoje?" },
    +    { role: "assistant", content: first.content }, // thinking + tool_use intactos
    +    {
    +      role: "user",
    +      content: [{
    +        type: "tool_result",
    +        tool_use_id: toolUse.id,
    +        content: "Chuva forte prevista para a tarde.",
    +      }],
    +    },
    +  ],
    +});
    +
    +
    +
    # O turno do assistente (content) deve conter os blocos thinking originais
    +# com sua signature, seguidos do bloco tool_use, e depois o tool_result do usuário.
    +curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 16000,
    +    "thinking": { "type": "adaptive" },
    +    "tools": [ { "name": "get_weather", "input_schema": {"type":"object","properties":{"city":{"type":"string"}},"required":["city"]} } ],
    +    "messages": [
    +      { "role": "user", "content": "Devo levar guarda-chuva em São Paulo hoje?" },
    +      { "role": "assistant", "content": [ {"type":"thinking","thinking":"...","signature":"..."}, {"type":"tool_use","id":"toolu_01","name":"get_weather","input":{"city":"São Paulo"}} ] },
    +      { "role": "user", "content": [ {"type":"tool_result","tool_use_id":"toolu_01","content":"Chuva forte prevista para a tarde."} ] }
    +    ]
    +  }'
    +
    +
    + +

    3.3. Interleaved thinking

    +

    O interleaved thinking permite ao Claude raciocinar entre chamadas de ferramenta — refletindo sobre o resultado de uma ferramenta antes de decidir a próxima. Disponibilidade:

    +
    + + + + + +
    ConfiguraçãoInterleaved thinking
    Adaptive em claude-opus-4-8 / claude-sonnet-4-6Automático (sem header beta).
    Manual (enabled) em claude-sonnet-4-6Via header anthropic-beta: interleaved-thinking-2025-05-14.
    + +

    3.4. tool_choice e raciocínio

    +

    Quando o raciocínio está ativo, há limitações com tool_choice: você não pode forçar uma ferramenta específica (tool_choice: {type: "tool", ...}) nem tool_choice: {type: "any"} de forma incompatível com o pensamento. Use tool_choice: {type: "auto"} (padrão) com raciocínio ativo e deixe o Claude decidir.

    +
    + + +
    +

    4. Orçamentos de tarefa (task budgets)

    +

    Os task budgets definem um teto de tokens para uma tarefa inteira — somando múltiplas requisições/turnos de um fluxo agêntico — em vez de limitar token a token por chamada. Servem para controlar custo e horizonte de tarefas longas com ferramentas.

    + +

    Beta Requer o header anthropic-beta: task-budgets-2026-03-13 (verificado em 2026-06-10). Apenas Claude Opus 4.8 — não suportado em Sonnet 4.6 nem Haiku 4.5. Defina output_config.task_budget = {"type":"tokens","total": N} (campo opcional remaining para retomar após compactação). O mínimo é 20.000 tokens (valores menores retornam 400); o orçamento é advisory (hint suave), enquanto max_tokens continua sendo o teto rígido por requisição.

    + +

    4.1. Como usar

    +

    Defina output_config.task_budget com o tipo e o total. Combine com effort para orientar a alocação de raciocínio dentro do orçamento. No SDK Python, use o namespace client.beta.messages e passe betas=[...].

    +
    +
    + + + +
    +
    +
    message = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=16000,
    +    thinking={"type": "adaptive"},
    +    output_config={
    +        "effort": "high",
    +        "task_budget": {"type": "tokens", "total": 64000},
    +    },
    +    betas=["task-budgets-2026-03-13"],
    +    messages=[{"role": "user", "content": "Refatore este módulo e rode os testes."}],
    +)
    +
    +
    +
    const message = await client.beta.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 16000,
    +  thinking: { type: "adaptive" },
    +  output_config: {
    +    effort: "high",
    +    task_budget: { type: "tokens", total: 64000 },
    +  },
    +  betas: ["task-budgets-2026-03-13"],
    +  messages: [{ role: "user", content: "Refatore este módulo e rode os testes." }],
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "anthropic-beta: task-budgets-2026-03-13" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 16000,
    +    "thinking": { "type": "adaptive" },
    +    "output_config": {
    +      "effort": "high",
    +      "task_budget": { "type": "tokens", "total": 64000 }
    +    },
    +    "messages": [ { "role": "user", "content": "Refatore este módulo e rode os testes." } ]
    +  }'
    +
    +
    +
    Dica: diferencie os três controles: max_tokens limita a saída de uma requisição; task_budget limita o consumo da tarefa toda (várias requisições); effort é orientação soft de quanto raciocinar. Use os três juntos para custo previsível em agentes de horizonte longo.
    +
    + + +
    +

    5. Prompt caching (cache de prompt)

    +

    O prompt caching permite reutilizar prefixos grandes e estáveis do prompt (system prompt extenso, definições de ferramenta, documentos, exemplos few-shot) entre requisições, cortando custo e latência drasticamente. Você marca pontos de cache (breakpoints) com cache_control.

    + + +

    5.1. Mínimos de tokens cacheáveis (por modelo)

    +

    Prompts menores que o mínimo são processados sem cache e nenhum erro é retornado. Verifique usage.cache_creation_input_tokens e usage.cache_read_input_tokens: se ambos forem 0, o prompt não foi cacheado.

    +
    + + + + + + +
    ModeloMínimo de tokens cacheáveis
    claude-opus-4-84.096 tokens
    claude-sonnet-4-61.024 tokens
    claude-haiku-4-54.096 tokens
    + +

    5.2. TTL e preços

    +
    + + + + + + +
    Tipo de tokenMultiplicador vs. preço base de input
    Cache write (TTL 5 min, padrão)1,25× (refrescado sem custo extra a cada uso)
    Cache write (TTL 1 h)2× (opt-in com "ttl": "1h")
    Cache hit / refresh (read)0,1× (10% do preço base)
    +

    Exemplo para claude-opus-4-8 ($5/MTok base): cache write 5m = $6,25/MTok; cache write 1h = $10/MTok; cache read = $0,50/MTok.

    + +

    5.3. Caching automático (breakpoint no nível superior)

    +

    Adicione um único cache_control no nível superior do corpo da requisição. A API aplica o breakpoint ao último bloco cacheável e move o breakpoint para a frente automaticamente conforme a conversa cresce.

    +
    +
    + + + +
    +
    +
    response = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    cache_control={"type": "ephemeral"},  # breakpoint automático no último bloco cacheável
    +    system="Você é um assistente jurídico... (system prompt longo e estável)",
    +    messages=[{"role": "user", "content": "Resuma o contrato anexo."}],
    +)
    +print(response.usage.cache_creation_input_tokens, response.usage.cache_read_input_tokens)
    +
    +
    +
    const response = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  cache_control: { type: "ephemeral" }, // breakpoint automático
    +  system: "Você é um assistente jurídico... (system prompt longo e estável)",
    +  messages: [{ role: "user", content: "Resuma o contrato anexo." }],
    +});
    +console.log(response.usage.cache_creation_input_tokens, response.usage.cache_read_input_tokens);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "cache_control": { "type": "ephemeral" },
    +    "system": "Você é um assistente jurídico... (system prompt longo e estável)",
    +    "messages": [ { "role": "user", "content": "Resuma o contrato anexo." } ]
    +  }'
    +
    +
    +
    Nota: caching automático está disponível na Claude API e na Claude Platform na AWS / Microsoft Foundry (beta). Não é suportado em Amazon Bedrock nem Vertex AI (use breakpoints explícitos lá).
    + +

    5.4. Breakpoints explícitos em blocos de conteúdo

    +

    Para controle fino, coloque cache_control diretamente em blocos específicos (system, tools, document, etc.). Há no máximo 4 breakpoints por requisição. Tudo antes de um breakpoint (inclusive) entra no prefixo cacheável.

    +
    {
    +  "model": "claude-opus-4-8",
    +  "max_tokens": 1024,
    +  "tools": [ { "name": "...", "cache_control": { "type": "ephemeral" } } ],
    +  "system": [
    +    { "type": "text", "text": "Instruções base..." },
    +    { "type": "text", "text": "Base de conhecimento longa...", "cache_control": { "type": "ephemeral" } }
    +  ],
    +  "messages": [ { "role": "user", "content": "..." } ]
    +}
    + +

    5.5. TTL de 1 hora

    +
    { "cache_control": { "type": "ephemeral", "ttl": "1h" } }
    +

    Útil para prefixos reaproveitados ao longo de minutos a uma hora (ex.: documento grande consultado várias vezes). Custa 2× o input base na escrita, mas economiza em muitas leituras subsequentes (0,1×).

    + +

    5.6. Pré-aquecimento (pre-warming) do cache

    +

    Para garantir que o prefixo já esteja em cache antes do primeiro uso real, faça uma requisição de aquecimento com max_tokens mínimo. Isso paga a escrita do cache uma vez e deixa as leituras seguintes baratas.

    +
    # Aquece o cache do prefixo sem gerar resposta longa
    +client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1,
    +    cache_control={"type": "ephemeral"},
    +    system="... prefixo grande e estável ...",
    +    messages=[{"role": "user", "content": "ok"}],
    +)
    + +

    5.7. Pegadinhas (edge cases)

    +
      +
    • Se o último bloco já tem cache_control explícito com o mesmo TTL do automático → no-op.
    • +
    • Se o último bloco tem cache_control explícito com TTL diferente → erro 400.
    • +
    • Se os 4 slots de breakpoint explícito já estão usados → erro 400 ao adicionar o automático.
    • +
    • Misturar TTLs: você pode ter breakpoints de 5m e 1h na mesma requisição, mas planeje a ordem (o prefixo mais estável com TTL maior).
    • +
    +
    Atenção: mudanças antes de um breakpoint invalidam o cache daquele ponto em diante. Mantenha conteúdo volátil (a pergunta do usuário) depois dos breakpoints e conteúdo estável (system, tools, documentos) antes.
    +
    + + +
    +

    6. Diagnóstico de cache (cache diagnostics)

    +

    Quando o cache não está acertando como esperado, os diagnósticos de cache explicam por que houve cache miss, comparando a requisição atual com a anterior e apontando o primeiro ponto de divergência (modelo, system prompt, tools ou histórico de mensagens).

    + +

    Beta Requer o header anthropic-beta: cache-diagnosis-2026-04-07 (verificado em 2026-05-24). Passe o id da resposta anterior em diagnostics.previous_message_id; a API retorna um objeto diagnostics descrevendo a divergência. Disponível apenas na Claude API — não suportado em Amazon Bedrock nem Vertex AI.

    + +

    6.1. Como usar

    +

    Passe diagnostics com o previous_message_id da requisição anterior (ou None na primeira). A resposta inclui um cache_miss_reason indicando onde o prefixo divergiu.

    +
    +
    + + + +
    +
    +
    message = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    diagnostics={"previous_message_id": None},  # ou o id da resposta anterior
    +    betas=["cache-diagnosis-2026-04-07"],
    +    cache_control={"type": "ephemeral"},
    +    system="... prefixo grande ...",
    +    messages=[{"role": "user", "content": "Continue."}],
    +)
    +# Inspecione o motivo de eventual cache miss
    +print(getattr(message, "cache_miss_reason", None))
    +
    +
    +
    const message = await client.beta.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  diagnostics: { previous_message_id: null }, // ou o id da resposta anterior
    +  betas: ["cache-diagnosis-2026-04-07"],
    +  cache_control: { type: "ephemeral" },
    +  system: "... prefixo grande ...",
    +  messages: [{ role: "user", content: "Continue." }],
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "anthropic-beta: cache-diagnosis-2026-04-07" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "diagnostics": { "previous_message_id": null },
    +    "cache_control": { "type": "ephemeral" },
    +    "system": "... prefixo grande ...",
    +    "messages": [ { "role": "user", "content": "Continue." } ]
    +  }'
    +
    +
    +
    Dica: as causas mais comuns de cache miss são: alterar conteúdo antes de um breakpoint, alternar o modo de thinking (adaptive ↔ enabled/disabled) nas mensagens, ou ficar abaixo do mínimo de tokens cacheáveis do modelo. Use o cache_miss_reason para localizar exatamente o ponto de divergência.
    +
    + + +
    +

    7. Edição de contexto (context editing)

    +

    A edição de contexto remove automaticamente conteúdo antigo da janela quando ela cresce demais — por exemplo, resultados de ferramentas já consumidos e blocos de pensamento antigos — preservando os mais recentes. Mantém agentes de horizonte longo dentro da janela sem você gerenciar o histórico manualmente.

    + +

    Beta Requer o header anthropic-beta: context-management-2025-06-27.

    + +

    7.1. Tipos de edição

    +
    + + + + + +
    Tipo de editO que limpa
    clear_tool_uses_20250919Resultados de uso de ferramentas (tool_use/tool_result) antigos.
    clear_thinking_20251015Blocos de pensamento (thinking) antigos.
    + +

    7.2. Parâmetros de um edit clear_tool_uses

    +
    + + + + + + + +
    CampoDescrição
    triggerQuando acionar a limpeza, ex. {"type": "input_tokens", "value": 30000}.
    keepQuanto preservar, ex. {"type": "tool_uses", "value": 3} (mantém os 3 usos de ferramenta mais recentes).
    clear_at_leastMínimo a limpar por acionamento (evita limpezas insignificantes).
    exclude_toolsLista de ferramentas cujos resultados nunca devem ser limpos.
    + +

    7.3. Exemplo

    +
    +
    + + + +
    +
    +
    message = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=16000,
    +    betas=["context-management-2025-06-27"],
    +    context_management={
    +        "edits": [
    +            {
    +                "type": "clear_tool_uses_20250919",
    +                "trigger": {"type": "input_tokens", "value": 30000},
    +                "keep": {"type": "tool_uses", "value": 3},
    +                "clear_at_least": {"type": "input_tokens", "value": 5000},
    +                "exclude_tools": ["get_critical_state"],
    +            },
    +            {"type": "clear_thinking_20251015"},
    +        ]
    +    },
    +    tools=[...],
    +    messages=[...],
    +)
    +
    +
    +
    const message = await client.beta.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 16000,
    +  betas: ["context-management-2025-06-27"],
    +  context_management: {
    +    edits: [
    +      {
    +        type: "clear_tool_uses_20250919",
    +        trigger: { type: "input_tokens", value: 30000 },
    +        keep: { type: "tool_uses", value: 3 },
    +        clear_at_least: { type: "input_tokens", value: 5000 },
    +        exclude_tools: ["get_critical_state"],
    +      },
    +      { type: "clear_thinking_20251015" },
    +    ],
    +  },
    +  tools: [/* ... */],
    +  messages: [/* ... */],
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "anthropic-beta: context-management-2025-06-27" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 16000,
    +    "context_management": {
    +      "edits": [
    +        {
    +          "type": "clear_tool_uses_20250919",
    +          "trigger": { "type": "input_tokens", "value": 30000 },
    +          "keep": { "type": "tool_uses", "value": 3 },
    +          "clear_at_least": { "type": "input_tokens", "value": 5000 },
    +          "exclude_tools": ["get_critical_state"]
    +        },
    +        { "type": "clear_thinking_20251015" }
    +      ]
    +    },
    +    "messages": [ ... ]
    +  }'
    +
    +
    +
    Atenção: limpar conteúdo invalida os breakpoints de cache a partir do ponto editado, pois o prefixo muda. Posicione o context editing levando em conta o cache. Use exclude_tools para nunca descartar resultados de ferramentas que carregam estado crítico (ex.: identificadores ou saldos que o agente ainda precisará).
    +
    + + +
    +

    8. Compactação de contexto (compaction)

    +

    A compaction resume automaticamente o histórico antigo da conversa em uma forma condensada quando o contexto cresce, preservando as informações essenciais e liberando espaço — diferente do context editing, que remove blocos; a compaction resume. Sobre o tamanho da janela de contexto que esses mecanismos protegem, veja a Parte A.

    + +

    Beta Requer o header anthropic-beta: compact-2026-01-12 (verificado em 2026-05-24). É distinto do header de context editing context-management-2025-06-27.

    + +

    8.1. Como usar

    +

    Adicione um edit do tipo compact_20260112 em context_management.edits. A compaction pode coexistir com edits de limpeza (cap. 7).

    +
    +
    + + + +
    +
    +
    message = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=16000,
    +    betas=["compact-2026-01-12"],
    +    context_management={"edits": [{"type": "compact_20260112"}]},
    +    messages=[...],  # histórico longo de conversa agêntica
    +)
    +
    +
    +
    const message = await client.beta.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 16000,
    +  betas: ["compact-2026-01-12"],
    +  context_management: { edits: [{ type: "compact_20260112" }] },
    +  messages: [/* histórico longo */],
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "anthropic-beta: compact-2026-01-12" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 16000,
    +    "context_management": { "edits": [ { "type": "compact_20260112" } ] },
    +    "messages": [ ... ]
    +  }'
    +
    +
    +
    Dica: use compaction para agentes que rodam por muitas dezenas de turnos (programação, pesquisa, automação) onde o histórico bruto explodiria a janela mas o significado precisa ser preservado. Para contextos onde só os blocos recentes importam e os antigos podem ser descartados sem resumir, prefira context editing (mais barato). Os dois podem ser combinados.
    +
    + + +
    +

    9. Visão (entendimento de imagens)

    +

    As capacidades de visão deixam o Claude entender e analisar imagens: descrever cenas, ler texto, interpretar gráficos/diagramas, comparar várias imagens e dar suporte a computer use e leitura de telas.

    + + +

    9.1. Limites

    +
    + + + + + + + + +
    LimiteValor
    Imagens por requisição (API, modelos com janela de 200k)100
    Imagens por requisição (API, demais modelos)600
    Dimensões máximas por imagem8000×8000 px (reduz para 2000×2000 px se > 20 imagens na requisição)
    Formatos suportadosJPEG, PNG, GIF, WebP (animações: só o 1º frame é usado)
    Tamanho máximo da requisição32 MB (endpoints padrão; menor em algumas plataformas parceiras)
    +
    Nota: mesmo com a Files API, requisições com muitas imagens grandes podem falhar antes de atingir 600 imagens por causa do limite de tamanho do payload. Reduza dimensões/tamanho (downsampling) ou referencie por file_id.
    + +

    9.2. Custo de tokens por imagem

    +

    Uma imagem usa aproximadamente width * height / 750 tokens (em pixels). Se exceder a resolução nativa do modelo, é redimensionada preservando o aspect ratio e preenchida (padding) até múltiplos de 28 px.

    +
    + + + + + +
    ModeloResolução nativa máximaTokens máximos por imagem
    claude-opus-4-8até 2576 px na borda longa~4784 tokens (alta resolução)
    claude-sonnet-4-6 / claude-haiku-4-5até 1568 px na borda longa~1568 tokens
    +
    Dica: o suporte a alta resolução (até 2576 px na borda longa) foi introduzido no Opus 4.7 e segue no claude-opus-4-8 — automático e sem header beta — ótimo para computer use, leitura de screenshots e análise de documentos. Mas pode usar até ~3× mais tokens por imagem (4784 vs. 1568). Se não precisa da fidelidade extra, faça downsampling antes de enviar para controlar custo.
    + +

    9.3. Fontes de imagem e exemplo

    +

    Há três formas de fornecer imagens: base64, url e file (via Files API — ver capítulo 11). Coloque imagens antes do texto para melhores resultados.

    +
    +
    + + + +
    +
    +
    import anthropic, base64, httpx
    +
    +client = anthropic.Anthropic()
    +
    +url = "https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
    +img_data = base64.standard_b64encode(httpx.get(url).content).decode("utf-8")
    +
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": img_data}},
    +            {"type": "text", "text": "O que há nesta imagem?"},
    +        ],
    +    }],
    +)
    +print(message.content[0].text)
    +
    +
    +
    // Opção mais simples: imagem por URL
    +const message = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{
    +    role: "user",
    +    content: [
    +      { type: "image", source: { type: "url", url: "https://exemplo.com/foto.jpg" } },
    +      { type: "text", text: "O que há nesta imagem?" },
    +    ],
    +  }],
    +});
    +console.log(message.content[0].text);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{
    +      "role": "user",
    +      "content": [
    +        { "type": "image", "source": { "type": "url", "url": "https://exemplo.com/foto.jpg" } },
    +        { "type": "text", "text": "O que há nesta imagem?" }
    +      ]
    +    }]
    +  }'
    +
    +
    +
    Nota: em Amazon Bedrock e Vertex AI, apenas fontes base64 estão disponíveis atualmente. Ao pedir coordenadas (pontos, bounding boxes), elas vêm em relação à imagem redimensionada/com padding — reescale no cliente.
    +
    + + +
    +

    10. Suporte a PDF

    +

    O Claude processa PDFs entendendo texto e elementos visuais (gráficos, tabelas, diagramas): cada página é convertida em imagem e tem o texto extraído, e o modelo analisa ambos. Útil para relatórios financeiros, documentos jurídicos, tradução e extração estruturada.

    + + +

    10.1. Requisitos e limites

    +
    + + + + + + +
    RequisitoLimite
    Tamanho máximo da requisição32 MB (varia por plataforma)
    Máximo de páginas por requisição600 (100 para modelos com janela de 200k tokens)
    FormatoPDF padrão, sem senha/criptografia
    +

    Os limites valem para o payload inteiro (PDF + qualquer outro conteúdo). Como o suporte a PDF usa as capacidades de visão, está sujeito às mesmas limitações da visão. Todos os modelos ativos suportam PDF.

    + +

    10.2. Custo (estimativa de tokens)

    +
      +
    • Texto: tipicamente 1.500–3.000 tokens por página, conforme densidade. Sem taxa adicional de PDF.
    • +
    • Imagem: como cada página vira imagem, aplica-se o mesmo cálculo de tokens da visão.
    • +
    +
    Atenção: PDFs densos (fontes pequenas, tabelas complexas, muitos gráficos) podem encher a janela de contexto antes de atingir o limite de páginas. Divida o documento em seções; para arquivos grandes, faça downsampling das imagens embutidas. Use a Files API para manter o payload pequeno.
    + +

    10.3. Três formas de enviar um PDF

    +

    Via url, base64 ou file_id (Files API). Coloque o PDF antes do texto.

    +
    +
    + + + +
    +
    +
    # Opção 1: PDF por URL (mais simples)
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "document", "source": {"type": "url", "url": "https://exemplo.com/relatorio.pdf"}},
    +            {"type": "text", "text": "Quais são as conclusões principais deste documento?"},
    +        ],
    +    }],
    +)
    +print(message.content)
    +
    +
    +
    // Opção 1: PDF por URL
    +const response = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{
    +    role: "user",
    +    content: [
    +      { type: "document", source: { type: "url", url: "https://exemplo.com/relatorio.pdf" } },
    +      { type: "text", text: "Quais são as conclusões principais deste documento?" },
    +    ],
    +  }],
    +});
    +console.log(response);
    +
    +
    +
    # Opção 2: PDF em base64
    +curl https://api.anthropic.com/v1/messages \
    +  -H "content-type: application/json" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -d '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{
    +      "role": "user",
    +      "content": [
    +        { "type": "document", "source": { "type": "base64", "media_type": "application/pdf", "data": "JVBERi0xLj..." } },
    +        { "type": "text", "text": "Quais são as conclusões principais deste documento?" }
    +      ]
    +    }]
    +  }'
    +
    +
    + +

    10.4. PDF via Files API + prompt caching

    +

    Para PDFs reutilizados, faça upload uma vez (Files API, cap. 11) e referencie por file_id; combine com prompt caching colocando cache_control no bloco document.

    +
    # PDF via Files API (beta) — depois referencie por file_id
    +with open("relatorio.pdf", "rb") as f:
    +    up = client.beta.files.upload(file=("relatorio.pdf", f, "application/pdf"))
    +
    +message = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    betas=["files-api-2025-04-14"],
    +    messages=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "document", "source": {"type": "file", "file_id": up.id},
    +             "cache_control": {"type": "ephemeral"}},
    +            {"type": "text", "text": "Resuma o documento."},
    +        ],
    +    }],
    +)
    +
    Nota: em Amazon Bedrock e Vertex AI, apenas fontes base64 estão disponíveis. No Bedrock Converse API, a análise visual completa do PDF exige citações habilitadas; sem isso, há apenas extração de texto.
    +
    + + +
    +

    11. Files API

    +

    A Files API permite fazer upload de arquivos (PDFs, imagens, e outros formatos) uma vez e referenciá-los por file_id em várias requisições — evitando reenviar base64, reduzindo o payload e a latência.

    + +

    Beta Requer o header anthropic-beta: files-api-2025-04-14. No SDK, use o namespace client.beta.files e passe betas=["files-api-2025-04-14"] nas chamadas de mensagem.

    + +

    11.1. Upload e uso

    +
    +
    + + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +
    +# 1) Upload
    +with open("document.pdf", "rb") as f:
    +    file_upload = client.beta.files.upload(file=("document.pdf", f, "application/pdf"))
    +
    +# 2) Referencie por file_id em uma mensagem
    +message = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    betas=["files-api-2025-04-14"],
    +    messages=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "document", "source": {"type": "file", "file_id": file_upload.id}},
    +            {"type": "text", "text": "Quais são as conclusões principais?"},
    +        ],
    +    }],
    +)
    +print(message.content)
    +
    +
    +
    import Anthropic, { toFile } from "@anthropic-ai/sdk";
    +import fs from "fs";
    +
    +const anthropic = new Anthropic();
    +
    +// 1) Upload
    +const fileUpload = await anthropic.beta.files.upload({
    +  file: await toFile(fs.createReadStream("document.pdf"), undefined, { type: "application/pdf" }),
    +});
    +
    +// 2) Referencie por file_id
    +const response = await anthropic.beta.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  betas: ["files-api-2025-04-14"],
    +  messages: [{
    +    role: "user",
    +    content: [
    +      { type: "document", source: { type: "file", file_id: fileUpload.id } },
    +      { type: "text", text: "Quais são as conclusões principais?" },
    +    ],
    +  }],
    +});
    +console.log(response);
    +
    +
    +
    # 1) Upload
    +curl -X POST https://api.anthropic.com/v1/files \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: files-api-2025-04-14" \
    +  -F "file=@document.pdf"
    +
    +# 2) Use o file_id retornado
    +curl https://api.anthropic.com/v1/messages \
    +  -H "content-type: application/json" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: files-api-2025-04-14" \
    +  -d '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{
    +      "role": "user",
    +      "content": [
    +        { "type": "document", "source": { "type": "file", "file_id": "file_abc123" } },
    +        { "type": "text", "text": "Quais são as conclusões principais?" }
    +      ]
    +    }]
    +  }'
    +
    +
    + +

    11.2. Operações de gerenciamento

    +
    + + + + + + + + +
    OperaçãoEndpoint / SDK
    UploadPOST /v1/files · client.beta.files.upload(...)
    ListarGET /v1/files · client.beta.files.list()
    MetadadosGET /v1/files/{file_id} · client.beta.files.retrieve_metadata(file_id)
    Baixar conteúdoGET /v1/files/{file_id}/content · client.beta.files.download(file_id)
    ExcluirDELETE /v1/files/{file_id} · client.beta.files.delete(file_id)
    +
    Dica: além de PDFs e imagens, a Files API aceita outros formatos (.csv, .xlsx, .docx, .md, .txt) — veja “Working with other file formats” na doc de Files. Para conteúdo reutilizado em muitas requisições, Files API + prompt caching é a combinação mais econômica.
    +
    + + +
    +

    12. Citações e resultados de busca (citations & search results)

    +

    As citações fazem o Claude fundamentar afirmações em trechos exatos das fontes que você forneceu (documentos, PDFs, resultados de busca), retornando referências verificáveis. Os search results são um tipo de bloco para alimentar RAG com citações nativas.

    + + +

    12.1. Habilitando citações

    +

    Adicione "citations": {"enabled": true} ao bloco document (ou search_result). Quando habilitado, blocos de texto da resposta podem conter um array citations apontando para o local exato na fonte.

    +
    +
    + + + +
    +
    +
    message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{
    +        "role": "user",
    +        "content": [
    +            {
    +                "type": "document",
    +                "source": {"type": "text", "media_type": "text/plain",
    +                           "data": "O céu é azul devido ao espalhamento de Rayleigh..."},
    +                "title": "Por que o céu é azul",
    +                "citations": {"enabled": True},
    +            },
    +            {"type": "text", "text": "Por que o céu é azul? Cite a fonte."},
    +        ],
    +    }],
    +)
    +for block in message.content:
    +    if block.type == "text":
    +        print(block.text)
    +        for c in (block.citations or []):
    +            print("  citação:", c)
    +
    +
    +
    const message = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{
    +    role: "user",
    +    content: [
    +      {
    +        type: "document",
    +        source: { type: "text", media_type: "text/plain",
    +                  data: "O céu é azul devido ao espalhamento de Rayleigh..." },
    +        title: "Por que o céu é azul",
    +        citations: { enabled: true },
    +      },
    +      { type: "text", text: "Por que o céu é azul? Cite a fonte." },
    +    ],
    +  }],
    +});
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  -H "content-type: application/json" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -d '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{
    +      "role": "user",
    +      "content": [
    +        { "type": "document",
    +          "source": { "type": "text", "media_type": "text/plain", "data": "O céu é azul devido ao espalhamento de Rayleigh..." },
    +          "title": "Por que o céu é azul",
    +          "citations": { "enabled": true } },
    +        { "type": "text", "text": "Por que o céu é azul? Cite a fonte." }
    +      ]
    +    }]
    +  }'
    +
    +
    + +

    12.2. Tipos de localização de citação

    +
    + + + + + + + +
    TipoFonteCampos de localização
    char_locationDocumento de texto simplesstart_char_index, end_char_index
    page_locationPDFstart_page_number, end_page_number
    content_block_locationDocumento de conteúdo customizado (lista de blocos)start_block_index, end_block_index
    search_result_locationBloco search_resultsearch_result_index, start_block_index, end_block_index
    +

    Cada citação inclui também o cited_text (o trecho exato citado) e o document_index/título, permitindo renderizar referências clicáveis.

    + +

    12.3. Search results (RAG com citações nativas)

    +

    O bloco search_result representa um resultado de busca/recuperação que o Claude pode citar nativamente. Há dois jeitos de fornecê-los:

    +
      +
    • Método 1 — retorno de ferramenta: uma ferramenta de busca devolve blocos search_result dentro do tool_result.
    • +
    • Método 2 — conteúdo de usuário no nível superior: você inclui blocos search_result diretamente no content de uma mensagem do usuário.
    • +
    +

    Schema do bloco search_result:

    +
    {
    +  "type": "search_result",
    +  "source": "https://exemplo.com/artigo",
    +  "title": "Título do resultado",
    +  "content": [ { "type": "text", "text": "Trecho recuperado..." } ],
    +  "citations": { "enabled": true },
    +  "cache_control": { "type": "ephemeral" }
    +}
    +

    Campos: source, title e content são obrigatórios; citations e cache_control são opcionais. O conteúdo é somente texto.

    +
    +
    + + +
    +
    +
    # Método 2: search_result direto no conteúdo do usuário
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{
    +        "role": "user",
    +        "content": [
    +            {
    +                "type": "search_result",
    +                "source": "https://docs.exemplo.com/api/auth",
    +                "title": "Guia de autenticação",
    +                "content": [{"type": "text", "text": "Use o header x-api-key com sua chave de API..."}],
    +                "citations": {"enabled": True},
    +            },
    +            {"type": "text", "text": "Como autenticar? Cite a fonte."},
    +        ],
    +    }],
    +)
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  -H "content-type: application/json" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -d '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{
    +      "role": "user",
    +      "content": [
    +        { "type": "search_result",
    +          "source": "https://docs.exemplo.com/api/auth",
    +          "title": "Guia de autenticação",
    +          "content": [ { "type": "text", "text": "Use o header x-api-key com sua chave de API..." } ],
    +          "citations": { "enabled": true } },
    +        { "type": "text", "text": "Como autenticar? Cite a fonte." }
    +      ]
    +    }]
    +  }'
    +
    +
    +
    Nota: citações em search_result são tudo-ou-nada — habilite em todos os blocos de uma mesma requisição de forma consistente. Search results estão disponíveis na Claude API, no Amazon Bedrock e no Vertex AI. O conteúdo é somente texto (sem imagens dentro do search_result).
    +
    Dica: use search results em vez de injetar trechos como texto puro quando precisar de citações verificáveis num pipeline RAG: o Claude referencia o índice do resultado e os blocos exatos, e você pode renderizar a fonte clicável para o usuário final.
    +
    + + + + + + + + +
    +

    Parte C — Ferramentas (Tool Use), Skills & MCP

    +

    Esta parte cobre como o Claude chama ferramentas: o contrato tool_use → tool_result, a definição de ferramentas client-side e server-side, o catálogo completo de ferramentas fornecidas pela Anthropic (bash, text editor, computer use, memory, code execution, web search, web fetch, tool search, advisor), os recursos avançados (uso paralelo, chamada programática, modo estrito, streaming refinado, gerenciamento de contexto, combinações, prompt caching), as Agent Skills (SKILL.md + recursos, com divulgação progressiva) e o Model Context Protocol (MCP connector, servidores remotos e MCP tunnels).

    +
    + + + + +
    +

    1. Tool use — como funciona

    + + +

    Tool use (uso de ferramentas / function calling) permite que o Claude chame funções que você define ou que a Anthropic fornece. O Claude decide quando chamar uma ferramenta com base no pedido do usuário e na description da ferramenta; ele então devolve uma chamada estruturada que sua aplicação executa (ferramentas client-side) ou que a Anthropic executa (ferramentas server-side). O modelo nunca executa nada por conta própria: ele emite uma requisição estruturada, alguém roda a operação, e o resultado volta para a conversa.

    + +
    Nota: esse contrato faz o modelo se comportar menos como um gerador de texto e mais como uma função que você chama. A diferença é que quem decide qual função invocar é um modelo de linguagem, com base na conversa. Se você está escrevendo regex para extrair uma decisão da saída do modelo, essa decisão deveria ter sido uma chamada de ferramenta.
    + +

    Onde as ferramentas rodam: os três tipos

    +

    O eixo principal que diferencia ferramentas é onde o código executa. Toda ferramenta cai em uma de três categorias, e a categoria determina pelo que sua aplicação é responsável.

    +
    + + + + + + +
    CategoriaQuem executaExemplosO que você faz
    Ferramentas definidas pelo usuário (client-side)Sua aplicaçãoLógica de negócio, APIs internas, consultas a bancoEscreve o schema, executa o código, devolve o tool_result. É o grosso do tráfego de tool use.
    Ferramentas de schema-Anthropic (client-side)Sua aplicaçãobash, text_editor, computer, memoryMesma mecânica das definidas pelo usuário, mas o schema é treinado-no-modelo, então o Claude as chama de forma mais confiável.
    Ferramentas executadas no servidorAnthropicweb_search, web_fetch, code_execution, tool_searchVocê apenas habilita a ferramenta e lê a resposta final; nunca constrói um tool_result para elas.
    + +

    O loop agêntico (ferramentas client-side)

    +

    Ferramentas client-side (tanto as definidas pelo usuário quanto as de schema-Anthropic) exigem que sua aplicação conduza um loop. O formato canônico é um while baseado em stop_reason:

    +
      +
    1. Envie uma requisição com seu array tools e a mensagem do usuário.
    2. +
    3. O Claude responde com stop_reason: "tool_use" e um ou mais blocos tool_use.
    4. +
    5. Execute cada ferramenta e formate as saídas como blocos tool_result.
    6. +
    7. Envie uma nova requisição contendo as mensagens originais, a resposta do assistente e uma mensagem de usuário com os blocos tool_result.
    8. +
    9. Repita a partir do passo 2 enquanto stop_reason for "tool_use".
    10. +
    +

    O loop termina em qualquer outro motivo de parada ("end_turn", "max_tokens", "stop_sequence" ou "refusal"), o que significa que o Claude produziu uma resposta final ou parou por outro motivo.

    + +

    O loop do lado servidor e pause_turn

    +

    Ferramentas server-side rodam seu próprio loop dentro da infraestrutura da Anthropic. Uma única requisição sua pode disparar várias buscas web ou execuções de código antes de a resposta voltar. Esse loop interno tem um limite de iterações; se o modelo ainda está iterando ao atingir o teto, a resposta volta com stop_reason: "pause_turn" em vez de "end_turn". Um turno pausado significa que o trabalho não terminou: reenvie a conversa (incluindo a resposta pausada) para o modelo continuar. Veja a seção Ferramentas server-side.

    + +

    Quando usar (e quando não usar) ferramentas

    +

    Tool use serve quando a tarefa exige algo que o modelo não consegue fazer só com texto: ações com efeitos colaterais (enviar e-mail, escrever arquivo, atualizar registro), dados frescos ou externos (preços atuais, conteúdo de um banco), saídas estruturadas com formato garantido, e integração com sistemas existentes. Não serve quando o modelo pode responder só com o treino (resumo, tradução, conhecimento geral), quando a interação é Q&A de uma rodada sem efeitos colaterais, ou quando a latência da chamada dominaria uma resposta trivial.

    + +

    Preço do tool use

    +

    Requisições com tool use são cobradas por: (1) total de tokens de entrada enviados ao modelo (incluindo o parâmetro tools); (2) tokens de saída gerados; (3) para ferramentas server-side, cobrança adicional por uso (ex.: web search cobra por busca). Ao usar tools, a API injeta automaticamente um system prompt especial que habilita o tool use. Em todos os modelos atuais, esse prompt de sistema custa 346 tokens para tool_choice auto/none e 313 tokens para any/tool (assumindo ao menos 1 ferramenta; com none e nenhuma ferramenta, 0 tokens). Esses tokens entram nos contadores normais de usage.

    + +
    + + + + + + +
    Modeloauto / noneany / tool
    Claude Opus 4.8 (claude-opus-4-8)346 tokens313 tokens
    Claude Sonnet 4.6 (claude-sonnet-4-6)346 tokens313 tokens
    Claude Haiku 4.5 (claude-haiku-4-5)346 tokens313 tokens
    +
    Nota: esta tabela mostra apenas o custo em tokens do system prompt de tool use por modelo. Para a tabela comparativa de modelos, preços por token, snapshots e orientação de escolha (Opus 4.8 para tarefas complexas/raciocínio, Sonnet 4.6 para equilíbrio, Haiku 4.5 para baixa latência/custo), veja Modelos Claude.
    + +

    Exemplo mínimo (ferramenta server-side)

    +

    O exemplo mais simples usa uma ferramenta server-side, na qual a Anthropic cuida da execução:

    +
    +
    + + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +response = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    tools=[{"type": "web_search_20260209", "name": "web_search"}],
    +    messages=[{"role": "user", "content": "Qual a novidade mais recente do rover em Marte?"}],
    +)
    +print(response.content)
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic();
    +const response = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  tools: [{ type: "web_search_20260209", name: "web_search" }],
    +  messages: [{ role: "user", content: "Qual a novidade mais recente do rover em Marte?" }],
    +});
    +console.log(response.content);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "tools": [{"type": "web_search_20260209", "name": "web_search"}],
    +    "messages": [{"role": "user", "content": "Qual a novidade mais recente do rover em Marte?"}]
    +  }'
    +
    +
    +
    + + + + +
    +

    2. Definindo ferramentas

    + + +

    Ferramentas client-side (tanto de schema-Anthropic quanto definidas pelo usuário) são declaradas no parâmetro de topo tools. Cada definição inclui:

    +
    + + + + + + + +
    ParâmetroDescrição
    nameNome da ferramenta. Deve casar com a regex ^[a-zA-Z0-9_-]{1,64}$.
    descriptionDescrição em texto puro, detalhada, do que a ferramenta faz, quando usá-la e como se comporta.
    input_schemaObjeto JSON Schema definindo os parâmetros esperados.
    input_examples(Opcional) Array de objetos de entrada de exemplo para ajudar o Claude a entender como usar a ferramenta.
    +

    Propriedades opcionais disponíveis em qualquer definição (cache_control, strict, defer_loading, allowed_callers, eager_input_streaming) estão na Referência de ferramentas.

    + +

    Exemplo de definição simples

    +
    {
    +  "name": "get_weather",
    +  "description": "Get the current weather in a given location",
    +  "input_schema": {
    +    "type": "object",
    +    "properties": {
    +      "location": {
    +        "type": "string",
    +        "description": "The city and state, e.g. San Francisco, CA"
    +      },
    +      "unit": {
    +        "type": "string",
    +        "enum": ["celsius", "fahrenheit"],
    +        "description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
    +      }
    +    },
    +    "required": ["location"]
    +  }
    +}
    + +

    Boas práticas para descrições

    +
      +
    • Descrições extremamente detalhadas — de longe o fator mais importante. Explique o que a ferramenta faz, quando (e quando não) usar, o que cada parâmetro significa e quaisquer limitações. Mire em pelo menos 3–4 frases por ferramenta.
    • +
    • Considere input_examples para ferramentas complexas — com objetos aninhados, parâmetros opcionais ou formatos sensíveis. Cada exemplo deve ser válido perante o input_schema (exemplos inválidos retornam erro 400). Custo: ~20–50 tokens para exemplos simples, ~100–200 para objetos aninhados complexos. Não disponível em ferramentas server-side.
    • +
    • Consolide operações relacionadas em menos ferramentas — em vez de create_pr, review_pr, merge_pr, prefira uma ferramenta com um parâmetro action.
    • +
    • Use namespacing nos nomes — quando as ferramentas abrangem vários serviços, prefixe com o serviço (github_list_prs, slack_send_message). Isso é especialmente importante ao usar tool search.
    • +
    • Desenhe respostas com informação de alto sinal — retorne identificadores estáveis (slugs, UUIDs) e só os campos de que o Claude precisa. Respostas inchadas desperdiçam contexto.
    • +
    + +

    Controlando a saída: tool_choice

    +

    Há quatro opções para o campo tool_choice:

    +
    + + + + + + + +
    ValorComportamento
    autoO Claude decide se chama alguma ferramenta. Padrão quando há tools.
    anyO Claude deve usar uma das ferramentas, sem forçar uma específica.
    toolForça sempre uma ferramenta específica: {"type": "tool", "name": "get_weather"}.
    noneImpede o uso de qualquer ferramenta. Padrão quando não há tools.
    +
    Atenção: com any ou tool, a API faz prefill da mensagem do assistente para forçar a ferramenta — o modelo não emite texto natural antes dos blocos tool_use. Com adaptive/extended thinking, tool_choice any e tool não são suportados e geram erro; apenas auto (padrão) e none são compatíveis. Mudar tool_choice sob prompt caching invalida blocos de mensagem em cache.
    +
    Dica: combine tool_choice: {"type": "any"} com strict tool use (strict: true) para garantir tanto que uma ferramenta será chamada quanto que os inputs seguem o schema exatamente.
    +
    + +
    +

    2.1. Tratando chamadas de ferramenta (handle-tool-calls)

    + + +

    Para ferramentas client-side, a resposta tem stop_reason: "tool_use" e um ou mais blocos tool_use com id (identificador único, casado depois pelo resultado), name e input (objeto conforme o input_schema). Ao receber, você deve: (1) extrair name, id e input; (2) rodar a ferramenta correspondente; (3) continuar a conversa enviando uma mensagem user com um bloco tool_result.

    + +

    O bloco tool_result tem:

    +
      +
    • tool_use_id: o id da requisição tool_use que este resultado responde.
    • +
    • content (opcional): o resultado, como string ("15 degrees"), lista de blocos aninhados, ou blocos de documento. Pode usar tipos text, image ou document.
    • +
    • is_error (opcional): true se a execução resultou em erro.
    • +
    + +
    Cuidado — requisitos de formatação: os blocos tool_result devem vir imediatamente após os blocos tool_use correspondentes; não pode haver mensagens entre a mensagem do assistente (com tool_use) e a mensagem do usuário (com tool_result). Dentro da mensagem de usuário, os blocos tool_result devem vir primeiro no array de content; qualquer texto vem depois. Texto antes do tool_result causa erro 400 (tool_use ids were found without tool_result blocks immediately after).
    + +

    Exemplo de resultado bem-sucedido e de resultado de erro:

    +
    {
    +  "role": "user",
    +  "content": [
    +    { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "15 degrees" }
    +  ]
    +}
    +
    {
    +  "role": "user",
    +  "content": [
    +    {
    +      "type": "tool_result",
    +      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
    +      "content": "ConnectionError: the weather service API is not available (HTTP 500)",
    +      "is_error": true
    +    }
    +  ]
    +}
    + +
    Dica: escreva mensagens de erro instrutivas. Em vez de "failed", inclua o que deu errado e o que o Claude deve tentar a seguir (ex.: "Rate limit exceeded. Retry after 60 seconds."). Se uma chamada é inválida ou falta um parâmetro, o Claude tenta de novo 2–3 vezes antes de se desculpar. Para servidor, o Claude trata erros transparentemente — você não precisa lidar com is_error em ferramentas server-side.
    + +

    Para web search, os códigos de erro possíveis incluem: too_many_requests (limite de taxa), invalid_input (query inválida), max_uses_exceeded (limite de buscas excedido), query_too_long e unavailable (erro interno).

    + +
    Nota — diferença de outras APIs: diferentemente de APIs que usam papéis especiais (tool/function), a Claude API integra ferramentas diretamente nas mensagens user e assistant. Mensagens contêm arrays de blocos text, image, tool_use e tool_result: mensagens user incluem conteúdo do cliente e tool_result; mensagens assistant contêm conteúdo gerado e tool_use.
    +
    + + + + +
    +

    3. Tipos de ferramentas e referência (catálogo)

    + + +

    A Anthropic fornece dois tipos: ferramentas server-side (executam na infraestrutura da Anthropic) e ferramentas client-side de schema-Anthropic (a Anthropic define o schema, sua aplicação executa). Ambas aparecem no array tools junto com suas ferramentas próprias. O catálogo abaixo lista os valores exatos de type e os headers beta — verificados na doc oficial.

    + +
    + + + + + + + + + + + + + +
    FerramentatypeExecuçãoStatus
    Web searchweb_search_20260209
    web_search_20250305
    ServidorGA
    Web fetchweb_fetch_20260209
    web_fetch_20250910
    ServidorGA
    Code executioncode_execution_20260521
    code_execution_20260120
    code_execution_20250825
    ServidorGA
    Advisoradvisor_20260301ServidorBeta advisor-tool-2026-03-01
    Tool searchtool_search_tool_regex_20251119
    tool_search_tool_bm25_20251119
    ServidorGA
    MCP connectormcp_toolsetServidorBeta mcp-client-2025-11-20
    Memorymemory_20250818ClienteGA
    Bashbash_20250124ClienteGA
    Text editortext_editor_20250728
    text_editor_20250124
    ClienteGA
    Computer usecomputer_20251124
    computer_20250124
    ClienteBeta computer-use-2025-11-24 / computer-use-2025-01-24
    +
    Nota: os valores de tool search também aceitam aliases sem data (tool_search_tool_regex, tool_search_tool_bm25), que resolvem para a versão datada mais recente.
    + +

    Versionamento de ferramentas

    +

    A maioria das ferramentas carrega o sufixo _YYYYMMDD no type. Uma nova versão sai quando o comportamento, o schema ou o suporte a modelos muda; as versões antigas continuam disponíveis. As relações variam:

    +
      +
    • Por capacidade: web_search_20260209 / web_fetch_20260209 adicionam filtragem dinâmica de conteúdo; code_execution_20260120 adiciona chamada programática de ferramentas. Em cada caso, ambas as versões são atuais — você escolhe conforme precisa da nova capacidade.
    • +
    • Por modelo: text_editor_20250728 é para modelos Claude 4; text_editor_20250124 é para modelos anteriores.
    • +
    • Variante, não versão: tool_search_tool_regex_20251119 e tool_search_tool_bm25_20251119 são dois algoritmos lançados juntos; nenhum substitui o outro.
    • +
    • O mcp_toolset não é versionado por data — o versionamento vai no header anthropic-beta.
    • +
    + +

    Propriedades opcionais de definição (em qualquer ferramenta)

    +
    + + + + + + + + + +
    PropriedadeFinalidadeDisponível em
    cache_controlDefine um breakpoint de prompt cache nesta definiçãoTodas as ferramentas
    strictGarante validação de schema sobre nomes e inputsTodas, exceto mcp_toolset
    defer_loadingExclui a ferramenta do system prompt inicial; carrega sob demanda via tool searchTodas (para mcp_toolset, ver config do toolset)
    allowed_callersRestringe quais chamadores podem invocar a ferramentaTodas, exceto mcp_toolset
    input_examplesExemplos de inputFerramentas de usuário e de schema-Anthropic (não server-side)
    eager_input_streamingHabilita streaming refinado de inputApenas ferramentas definidas pelo usuário
    +

    O allowed_callers é um array que aceita "direct" (o modelo chama diretamente num bloco tool_use — padrão) e/ou "code_execution_20260120" (código rodando dentro de um sandbox de code execution pode chamar a ferramenta). Omitir "direct" torna a ferramenta chamável só de dentro do code execution. Ferramentas com defer_loading: true são removidas do prefixo antes do cálculo da chave de cache, preservando o prompt cache.

    +
    + + + + +
    +

    4. Ferramentas client-side detalhadas

    +

    As quatro ferramentas de schema-Anthropic client-side (bash, text_editor, computer, memory) mais a server-side code_execution (incluída aqui por proximidade conceitual). A vantagem de usar uma ferramenta de schema-Anthropic em vez de criar a sua equivalente é que esses schemas são treinados-no-modelo: o Claude foi otimizado em milhares de trajetórias bem-sucedidas com essas assinaturas exatas, então ele as chama de forma mais confiável.

    +
    + +
    +

    4.1. Bash tool — bash_20250124

    + +

    A bash tool permite ao Claude executar comandos shell em uma sessão bash persistente, viabilizando operações de sistema, scripts e automação de linha de comando. A sessão mantém estado (variáveis de ambiente, diretório de trabalho) entre comandos. GA · ZDR elegível.

    +

    É uma ferramenta schema-less: você não fornece input_schema — o schema está embutido no modelo e não pode ser modificado. Parâmetros: command (obrigatório, salvo quando se usa restart) e restart (opcional, true reinicia a sessão).

    +
    +
    + + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +response = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    tools=[{"type": "bash_20250124", "name": "bash"}],
    +    messages=[{"role": "user", "content": "List all Python files in the current directory."}],
    +)
    +print(response)
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic();
    +const response = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  tools: [{ type: "bash_20250124", name: "bash" }],
    +  messages: [{ role: "user", content: "List all Python files in the current directory." }],
    +});
    +console.log(response);
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "content-type: application/json" \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "tools": [{"type": "bash_20250124", "name": "bash"}],
    +    "messages": [{"role": "user", "content": "List all Python files in the current directory."}]
    +  }'
    +
    +
    +
    Cuidado: a bash tool dá ao Claude acesso a shell. Rode-a em um ambiente isolado (VM/contêiner com privilégios mínimos), restrinja o diretório de trabalho e considere uma allowlist de comandos quando o agente opera sobre código não confiável.
    +
    + +
    +

    4.2. Text editor tool — text_editor_20250728

    + +

    Permite ao Claude visualizar e modificar arquivos de texto — depurar, refatorar, gerar documentação, criar testes. A ferramenta tem o nome str_replace_based_edit_tool. Para modelos Claude 4 use text_editor_20250728; para modelos anteriores, text_editor_20250124. GA · ZDR elegível. Você pode opcionalmente passar max_characters para controlar a truncagem ao ler arquivos grandes (compatível com text_editor_20250728+).

    +

    Comandos suportados:

    +
    + + + + + + + +
    ComandoParâmetrosO que faz
    viewpath, view_range (opcional, [início, fim], 1-indexado, -1 = fim do arquivo)Lê arquivo (ou intervalo de linhas) ou lista um diretório.
    str_replacepath, old_str (deve casar exatamente, incluindo espaços), new_strSubstitui um trecho específico por outro. Edição precisa.
    createpath, file_textCria um novo arquivo com o conteúdo dado.
    insertpath, insert_line (0 = começo), insert_textInsere texto após a linha indicada.
    +
    {
    +  "type": "tool_use",
    +  "id": "toolu_01A09q90qw90lq917835lq9",
    +  "name": "str_replace_based_edit_tool",
    +  "input": {
    +    "command": "str_replace",
    +    "path": "primes.py",
    +    "old_str": "for num in range(2, limit + 1)",
    +    "new_str": "for num in range(2, limit + 1):"
    +  }
    +}
    +
    + +
    +

    4.3. Computer use tool — computer_20251124

    + +

    Permite ao Claude interagir com ambientes de desktop: captura de tela, controle de mouse/teclado, automação. Beta — exige um header beta:

    +
      +
    • computer-use-2025-11-24 (tipo computer_20251124) para Claude Opus 4.8 e Sonnet 4.6.
    • +
    • computer-use-2025-01-24 (tipo computer_20250124) para Claude Haiku 4.5.
    • +
    +

    ZDR elegível. Parâmetros da definição: display_width_px, display_height_px e display_number. Frequentemente combinado com text_editor e bash.

    +

    Ações disponíveis:

    +
    + + + + + + +
    GrupoAções
    Básicas (todas as versões)screenshot, left_click (com coordinate [x,y]), type, key (ex.: "ctrl+s"), mouse_move
    Aprimoradas (computer_20250124)scroll, left_click_drag, right_click, middle_click, double_click, triple_click, left_mouse_down/left_mouse_up, hold_key, wait
    Aprimoradas (computer_20251124)Todas as anteriores + zoom (ver uma região em resolução plena; exige enable_zoom: true e um region [x1,y1,x2,y2])
    +

    Para teclas modificadoras (Shift, Ctrl, Alt) durante clique/scroll, use o parâmetro text na própria ação (ex.: {"action": "left_click", "coordinate": [500,300], "text": "shift"}).

    +
    +
    + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +response = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    tools=[
    +        {"type": "computer_20251124", "name": "computer",
    +         "display_width_px": 1024, "display_height_px": 768, "display_number": 1},
    +        {"type": "text_editor_20250728", "name": "str_replace_based_edit_tool"},
    +        {"type": "bash_20250124", "name": "bash"},
    +    ],
    +    messages=[{"role": "user", "content": "Save a picture of a cat to my desktop."}],
    +    betas=["computer-use-2025-11-24"],
    +)
    +print(response)
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "content-type: application/json" \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "anthropic-beta: computer-use-2025-11-24" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "tools": [
    +      {"type": "computer_20251124", "name": "computer",
    +       "display_width_px": 1024, "display_height_px": 768, "display_number": 1}
    +    ],
    +    "messages": [{"role": "user", "content": "Save a picture of a cat to my desktop."}]
    +  }'
    +
    +
    +
    Cuidado: computer use tem riscos próprios, ampliados ao acessar a internet. Use uma VM/contêiner dedicado de privilégio mínimo, evite dar acesso a dados sensíveis, restrinja a internet a uma allowlist de domínios e peça confirmação humana para ações de consequência real. O Claude pode seguir instruções encontradas em conteúdo (prompt injection via páginas/imagens). A Anthropic treina o modelo para resistir e roda classificadores que pedem confirmação ao detectar injeções em screenshots — proteção que pode ser desativada via suporte para casos sem humano no loop. Há uma implementação de referência (contêiner Docker, ferramentas, loop de agente, UI web).
    +
    + +
    +

    4.4. Memory tool — memory_20250818

    + +

    Permite ao Claude armazenar e recuperar informação entre conversas, via um diretório de arquivos de memória. É o primitivo-chave para recuperação just-in-time: em vez de carregar tudo de uma vez, o agente guarda o que aprende e recupera sob demanda, mantendo o contexto ativo focado. GA · ZDR elegível.

    +

    A ferramenta é client-side: você controla onde e como os dados são guardados. O Claude faz chamadas de ferramenta e sua aplicação as executa localmente. Por segurança, restrinja todas as operações ao diretório /memories. Os SDKs trazem helpers (subclasse de BetaAbstractMemoryTool em Python; betaMemoryTool em TypeScript).

    +

    Comandos que sua implementação precisa tratar: view (lista diretório ou mostra arquivo, com view_range opcional), create (path, file_text), str_replace (old_str/new_str), insert (insert_line, insert_text), delete (recursivo para diretórios) e rename (old_path/new_path; não sobrescreve destino existente).

    +

    Quando habilitada, a Anthropic injeta automaticamente no system prompt o protocolo de memória: "IMPORTANT: ALWAYS VIEW YOUR MEMORY DIRECTORY BEFORE DOING ANYTHING ELSE", lembrando o Claude de checar progresso anterior e gravar status, pois o contexto pode ser resetado a qualquer momento.

    +
    Cuidado — path traversal: inputs maliciosos podem tentar acessar arquivos fora de /memories. Sua implementação DEVE validar todos os caminhos: confirmar que começam com /memories, resolver para a forma canônica e verificar que permanecem no diretório, rejeitar sequências como ../, ..\\ e variantes URL-encoded (%2e%2e%2f), e usar utilitários nativos (pathlib.Path.resolve() + relative_to() em Python). Considere também limitar tamanho de arquivos e expirar memórias antigas.
    +

    A memory tool combina com context editing (limpa tool_result antigos no cliente) e com compaction (sumariza a conversa no servidor): use ambos em fluxos longos — a memória persiste o que é crítico através das fronteiras de compactação.

    +
    + +
    +

    4.5. Code execution tool — code_execution_20250825 / code_execution_20260120 / code_execution_20260521

    + +

    Roda código Python e Bash em um contêiner isolado para analisar dados, gerar arquivos e iterar sobre soluções. É um primitivo central para agentes de alto desempenho — habilita a filtragem dinâmica de web search/web fetch. GA (server-side) desde 2026-02-17, sem header beta (confirmado na doc oficial em 2026-06-10; o header legado code-execution-2025-08-25 segue aceito por compatibilidade — alguns exemplos de SDK ainda o usam via namespace beta). Não é elegível para ZDR.

    +
    Dica: code execution é gratuito quando usado com web search ou web fetch — incluindo web_search_20260209 ou web_fetch_20260209, não há cobrança extra por chamadas de code execution além dos custos normais de token. As cobranças padrão de code execution aplicam-se quando essas ferramentas não estão presentes.
    +

    São três versões GA (nenhuma exige header beta — All three tool versions are generally available and don't require an anthropic-beta header), cada uma construída sobre a anterior: code_execution_20250825 suporta comandos Bash e operações de arquivo e roda em todos os modelos da tabela; code_execution_20260120 adiciona persistência de estado do REPL e chamada programática de ferramentas a partir do sandbox; code_execution_20260521 usa o mesmo runtime do 20260120, diferindo só na tool description, que informa ao modelo o limite de 90 s de wall-clock por célula Python na chamada programática (célula que excede retorna return_code não-zero e status detection_timeout). A legada code_execution_20250522 é só Python.

    +
    Atenção ao Haiku 4.5: a tabela oficial de compatibilidade lista as três versões (20250825, 20260120, 20260521) como aceitas pelo claude-haiku-4-5 — o texto literal: Claude Haiku 4.5 accepts the code_execution_20260120 and code_execution_20260521 tool types, but programmatic tool calling and the REPL state persistence that depends on it aren't available on it. Ou seja, no Haiku 4.5 os tipos novos são aceitos, mas degradam para o comportamento do 20250825 (sem REPL persistence e sem chamada programática). Code execution está disponível na Claude API, Claude Platform on AWS e Microsoft Foundry; não está em Amazon Bedrock nem Vertex AI.
    +

    Contêiner (runtime): Python 3.11.12, Linux x86_64, 5 GiB de RAM, 5 GiB de disco, 1 CPU. Sem acesso à internet e isolamento total do host. Contêineres expiram 30 dias após a criação e são escopados ao workspace da API key. Bibliotecas pré-instaladas incluem pandas, numpy, scipy, scikit-learn, matplotlib, seaborn, pyarrow, openpyxl, pillow, python-pptx, python-docx, pypdf, pdfplumber, reportlab, sympy, sqlite, ripgrep, entre outras.

    +

    Você pode reutilizar um contêiner entre requisições passando o container ID de uma resposta anterior, mantendo arquivos criados. Para enviar seus próprios arquivos, use a Files API (header files-api-2025-04-14) e referencie-os com um bloco container_upload ({"type": "container_upload", "file_id": "file_abc123"}).

    +
    +
    + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +response = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=4096,
    +    messages=[{"role": "user",
    +               "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"}],
    +    tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
    +)
    +print(response)
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 4096,
    +    "messages": [{"role": "user", "content": "Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"}],
    +    "tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
    +  }'
    +
    +
    +
    + + + + +
    +

    5. Ferramentas server-side

    + +

    Ferramentas server-side (web_search, web_fetch, code_execution, tool_search) executam na infraestrutura da Anthropic. Quando uma roda, aparece um bloco server_tool_use na resposta, com id prefixado por srvtoolu_ (vs. toolu_ das ferramentas de cliente). O resultado aparece logo após, no mesmo turno do assistente — você não responde com tool_result.

    +
    {
    +  "type": "server_tool_use",
    +  "id": "srvtoolu_01A2B3C4D5E6F7G8H9",
    +  "name": "web_search",
    +  "input": { "query": "latest quantum computing breakthroughs" }
    +}
    + +

    Continuação com pause_turn

    +

    O loop interno tem limite de iterações; ao atingi-lo, a resposta volta com stop_reason: "pause_turn". Para continuar, reenvie a conversa passando a resposta pausada como mensagem assistant (preservando as mesmas ferramentas). Você pode opcionalmente modificar o conteúdo antes de continuar.

    + +

    ZDR e allowed_callers

    +

    As versões básicas — web_search_20250305 e web_fetch_20250910 — são elegíveis para Zero Data Retention (ZDR). As versões _20260209 com filtragem dinâmica não são ZDR-elegíveis por padrão (a filtragem usa code execution internamente). Para usá-las com ZDR, desabilite a filtragem dinâmica com "allowed_callers": ["direct"], restringindo a ferramenta à invocação direta.

    + +

    Filtragem de domínio

    +

    Ferramentas que acessam a web aceitam allowed_domains e blocked_domains (use um ou outro, nunca ambos na mesma requisição). Regras: domínios sem esquema HTTP/HTTPS (example.com, não https://example.com); subdomínios são incluídos automaticamente (example.com cobre docs.example.com); subcaminhos são suportados (example.com/blog casa example.com/blog/post-1); curinga (*) apenas um por entrada, e só após a parte do domínio (válido: example.com/*; inválido: *.example.com). Restrições no nível da requisição devem ser compatíveis com as do nível da organização no Console (só podem restringir mais, nunca ampliar).

    +
    Atenção: caracteres Unicode em nomes de domínio podem criar ataques de homógrafos (ex.: аmazon.com com 'а' cirílico parece amazon.com). Prefira nomes ASCII e teste seus filtros contra variações de homógrafos.
    +
    Atenção: incluir uma ferramenta code_execution autônoma ao lado das versões _20260209 dos tools web cria dois ambientes de execução, o que pode confundir o modelo. Use um ou outro, ou fixe ambos na mesma versão.
    +
    + +
    +

    5.1. Web search — web_search_20260209 / web_search_20250305

    + +

    Dá ao Claude acesso a conteúdo web em tempo real, com citações das fontes. A versão mais recente (web_search_20260209) suporta filtragem dinâmica em Claude Opus 4.8 e Sonnet 4.6: o Claude escreve e executa código para filtrar os resultados antes de chegarem ao contexto, melhorando a precisão e reduzindo tokens. A versão anterior (web_search_20250305) permanece disponível sem filtragem dinâmica. GA.

    +
    Nota: a filtragem dinâmica requer a ferramenta code execution habilitada. O administrador da organização deve habilitar web search no Console. A filtragem dinâmica está na Claude API, Claude Platform on AWS e Microsoft Foundry; em Vertex AI só a busca básica; não está em Amazon Bedrock.
    +

    Parâmetros da definição:

    +
    + + + + + + +
    ParâmetroDescrição
    max_usesLimita o nº de buscas por requisição. Exceder gera erro max_uses_exceeded.
    allowed_domains / blocked_domainsFiltragem de domínio (ver seção acima).
    user_locationLocaliza resultados: type: "approximate", city, region, country, timezone (ID IANA).
    +

    A resposta inclui blocos server_tool_use (a query usada) e web_search_tool_result com web_search_result (url, title, encrypted_content, page_age), e o texto final com citações.

    +
    {
    +  "type": "web_search_20250305",
    +  "name": "web_search",
    +  "max_uses": 5,
    +  "allowed_domains": ["example.com", "trusteddomain.org"],
    +  "user_location": {
    +    "type": "approximate",
    +    "city": "San Francisco",
    +    "region": "California",
    +    "country": "US",
    +    "timezone": "America/Los_Angeles"
    +  }
    +}
    +
    + +
    +

    5.2. Web fetch — web_fetch_20260209 / web_fetch_20250910

    + +

    Recupera o conteúdo completo de páginas web e documentos PDF específicos (com extração automática de texto para PDFs) e responde com citações opcionais. A versão web_fetch_20260209 suporta filtragem dinâmica (Opus 4.8, Sonnet 4.6), útil para extrair seções de documentos longos. GA. Não suporta sites renderizados dinamicamente com JavaScript.

    +
    Cuidado — exfiltração de dados: habilitar web fetch em ambientes onde o Claude processa entrada não confiável junto a dados sensíveis cria risco de exfiltração. Para mitigar, o Claude não pode construir URLs dinamicamente — só busca URLs fornecidas explicitamente pelo usuário ou vindas de resultados anteriores de web search/web fetch. Ainda há risco residual: considere desabilitar a ferramenta, usar max_uses para limitar requisições, e allowed_domains para restringir a domínios seguros.
    +

    Parâmetros principais: max_uses, allowed_domains/blocked_domains, e citações (habilitadas via citations: { enabled: true } no resultado). O resultado (web_fetch_tool_result / web_fetch_result) traz a URL, um bloco document com o texto, title e retrieved_at. As citações usam char_location com document_index, start_char_index/end_char_index e cited_text.

    +
    + + + +
    +

    5.4. Advisor tool — advisor_20260301

    + +

    Pareia um modelo executor mais rápido e barato com um modelo advisor de maior inteligência que dá orientação estratégica no meio da geração. O advisor lê toda a conversa e produz um plano ou correção de rumo (tipicamente 400–700 tokens de texto), e o executor continua. Encaixa em cargas agênticas de longo horizonte (agentes de coding, computer use, pesquisa multi-passo) onde a maioria dos turnos é mecânica mas um excelente plano é crucial. Beta — header advisor-tool-2026-03-01. ZDR elegível.

    +

    O modelo executor (campo model de topo) e o advisor (campo model dentro da definição da ferramenta) devem formar um par válido — o advisor deve ser ao menos tão capaz quanto o executor:

    +
    + + + + + + +
    ExecutorAdvisor
    Claude Haiku 4.5 (claude-haiku-4-5)Claude Opus 4.8 (claude-opus-4-8)
    Claude Sonnet 4.6 (claude-sonnet-4-6)Claude Opus 4.8 (claude-opus-4-8)
    Claude Opus 4.8 (claude-opus-4-8)Claude Opus 4.8 (claude-opus-4-8)
    +

    Par inválido retorna 400 invalid_request_error. Disponível em beta na Claude API e Claude Platform on AWS (não em Bedrock, Vertex AI ou Microsoft Foundry). Desde 02/06/2026, a definição da ferramenta aceita max_tokens (tools[].max_tokens) para limitar a saída do advisor por chamada — reduz latência e custo quando você não precisa de orientações longas.

    +
    +
    + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +response = client.beta.messages.create(
    +    model="claude-sonnet-4-6",          # executor
    +    max_tokens=4096,
    +    betas=["advisor-tool-2026-03-01"],
    +    tools=[{"type": "advisor_20260301", "name": "advisor", "model": "claude-opus-4-8"}],  # advisor
    +    messages=[{"role": "user", "content": "Build a concurrent worker pool in Go with graceful shutdown."}],
    +)
    +print(response)
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "anthropic-beta: advisor-tool-2026-03-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-sonnet-4-6",
    +    "max_tokens": 4096,
    +    "tools": [{"type": "advisor_20260301", "name": "advisor", "model": "claude-opus-4-8"}],
    +    "messages": [{"role": "user", "content": "Build a concurrent worker pool in Go with graceful shutdown."}]
    +  }'
    +
    +
    +
    + + + + +
    +

    6. Recursos avançados de tool use

    +

    Recursos que melhoram desempenho, confiabilidade, latência e custo de contexto em fluxos agênticos.

    +
    + +
    +

    6.1. Uso paralelo de ferramentas

    + +

    Por padrão, o Claude pode usar várias ferramentas para responder a uma query. As chamadas em um único turno são não ordenadas: você pode rodá-las concorrentemente (Promise.all, asyncio.gather) ou em sequência. Para desabilitar, use disable_parallel_tool_use=true: com tool_choice: auto garante no máximo uma ferramenta; com any/tool, garante exatamente uma.

    +
    Dica: envie todos os tool_result em uma única mensagem de usuário (não um por turno) para manter o paralelismo funcionando nos turnos seguintes. Se o Claude ocasionalmente agrupar chamadas que dependem entre si (ex.: criar e depois atualizar o mesmo recurso), não precisa detectar isso antes: despache tudo e, se uma falhar, devolva o erro natural em um tool_result com is_error: true — o Claude reconhece a dependência e refaz a chamada.
    +
    + +
    +

    6.2. Chamada programática de ferramentas (programmatic tool calling)

    + +

    Permite ao Claude escrever código que chama suas ferramentas programaticamente dentro do sandbox de code execution, em vez de exigir round trips pelo modelo a cada invocação. Reduz latência em fluxos multi-ferramenta e diminui o consumo de tokens (o Claude filtra/processa dados antes de chegarem ao contexto). Ex.: checar conformidade de orçamento de 20 funcionários — em vez de 20 round trips com milhares de linhas no contexto, um único script roda as 20 consultas, filtra e retorna só quem excedeu o limite.

    +

    Requer code_execution_20260120 (ou 20260521), suportado em Opus 4.5+, Sonnet 4.5+, Sonnet 5 e Fable 5. O Haiku 4.5 aceita os tipos, mas a chamada programática de ferramentas não funciona nele (degrada para o comportamento do 20250825). Não é ZDR-elegível. Disponível na Claude API, Claude Platform on AWS e Microsoft Foundry (não em Bedrock/Vertex AI).

    +

    Marque a ferramenta com "allowed_callers": ["code_execution_20260120"] para torná-la chamável de dentro do sandbox. O bloco tool_use da resposta inclui um campo caller identificando quem chamou. Monitore expires_at do contêiner: se ele expira enquanto aguarda seu tool_result, o Claude pode tratar como timeout e refazer.

    +
    {
    +  "type": "code_execution_20260120",
    +  "name": "code_execution"
    +}
    +{
    +  "name": "query_database",
    +  "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",
    +  "input_schema": { "type": "object", "properties": { "sql": {"type": "string"} }, "required": ["sql"] },
    +  "allowed_callers": ["code_execution_20260120"]
    +}
    +
    + +
    +

    6.3. Modo estrito (strict tool use)

    + +

    Definir strict: true na definição de uma ferramenta garante que os inputs do Claude casem com seu JSON Schema, restringindo a amostragem de tokens a saídas válidas (grammar-constrained sampling). Sem modo estrito, o Claude pode retornar tipos incompatíveis ("2" em vez de 2) ou campos faltando. Use para validar parâmetros, construir fluxos agênticos e garantir chamadas type-safe — funções recebem argumentos corretamente tipados toda vez, sem precisar validar e refazer. Disponível em todas as ferramentas exceto mcp_toolset.

    +
    Atenção: a gramática usa apenas o subconjunto suportado de JSON Schema. Por exemplo, pattern com strict: true gera erro (string patterns are not supported) — remova o pattern ou o strict. Inclua "additionalProperties": false no schema.
    +
    {
    +  "name": "get_weather",
    +  "description": "Get the current weather in a given location",
    +  "strict": true,
    +  "input_schema": {
    +    "type": "object",
    +    "properties": {
    +      "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA" },
    +      "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
    +    },
    +    "required": ["location"],
    +    "additionalProperties": false
    +  }
    +}
    +
    + +
    +

    6.4. Streaming refinado de input (fine-grained tool streaming)

    + +

    Permite fazer streaming dos valores de parâmetro de uma ferramenta sem buffering nem validação de JSON no servidor, reduzindo a latência para começar a receber parâmetros grandes. Disponível em todos os modelos e plataformas. Habilite com eager_input_streaming: true em qualquer ferramenta definida pelo usuário, e ative stream na requisição. ZDR elegível.

    +
    Atenção: com streaming refinado você pode receber JSON inválido ou parcial. Trate esses casos no seu código.
    +
    + +
    +

    6.5. Gerenciando o contexto das ferramentas

    + +

    Definições de ferramentas e blocos tool_result acumulados consomem o contexto. Quatro abordagens atacam fontes diferentes de pressão:

    +
    + + + + + + + +
    AbordagemO que reduzQuando encaixa
    Tool searchDefinições carregadas no inícioToolsets grandes (20+) onde a maioria não é necessária a cada turno
    Programmatic tool callingRound trips de tool_resultCadeias de chamadas que podem rodar como um único script
    Prompt cachingCusto de tokens das definições repetidasToolsets estáveis em muitas requisições
    Context editingBlocos tool_result antigos no históricoConversas longas onde resultados antigos já não importam
    +

    Elas compõem. Ponto de partida para um agente de alto volume: (1) habilite prompt caching nas definições desde o dia 1; (2) adicione tool search quando passar de ~20 ferramentas; (3) adicione context editing quando as conversas começarem a ficar longas; (4) considere programmatic tool calling se notar cadeias repetitivas de chamadas pequenas.

    +
    + +
    +

    6.6. Combinações de ferramentas

    + +

    Pareamentos comuns das ferramentas fornecidas pela Anthropic — pontos de partida, não prescrições:

    +
    + + + + + + + + +
    PadrãoFerramentasUso
    Agente de pesquisaweb_search + code_executionBusca encontra fontes; code execution analisa e sintetiza (ex.: comparar resultados financeiros computando sobre os dados).
    Agente de codingtext_editor + bashO loop canônico de dev: inspeciona código, edita, roda testes, repete. Pareie com diretório restrito e allowlist de comandos.
    Cite-then-fetchweb_search + web_fetchBusca traz URLs candidatas; fetch recupera só as 2–3 relevantes, evitando baixar tudo.
    Agente de longa duraçãomemory + qualquer toolsetMemória persiste estado entre conversas; é ortogonal ao resto do toolset.
    Tudo-em-umcomputer_useOpera um desktop completo — alcança qualquer app que um humano alcança. É a opção mais geral e a mais lenta (cada ação é um round trip de screenshot).
    +
    + +
    +

    6.7. Tool use com prompt caching

    + +

    Coloque cache_control: {"type": "ephemeral"} na última ferramenta do array tools para cachear todo o prefixo de definições (da primeira até o breakpoint). Para mcp_toolset, coloque o breakpoint na própria entrada do toolset — a API o aplica à última ferramenta expandida. Ferramentas com defer_loading: true não entram no prefixo (são adicionadas inline como tool_reference quando descobertas), então adicionar ferramentas via tool search não quebra o cache.

    +

    O cache segue a hierarquia de prefixo tools → system → messages; mudar um nível invalida ele e tudo depois:

    +
    + + + + + + + + + +
    MudançaInvalida
    Modificar definições de ferramentasCache inteiro (tools, system, messages)
    Ligar/desligar web search ou citaçõesCaches de system e messages
    Mudar tool_choiceCache de messages
    Mudar disable_parallel_tool_useCache de messages
    Alternar presença de imagensCache de messages
    Mudar parâmetros de thinkingCache de messages
    +
    + +
    +

    6.8. Tool Runner (SDK)

    + +

    O Tool Runner é a abstração do SDK que conduz o loop agêntico, embrulha erros e dá segurança de tipos automaticamente — roda as ferramentas quando o Claude as chama, gerencia o ciclo requisição/resposta e o estado da conversa. Beta, disponível nos SDKs Python, TypeScript, C#, Go, Java, PHP e Ruby. Use o loop manual quando precisar de aprovação humana, logging customizado ou execução condicional.

    +

    Em Python, o decorador @beta_tool deriva o JSON Schema a partir das anotações de tipo e da docstring da função (use @beta_async_tool no cliente assíncrono). Em TypeScript, prefira betaZodTool() (validação Zod, requer Zod 3.25.0+) ou betaTool() (baseado em JSON Schema).

    +
    +
    + + +
    +
    +
    import json
    +from anthropic import Anthropic, beta_tool
    +
    +client = Anthropic()
    +
    +@beta_tool
    +def get_weather(location: str, unit: str = "fahrenheit") -> str:
    +    """Get the current weather in a given location.
    +
    +    Args:
    +        location: The city and state, e.g. San Francisco, CA
    +        unit: Temperature unit, either 'celsius' or 'fahrenheit'
    +    """
    +    return json.dumps({"temperature": "20°C", "condition": "Sunny"})
    +
    +runner = client.beta.messages.tool_runner(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    tools=[get_weather],
    +    messages=[{"role": "user", "content": "What's the weather like in Paris?"}],
    +)
    +for message in runner:
    +    print(message)
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
    +import { z } from "zod";
    +
    +const client = new Anthropic();
    +
    +const getWeatherTool = betaZodTool({
    +  name: "get_weather",
    +  description: "Get the current weather in a given location",
    +  inputSchema: z.object({
    +    location: z.string().describe("The city and state, e.g. San Francisco, CA"),
    +    unit: z.enum(["celsius", "fahrenheit"]).default("fahrenheit"),
    +  }),
    +  run: async (input) => JSON.stringify({ temperature: "20°C", condition: "Sunny" }),
    +});
    +
    +const finalMessage = await client.beta.messages.toolRunner({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  tools: [getWeatherTool],
    +  messages: [{ role: "user", content: "What's the weather like in Paris?" }],
    +});
    +
    +
    +
    + +
    +

    6.9. Tutorial: construir um agente que usa ferramentas

    + +

    O tutorial constrói um agente de gerenciamento de calendário em cinco "anéis" concêntricos, cada um um programa completo e executável que adiciona exatamente um conceito sobre o anterior. A ferramenta de exemplo é create_calendar_event, cujo schema usa objetos aninhados, arrays e campos opcionais (input realista):

    +
      +
    1. Anel 1 — Uma ferramenta, um turno: o menor programa possível. Envia o array tools com a mensagem do usuário; a resposta volta com stop_reason: "tool_use" e um bloco tool_use; você executa e devolve o tool_result com tool_use_id casando o id.
    2. +
    3. Anel 2 — O loop agêntico: faz o while baseado em stop_reason à mão.
    4. +
    5. Anel 3 — Uso paralelo de ferramentas.
    6. +
    7. Anel 4 — Tratamento de erros com is_error.
    8. +
    9. Anel 5 — Tool Runner: substitui o loop manual pela abstração do SDK.
    10. +
    +
    Dica: cada anel roda standalone — copie qualquer um para um arquivo novo e ele executa sem o código dos anteriores.
    +
    + +
    +

    6.10. Solução de problemas (troubleshooting)

    + +
    + + + + + + + + + + +
    SintomaCausa provávelCorreção
    Claude chama a ferramenta erradaAmbiguidade nas descriçõesAfie as descrições — diferencie por quando usar, não só o que fazem.
    Claude nunca chama sua ferramentaColisão de nomes ou schema genéricoCheque nomes duplicados; adicione input_examples.
    Tipos de parâmetro errados / parâmetro inexistenteModelo adivinhando sem modo estritoAdicione strict: true (se o schema estiver no subconjunto) ou input_examples.
    Chamadas paralelas não funcionamFormatação do históricoEnvie vários tool_result em UMA mensagem de usuário.
    Cache sempre invalidatool_choice variandoMantenha tool_choice estável ou ponha o breakpoint antes do ponto de variação.
    tool_use ids ... without tool_result blocks immediately afterFalta tool_result ou ele não é o primeiro blocoUm tool_result por tool_use, antes de qualquer texto.
    Comparação de string em inputs falha (modelos atuais)Escaping de Unicode/barra muda entre versõesFaça json.loads()/JSON.parse() — nunca compare strings serializadas cruas.
    +
    + + + + +
    +

    7. Agent Skills

    + +

    Agent Skills são capacidades modulares que estendem o Claude. Cada Skill empacota instruções, metadados e recursos opcionais (scripts, templates) que o Claude usa automaticamente quando relevantes. Diferentemente de prompts (instruções de conversa para tarefas pontuais), Skills carregam sob demanda e eliminam a necessidade de repetir a mesma orientação em várias conversas. Benefícios: especializar o Claude, reduzir repetição (criar uma vez, usar automaticamente) e compor capacidades. Não elegível para ZDR.

    + +

    Divulgação progressiva: três níveis de carregamento

    +

    Skills são diretórios no sistema de arquivos da VM do Claude. A arquitetura habilita divulgação progressiva — o Claude carrega informação em estágios, conforme necessário:

    +
    + + + + + + +
    NívelQuando carregaCusto de tokensConteúdo
    Nível 1: MetadadosSempre (no startup)~100 tokens por Skillname e description do frontmatter YAML
    Nível 2: InstruçõesQuando a Skill é acionadaMenos de 5k tokensCorpo do SKILL.md com instruções e orientação
    Nível 3+: RecursosConforme necessárioEfetivamente ilimitadoArquivos empacotados executados via bash sem carregar conteúdo no contexto
    +

    Skills rodam em um ambiente de code execution com acesso ao sistema de arquivos. Quando uma Skill é acionada, o Claude lê o SKILL.md via bash; se ele referencia outros arquivos (FORMS.md, schema), o Claude os lê também; quando há scripts executáveis, o Claude os roda via bash e recebe só a saída (o código do script nunca entra no contexto). Isso permite acesso a arquivos sob demanda, execução eficiente de scripts e nenhum limite prático de conteúdo empacotado não usado.

    + +

    Estrutura de uma Skill (SKILL.md)

    +

    Toda Skill exige um arquivo SKILL.md com frontmatter YAML. Campos obrigatórios: name e description.

    +
    ---
    +name: pdf-processing
    +description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
    +---
    +
    +# PDF Processing
    +
    +## Instructions
    +[Orientação clara, passo a passo, para o Claude seguir]
    +
    +## Examples
    +[Exemplos concretos de uso]
    +

    Requisitos: name ≤ 64 caracteres, só minúsculas/números/hífens, sem tags XML, sem as palavras reservadas "anthropic"/"claude"; description não vazia, ≤ 1024 caracteres, sem tags XML, devendo incluir o que a Skill faz e quando usá-la.

    +

    Skills pré-construídas (mesmo mecanismo das custom): PowerPoint (pptx), Excel (xlsx), Word (docx) e PDF (pdf).

    + +
    Cuidado — segurança: use Skills apenas de fontes confiáveis (criadas por você ou obtidas da Anthropic). Uma Skill maliciosa pode direcionar o Claude a invocar ferramentas ou executar código de formas que não correspondem ao propósito declarado. Audite todo o conteúdo (SKILL.md, scripts, recursos), desconfie de Skills que buscam dados de URLs externas, e trate a instalação com o mesmo rigor de instalar software em produção.
    +
    + +
    +

    7.1. Quickstart de Agent Skills

    + +

    O quickstart mostra como começar a usar as Skills pré-construídas (PowerPoint, Excel, Word, PDF) na API. As Skills integram-se à Messages API através da ferramenta code execution, especificando-se a Skill no parâmetro container (ver guia da API a seguir).

    +
    + +
    +

    7.2. Usando Skills com a Claude API

    + +

    Skills integram-se à Messages API via code execution, com a mesma estrutura container tanto para Skills da Anthropic quanto custom. Pré-requisitos: API key, a ferramenta code execution habilitada, e três headers beta: code-execution-2025-08-25 (Skills rodam no contêiner de code execution), skills-2025-10-02 (habilita Skills) e files-api-2025-04-14 (para upload/download de arquivos do contêiner).

    +
    + + + + + + + + +
    AspectoSkills da AnthropicSkills custom
    typeanthropiccustom
    skill_idNomes curtos: pptx, xlsx, docx, pdfGerado: skill_01AbCd...
    Formato de versionPor data: 20251013 ou latestTimestamp epoch ou latest
    GestãoPré-construídas e mantidas pela AnthropicUpload/gestão via Skills API (/v1/skills)
    DisponibilidadeTodos os usuáriosPrivada ao seu workspace
    +

    As Skills vão no parâmetro container (até 8 Skills por requisição); especifique type e skill_id, opcionalmente version.

    +
    +
    + +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: code-execution-2025-08-25,skills-2025-10-02" \
    +  -H "content-type: application/json" \
    +  -d '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 4096,
    +    "container": {
    +      "skills": [
    +        {"type": "anthropic", "skill_id": "pptx", "version": "latest"}
    +      ]
    +    },
    +    "messages": [{"role": "user", "content": "Create a presentation about renewable energy"}],
    +    "tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
    +  }'
    +
    +
    +
    Nota — onde funcionam: Custom Skills não sincronizam entre superfícies (claude.ai, API, Claude Code são separadas). Escopo de compartilhamento: claude.ai (só o usuário individual), Claude API (todo o workspace), Claude Code (pessoal ~/.claude/skills/ ou de projeto .claude/skills/). Na Claude API, o runtime das Skills não tem acesso à internet, não permite instalação de pacotes em runtime — só os pré-instalados do code execution.
    +
    + +
    +

    7.3. Boas práticas de autoria de Skills

    + +
      +
    • Concisão é a chave. O contexto é um bem público. Assuma que o Claude já é muito inteligente — só adicione contexto que ele não tem. Questione cada parágrafo: "o Claude realmente precisa disso?".
    • +
    • Ajuste os graus de liberdade à fragilidade da tarefa. Alta liberdade (instruções em texto) quando várias abordagens são válidas; média (pseudocódigo/scripts com parâmetros) quando há um padrão preferido; baixa (scripts específicos, poucos parâmetros) quando operações são frágeis e a consistência é crítica ("Run exactly this script... Do not modify").
    • +
    +
    + +
    +

    7.4. Skills para empresas (governança)

    + +

    Guia para admins e arquitetos que governam Skills em escala organizacional. Cobre revisão de segurança e vetting (avaliação de tier de risco contra indicadores: execução de código, manipulação de instruções, referências a MCP, padrões de rede, credenciais hardcoded, escopo de acesso a arquivos), uma checklist de revisão (ler todo o conteúdo, verificar comportamento dos scripts em sandbox, checar instruções adversariais e exfiltração, confirmar ausência de credenciais), e avaliação antes do deploy em cinco dimensões: precisão de acionamento, comportamento em isolamento, coexistência (a nova Skill degrada as outras?), seguimento de instruções e qualidade de saída.

    +

    Exija suites de avaliação com 3–5 queries representativas por Skill (casos que devem e não devem acionar + bordas ambíguas), testando nos modelos usados (Haiku, Sonnet, Opus), pois a eficácia varia por modelo. Ciclo de vida: Planejar → Criar e revisar → Testar → Implantar → Monitorar → Iterar ou descontinuar, com separação de funções (autores não revisam a si mesmos).

    +
    + + + + +
    +

    8. MCP — Model Context Protocol

    + +

    O MCP connector permite conectar a servidores MCP remotos diretamente da Messages API, sem implementar um cliente MCP separado. Beta — header mcp-client-2025-11-20 (a versão anterior mcp-client-2025-04-04 está depreciada). Não elegível para ZDR. Recursos: integração direta, chamada de ferramentas via Messages API, configuração flexível (habilitar todas, allowlist ou denylist), autenticação OAuth e múltiplos servidores numa requisição.

    +
    Atenção — limitações: da especificação MCP, apenas chamadas de ferramenta são suportadas hoje. O servidor deve ser exposto publicamente via HTTP (Streamable HTTP ou SSE); servidores STDIO locais não podem ser conectados diretamente (use MCP tunnels). Disponível na Claude API, Claude Platform on AWS e Microsoft Foundry (não em Bedrock/Vertex AI).
    + +

    Os dois componentes

    +

    O MCP connector usa: (1) MCP Server Definition — o array mcp_servers, que define conexão (URL, autenticação); (2) MCP Toolset — entrada mcp_toolset no array tools, que configura quais ferramentas habilitar.

    +

    Campos de mcp_servers: type (apenas "url"), url (deve começar com https://), name (identificador único, referenciado por exatamente um toolset) e authorization_token (opcional, token OAuth se o servidor exigir).

    +
    +
    + + +
    +
    +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +response = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1000,
    +    messages=[{"role": "user", "content": "What tools do you have available?"}],
    +    mcp_servers=[
    +        {"type": "url", "url": "https://example-server.modelcontextprotocol.io/sse",
    +         "name": "example-mcp", "authorization_token": "YOUR_TOKEN"}
    +    ],
    +    tools=[{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}],
    +    betas=["mcp-client-2025-11-20"],
    +)
    +print(response)
    +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  -H "Content-Type: application/json" \
    +  -H "X-API-Key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: mcp-client-2025-11-20" \
    +  -d '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1000,
    +    "messages": [{"role": "user", "content": "What tools do you have available?"}],
    +    "mcp_servers": [
    +      {"type": "url", "url": "https://example-server.modelcontextprotocol.io/sse",
    +       "name": "example-mcp", "authorization_token": "YOUR_TOKEN"}
    +    ],
    +    "tools": [{"type": "mcp_toolset", "mcp_server_name": "example-mcp"}]
    +  }'
    +
    +
    + +

    Configuração do MCP toolset

    +

    O mcp_toolset tem mcp_server_name (deve casar com um name em mcp_servers), default_config (configuração padrão aplicada a todas as ferramentas do conjunto), configs (overrides por ferramenta) e cache_control. Cada config aceita enabled (padrão true) e defer_loading (padrão false). Precedência (maior → menor): config específica em configs, default_config, padrões do sistema.

    +

    Padrões comuns:

    +
    + + + + + + +
    PadrãoComo
    Habilitar todasSó {"type": "mcp_toolset", "mcp_server_name": "..."}
    Allowlist (só específicas)default_config: {enabled: false} + configs habilitando ferramentas específicas
    Denylist (desabilitar específicas)Default habilitado + configs com enabled: false nas indesejadas
    +
    {
    +  "type": "mcp_toolset",
    +  "mcp_server_name": "google-calendar-mcp",
    +  "default_config": { "enabled": false },
    +  "configs": {
    +    "search_events": { "enabled": true },
    +    "create_event":  { "enabled": true }
    +  }
    +}
    +
    + +
    +

    8.1. Servidores MCP remotos

    + +

    Várias empresas implantaram servidores MCP remotos que desenvolvedores podem conectar via o MCP connector. Para conectar: revise a documentação do servidor, garanta credenciais de autenticação e siga as instruções específicas de cada empresa.

    +
    Atenção: esses servidores são serviços de terceiros, não são da Anthropic. Conecte-se apenas a servidores que você confia e revise as práticas de segurança e termos de cada um. Há centenas de servidores MCP no GitHub.
    +
    + +
    +

    8.2. MCP tunnels

    + +

    MCP tunnels conectam o Claude a servidores MCP que rodam dentro da sua rede privada. O tráfego flui por uma conexão somente de saída (outbound-only), então você não abre portas de entrada no firewall, não expõe serviços à internet pública nem precisa fazer allowlist dos IPs da Anthropic. Beta (research preview, exige solicitar acesso); depende de um provedor de rede terceiro (Cloudflare).

    + +

    Como funciona

    +

    Uma implantação tem dois componentes na sua rede: cloudflared (o agente de túnel, que inicia conexões outbound-only para a borda do túnel operada pela Anthropic) e Proxy (componente de roteamento da Anthropic que termina o TLS interno, valida que os IPs upstream estão num intervalo permitido e roteia por hostname). Cada servidor MCP exposto ganha um hostname sob seu domínio de túnel (ex.: docs.<seu-dominio-de-tunel>), que você anexa a uma sessão de Managed Agent no Console ou passa à Messages API via MCP connector.

    + +

    Modelo de segurança (três camadas)

    +
    + + + + + + +
    CamadaProtege contra
    mTLS externo (Anthropic ↔ provedor de transporte) com validação de IPClientes não autorizados alcançarem o túnel
    TLS interno (backend da Anthropic → seu proxy)Inspeção de payload pelo provedor de transporte ou intermediários
    OAuth em cada servidor MCPUso não autorizado de ferramentas MCP por tráfego autenticado do túnel
    +

    Como o proxy termina o TLS interno com um certificado que só você possui, a Cloudflare não consegue ler payloads (recebe apenas metadados: IP de egresso, fingerprint do host cloudflared, timing/volume, e o subdomínio *.tunnel.anthropic.com).

    +
    Cuidado: se um atacante obtiver seu tunnel token e uma de suas chaves privadas TLS, poderá personificar seu proxy e ler payloads de requisições MCP. Trate ambos como segredos de alto valor.
    + +

    Usando os servidores tunelados

    +

    Uma vez ativo o túnel (com certificado CA ativo e stack conectado), os servidores MCP roteados ficam acessíveis a partir de Claude Managed Agents e da Messages API. O túnel carrega o tráfego criptografado mas não autentica ao servidor — se o upstream exige OAuth/bearer próprio, forneça-o como faria com qualquer servidor MCP. Pela Messages API, passe a URL roteada no array mcp_servers: o host é <subdominio>.<seu-dominio-de-tunel> e o path é o que seu servidor upstream serve (FastMCP streamable-http usa /mcp). O corpo e o header anthropic-beta: mcp-client-2025-11-20 seguem o formato padrão do MCP connector — só a url é específica do túnel.

    +
    Nota: túneis MCP criados pelo Console não aparecem como conectores no claude.ai.
    + +

    Quickstart, deploy e operação

    +

    Documentação operacional do MCP tunnels:

    +
      +
    • Quickstart (doc): caminho mais curto, com Docker Compose e credenciais manuais. Um stack de três contêineres (servidor MCP de amostra, proxy do túnel, conector outbound); o servidor fica acessível em https://echo.<seu-dominio>/mcp sem nada escutando em porta pública. Precisa de Docker/Compose, papel no Console que gerencie túneis, e OpenSSL 1.1.1+.
    • +
    • Deploy com Docker Compose (doc): stack como contêineres endurecidos em um único host, replicável em vários hosts. Requer túnel criado no Console (ID tnl_...).
    • +
    • Deploy com Helm (doc): chart oficial da Anthropic que instala o stack como um único Deployment em um cluster Kubernetes.
    • +
    • Gerenciar no Console (doc): criar túnel, registrar certificado CA, recuperar o tunnel token e anexar servidores a agentes. Autenticação à Tunnels API por Workload Identity Federation (recomendado, escopo org:manage_tunnels) ou credenciais manuais.
    • +
    • Referência (doc): config do proxy (/etc/mcp-gateway/config.yaml) com listen_addr, tunnel_domain, tls.cert_file/key_file, routes (mapa subdomínio → upstream scheme://host:port), upstream.allowed_ips (defesa primária contra SSRF, padrão RFC1918); mais a Tunnels REST API e o CLI de setup.
    • +
    • Segurança (doc): exigir OAuth em cada servidor, habilitar SSO, restringir upstream.allowed_ips ao menor CIDR, monitorar logs, rotacionar credenciais, fixar imagens por digest SHA-256, limitar alcance de rede.
    • +
    • Troubleshooting (doc): diagnóstico de conectividade, TLS e roteamento.
    • +
    +

    Requisitos de rede (saída): api.anthropic.com (443 TCP, provisionamento/rotação de token); cloudflared para a borda do túnel (198.41.192.0/19, 2606:4700:a0::/44, porta 7844 TCP e UDP, contínuo); proxy para seus servidores MCP upstream.

    +
    + + + + + + + + +
    +

    Parte D — Referência REST/SDK, Agentes Gerenciados, Governança & Nuvem

    +

    Esta parte é a referência canônica de baixo nível: os SDKs oficiais (com foco em Python e JavaScript/TypeScript; demais linguagens citadas como referência), o contrato REST language-neutral da API de Mensagens, Token Counting, Message Batches, Models e Files, os códigos de erro e rate limits, as plataformas de nuvem (Amazon Bedrock, Vertex AI, Microsoft Foundry, Claude Platform on AWS), os Claude Managed Agents (harness gerenciado) e o plano de governança/Admin (Admin API, workspaces, Workload Identity Federation, Usage & Cost, retenção e residência de dados, Compliance API).

    +
    + + + + +
    +

    1. SDKs oficiais

    +

    A Anthropic mantém SDKs idiomáticos para oito superfícies, todos com tipagem, streaming, retries e tratamento de erros embutidos. Todos enviam automaticamente o header anthropic-version: 2023-06-01 e leem a chave da variável de ambiente ANTHROPIC_API_KEY. Os mesmos clientes suportam as plataformas de nuvem (Bedrock, Vertex AI, Foundry, Claude Platform on AWS) através de classes/pacotes específicos — veja a seção 9.

    + +
    SDKs em profundidade: esta seção dá a visão geral e o contrato REST. Para uso completo dos SDKs, veja a Parte E — SDK Python (anthropic) e a Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk): clientes sync/async, todas as opções, streaming, helpers de ferramentas e MCP, batches, paginação, hierarquia de erros, retries/timeouts, respostas cruas, logging, namespace beta e clientes/pacotes de plataforma.
    + +

    1.1. Pacotes, instalação e versão mínima

    +
    Foco deste guia: os SDKs cobertos em profundidade são Python + (Parte E) e JavaScript/TypeScript (Parte F). + A Anthropic também mantém SDKs oficiais para Java, Go, C#/.NET, Ruby e PHP, além de uma CLI — citados aqui apenas como + referência; consulte a doc oficial para detalhes deles.
    +
    + + + + + + + + + + +
    LinguagemPacoteInstalaçãoRuntime / referência
    Python focoanthropicpip install anthropicPython 3.9+ · ver Parte E
    JavaScript/TypeScript foco@anthropic-ai/sdknpm install @anthropic-ai/sdkTS 4.9+ (Node 20+, Deno, Bun, Workers) · ver Parte F
    Java referênciacom.anthropic:anthropic-javaimplementation("com.anthropic:anthropic-java")Java 8+
    Go referênciaanthropic-sdk-gogo get github.com/anthropics/anthropic-sdk-goGo 1.23+
    C# / .NET referênciaAnthropicdotnet add package Anthropic.NET Standard 2.0+
    Ruby referênciaanthropicbundle add anthropicRuby 3.2.0+
    PHP referênciaanthropic-ai/sdkcomposer require anthropic-ai/sdkPHP 8.1.0+
    +
    Nota: versões de pacote são fatos perecíveis. Verifique a versão instalada com anthropic.__version__ (Python) ou pelo gerenciador de pacotes (npm ls @anthropic-ai/sdk). Repositórios oficiais: anthropics/anthropic-sdk-python e anthropics/anthropic-sdk-typescript (foco), além de -java, -go, -ruby, -csharp, -php.
    + +

    1.2. Inicialização do client (síncrono e assíncrono)

    +

    O exemplo "Olá, Claude" em três superfícies. Em Python existem dois clients: Anthropic() (síncrono) e AsyncAnthropic() (assíncrono, mesma interface com await).

    +
    +
    + + + +
    +
    +
    import os
    +from anthropic import Anthropic, AsyncAnthropic
    +
    +# Síncrono — api_key é opcional (lê ANTHROPIC_API_KEY do ambiente)
    +client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
    +
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +print(message.content[0].text)
    +
    +# Assíncrono — mesma API, com await
    +import asyncio
    +aclient = AsyncAnthropic()
    +
    +async def main():
    +    msg = await aclient.messages.create(
    +        model="claude-opus-4-8",
    +        max_tokens=1024,
    +        messages=[{"role": "user", "content": "Olá, Claude"}],
    +    )
    +    print(msg.content[0].text)
    +
    +asyncio.run(main())
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic(); // lê ANTHROPIC_API_KEY do ambiente
    +
    +const message = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Olá, Claude" }],
    +});
    +console.log(message.content);
    +
    +
    +
    # CLI oficial (ant)
    +ant messages create \
    +  --model claude-opus-4-8 \
    +  --max-tokens 1024 \
    +  --message '{role: user, content: "Olá, Claude"}' \
    +  --transform content
    +
    +
    + +

    1.3. Recursos do SDK: streaming, retries, timeouts, paginação

    +

    Os SDKs encapsulam quatro comportamentos operacionais. Os valores abaixo são os defaults do SDK Python; outros SDKs seguem convenções equivalentes.

    +
    + + + + + + + +
    RecursoComportamento padrãoComo configurar
    StreamingSSE evento a evento via stream=True; ou helper de contexto client.messages.stream(...) com text_stream e get_final_message()stream=True (iterável de eventos, menos memória) ou with client.messages.stream(...) as s:
    Retries2 tentativas automáticas com backoff exponencial em erros de conexão, 408, 409, 429 e ≥500Anthropic(max_retries=0) ou client.with_options(max_retries=5)
    Timeouts10 minutos por padrão; lança APITimeoutErrorAnthropic(timeout=20.0) ou httpx.Timeout(...) granular
    Auto-paginaçãoItera entre páginas automaticamente em métodos list()for batch in client.messages.batches.list(limit=20): · ou .has_next_page()/.get_next_page()
    +
    +
    + + +
    +
    +
    from anthropic import Anthropic
    +
    +client = Anthropic(max_retries=2, timeout=600.0)
    +
    +# Streaming com helper de contexto: acumula texto e mensagem final
    +with client.messages.stream(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Escreva um haicai"}],
    +) as stream:
    +    for text in stream.text_stream:
    +        print(text, end="", flush=True)
    +    final = stream.get_final_message()
    +    print("\n", final.usage)
    +
    +# Auto-paginação: percorre todas as páginas de batches
    +for batch in client.messages.batches.list(limit=20):
    +    print(batch.id)
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic({ maxRetries: 2, timeout: 600_000 });
    +
    +// Streaming: helper com finalMessage()
    +const stream = client.messages.stream({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Escreva um haicai" }],
    +});
    +for await (const event of stream) {
    +  if (event.type === "content_block_delta") process.stdout.write(JSON.stringify(event.delta));
    +}
    +const finalMessage = await stream.finalMessage();
    +console.log(finalMessage.usage);
    +
    +
    +
    Dica: em Python, pip install "anthropic[aiohttp]" habilita o backend DefaultAioHttpClient para melhor concorrência assíncrona. client.with_raw_response.create(...) expõe headers da resposta (por exemplo request-id); message._request_id é a propriedade pública para correlacionar requisições com o suporte.
    +
    Atenção (requisições longas): evite max_tokens alto sem streaming. O SDK lança ValueError se uma requisição não-streaming for estimada em > ~10 minutos. Use stream=True (ou o helper .stream() com get_final_message()) para gerações longas. O SDK define TCP keep-alive para mitigar quedas de conexões ociosas.
    +
    + + + + +
    +

    2. Referência REST — endpoints & autenticação

    +

    A API REST da Anthropic é language-neutral: os SDKs são wrappers finos sobre os endpoints HTTP descritos aqui. Base URL (API de primeira parte): https://api.anthropic.com. As plataformas de nuvem usam base URLs próprias (veja a seção 9).

    + + +

    2.1. Headers obrigatórios e versionamento

    +
    + + + + + + + +
    HeaderValorObrigatório
    x-api-keyChave da API sk-ant-api... (ou bearer token em plataformas de nuvem)Sim (ou Authorization: Bearer com WIF/OAuth)
    anthropic-version2023-06-01Sim
    content-typeapplication/jsonSim (para corpos JSON)
    anthropic-betaLista de features beta, ex. files-api-2025-04-14Apenas quando a feature exigir
    +

    A política de versionamento garante, para uma dada versão da Messages API, a preservação dos parâmetros de entrada e saída existentes. A Anthropic pode: adicionar inputs opcionais, adicionar valores à saída, alterar condições de erro e adicionar novas variantes a enums de saída (por exemplo, novos tipos de eventos de streaming). Trate enums de saída como abertos.

    + + +

    2.2. Mapa de endpoints REST

    +
    + + + + + + + + + + + + + + + + + + + +
    RecursoMétodo & caminhoDescrição
    MessagesPOST /v1/messagesGera a próxima mensagem da conversa
    Token CountingPOST /v1/messages/count_tokensConta tokens sem gerar
    Batches — criarPOST /v1/messages/batchesCria lote de requisições
    Batches — listarGET /v1/messages/batchesLista lotes (paginado)
    Batches — recuperarGET /v1/messages/batches/{id}Estado do lote
    Batches — resultadosGET /v1/messages/batches/{id}/resultsStream JSONL de resultados
    Batches — cancelarPOST /v1/messages/batches/{id}/cancelInicia cancelamento
    Batches — deletarDELETE /v1/messages/batches/{id}Remove lote (precisa estar ended)
    Models — listarGET /v1/modelsModelos disponíveis
    Models — recuperarGET /v1/models/{model_id}Metadados de um modelo
    Files (beta)POST/GET/DELETE /v1/filesUpload/listagem/exclusão de arquivos
    Skills (beta)POST/GET/DELETE /v1/skills e /v1/skills/{id}/versionsCRUD de Skills custom e versionamento (header skills-2025-10-02)
    OAuth (WIF)POST /v1/oauth/tokenTroca de JWT por token de acesso
    Admin / Organização/v1/organizations/*Admin API (requer chave sk-ant-admin...)
    Compliance/v1/compliance/*Atividade, chats, arquivos (Claude Enterprise)
    Managed Agents (beta)/v1/agents, /v1/sessions, /v1/environments …Harness de agentes gerenciados
    +
    + + + + +
    +

    3. POST /v1/messages — corpo da requisição & resposta

    +

    Envia uma lista estruturada de mensagens de entrada (texto e/ou imagem) e o modelo gera a próxima mensagem. Pode ser usado para consultas únicas ou conversas multi-turno stateless.

    + + +

    3.1. Parâmetros do corpo (request body)

    +
    + + + + + + + + + + + + + + + + + + + + + + +
    ParâmetroTipoObrig.Descrição
    modelstring (Model)SimID do modelo, ex. claude-opus-4-8
    messagesarray de MessageParamSimTurnos alternados user/assistant. content é string ou array de blocos. Limite de 100.000 mensagens por requisição
    max_tokensnumberSimMáximo de tokens a gerar. 0 pré-aquece o cache sem gerar. Máximo varia por modelo
    systemstring ou array de TextBlockParamNãoPrompt de sistema. Não existe role "system" em messages
    metadataobjectNão{ user_id } — identificador opaco para detecção de abuso
    stop_sequencesarray de stringNãoStrings que param a geração; produzem stop_reason: "stop_sequence"
    streambooleanNãoStreaming via SSE
    temperaturenumberNão0.0–1.0, default 1.0
    top_pnumberNãoNucleus sampling (uso avançado)
    top_knumberNãoAmostragem entre os top-K tokens (uso avançado)
    toolsarray de ToolUnionNãoDefinições de ferramentas (function calling / server tools)
    tool_choiceToolChoiceNãoauto · any · tool (específica) · none
    thinkingThinkingConfigParamNãoadaptive (recomendado para Opus 4.8) · enabled (com budget_tokens) · disabled
    service_tier"auto" ou "standard_only"NãoSeleção de tier de capacidade
    containerstringNãoReuso de container entre requisições (code execution)
    context_managementobjectNãoCompactação / edição de contexto server-side (beta)
    output_format / output_configobjectNãoSaída estruturada (JSON schema) e nível de effort
    mcp_serversarrayNãoServidores MCP remotos (MCP connector, beta)
    inference_geostringNão"global" (default) ou "us" — residência de inferência (veja a seção 11.6)
    +
    Atenção (sampling depreciado): temperature, top_p e top_k retornam 400 quando definidos com valor não-default em Claude Opus 4.7, Opus 4.8, Sonnet 5, Fable 5 e Mythos 5 (seguem válidos em Opus 4.6, Sonnet 4.6 e modelos anteriores). Isso vale em toda requisição, independentemente de thinking estar ativo. Os campos continuam nos tipos do SDK para compatibilidade de type-check, mas a API rejeita valores não-default — omita-os e guie a variedade estilística por prompting (recomendação oficial). Ao migrar de Sonnet 4.6 → Sonnet 5, audite chamadas com temperature/top_p explícitos antes de trocar o ID. Fonte: model-deprecations.
    +
    Atenção (prefill): Claude Opus 4.8 e Sonnet 4.6 não suportam pré-preencher (prefill) a última mensagem assistant. Enviar um turno assistant final retorna 400 invalid_request_error. Use saída estruturada (output_config.format), instruções no system prompt ou structured outputs.
    + +

    3.2. Objeto de resposta (Message)

    +
    + + + + + + + + + + + + + +
    CampoTipoDescrição
    idstringIdentificador único da mensagem (ex. msg_013Zva...)
    type"message"Sempre "message"
    role"assistant"Sempre "assistant"
    contentarray de ContentBlockBlocos gerados: text, thinking, redacted_thinking, tool_use, server_tool_use, web_search_tool_result, web_fetch_tool_result, code_execution_tool_result, container_upload, entre outros
    modelstringModelo que atendeu a requisição
    stop_reasonenumMotivo do término (tabela abaixo)
    stop_sequencestring ou nullA stop_sequence que disparou o término, se houver
    usageUsageContagem de tokens / billing (seção 3.3)
    stop_detailsobjectDetalhes de recusa: category ("cyber"/"bio"; no Fable 5 também "reasoning_extraction" — bloqueio por engenharia reversa/duplicação de outputs sob os ToS, desde 09/06/2026), explanation, type: "refusal"
    containerobject{ id, expires_at } quando a ferramenta de code execution é usada
    +

    Valores de stop_reason:

    +
    + + + + + + + + + +
    ValorSignificado
    "end_turn"Ponto de parada natural
    "max_tokens"Atingiu max_tokens ou o máximo do modelo
    "stop_sequence"Gerou uma das stop_sequences
    "tool_use"O modelo invocou uma ou mais ferramentas
    "pause_turn"Turno longo pausado; reenvie a resposta para continuar
    "refusal"Classificador de streaming interveio por política
    +
    Nota: em modo não-streaming, stop_reason é sempre não-nulo. Em streaming, é null no evento message_start e não-nulo nos demais.
    + +

    3.3. Objeto Usage

    +
    + + + + + + + + + + + +
    CampoTipoDescrição
    input_tokensnumberTokens de entrada (excluindo tokens de cache)
    output_tokensnumberTokens de saída gerados
    cache_creation_input_tokensnumberTokens usados para criar entrada de cache
    cache_read_input_tokensnumberTokens lidos do cache
    cache_creationobjectDetalhe: ephemeral_5m_input_tokens e ephemeral_1h_input_tokens
    server_tool_useobjectContagem de chamadas server-side: web_search_requests, web_fetch_requests
    service_tierenum"standard" · "priority" · "batch"
    inference_geostringGeografia onde a inferência rodou
    +
    Dica: total de tokens de entrada = input_tokens + cache_creation_input_tokens + cache_read_input_tokens.
    + +

    3.4. Exemplo completo

    +
    +
    + + +
    +
    +
    curl https://api.anthropic.com/v1/messages \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{"role": "user", "content": "Olá, Claude"}]
    +  }'
    +
    +
    +
    import anthropic
    +client = anthropic.Anthropic()
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +print(message.content[0].text)
    +print(message.usage)  # Usage(input_tokens=..., output_tokens=...)
    +
    +
    +
    Resposta JSON (200) +
    {
    +  "id": "msg_013Zva2CMHLNnXjNJJKqJ2EF",
    +  "type": "message",
    +  "role": "assistant",
    +  "content": [{"type": "text", "text": "Olá! Sou o Claude."}],
    +  "model": "claude-opus-4-8",
    +  "stop_reason": "end_turn",
    +  "stop_sequence": null,
    +  "usage": {
    +    "input_tokens": 2095,
    +    "output_tokens": 503,
    +    "cache_creation_input_tokens": 0,
    +    "cache_read_input_tokens": 0,
    +    "service_tier": "standard"
    +  }
    +}
    +
    +
    + + + + +
    +

    4. POST /v1/messages/count_tokens

    +

    Conta o número de tokens de uma Message — incluindo tools, imagens e documentos — sem criar a mensagem. Útil para validar custos e limites antes de enviar. Aceita os mesmos parâmetros relevantes da Messages API: model, messages, system, tools, tool_choice, thinking, mcp_servers (mas não max_tokens).

    + +

    A resposta é um objeto simples com input_tokens (number). O limite de tamanho de requisição é o mesmo da Token Counting API (32 MB).

    +
    +
    + + +
    +
    +
    curl https://api.anthropic.com/v1/messages/count_tokens \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "model": "claude-opus-4-8",
    +    "messages": [{"role": "user", "content": "Olá, mundo"}]
    +  }'
    +# -> {"input_tokens": 10}
    +
    +
    +
    count = client.messages.count_tokens(
    +    model="claude-opus-4-8",
    +    messages=[{"role": "user", "content": "Olá, mundo"}],
    +)
    +print(count.input_tokens)  # 10
    +
    +
    +
    + + + + +
    +

    5. Message Batches API

    +

    Processa múltiplas requisições da Messages API de uma vez, de forma assíncrona, com desconto de 50% sobre o preço padrão. Um lote começa a processar imediatamente e pode levar até 24 horas. Resultados ficam disponíveis por 29 dias. Para o lado conceitual do processamento em lote (quando usar, trade-offs, custo), veja a Parte A — Batch Processing; aqui detalhamos os endpoints REST e o ciclo de vida do objeto MessageBatch.

    + + +

    5.1. Criar um lote

    +

    O corpo é um array requests; cada item tem um custom_id (único por lote, usado para casar resultados) e params (os mesmos parâmetros da Messages API).

    +
    +
    + + +
    +
    +
    curl https://api.anthropic.com/v1/messages/batches \
    +  --header "x-api-key: $ANTHROPIC_API_KEY" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "content-type: application/json" \
    +  --data '{
    +    "requests": [
    +      {
    +        "custom_id": "req-1",
    +        "params": {
    +          "model": "claude-opus-4-8",
    +          "max_tokens": 1024,
    +          "messages": [{"role": "user", "content": "Olá, mundo"}]
    +        }
    +      }
    +    ]
    +  }'
    +
    +
    +
    batch = client.messages.batches.create(
    +    requests=[
    +        {
    +            "custom_id": "req-1",
    +            "params": {
    +                "model": "claude-opus-4-8",
    +                "max_tokens": 1024,
    +                "messages": [{"role": "user", "content": "Olá, mundo"}],
    +            },
    +        },
    +    ]
    +)
    +print(batch.id, batch.processing_status)
    +
    +
    + +

    5.2. Objeto MessageBatch e ciclo de vida

    +
    + + + + + + + + + + + + + +
    CampoTipoDescrição
    idstringEx. msgbatch_013Zva...
    type"message_batch"Sempre "message_batch"
    processing_statusenum"in_progress" · "canceling" · "ended"
    request_countsobjectprocessing, succeeded, errored, canceled, expired
    created_atstring (RFC 3339)Criação
    ended_atstringQuando todas as requisições terminaram (só após ended)
    expires_atstringExpiração (24h após criação)
    archived_atstringQuando os resultados ficaram indisponíveis
    cancel_initiated_atstringInício do cancelamento, se houve
    results_urlstringURL do arquivo .jsonl (só após ended)
    +
    Nota: os contadores em request_counts permanecem zerados (exceto processing) até o lote inteiro terminar. Um lote precisa estar ended antes de ser deletado — cancele primeiro se ainda estiver em progresso. A exclusão retorna { "id": "...", "type": "message_batch_deleted" }.
    + +

    5.3. Resultados em JSONL

    +

    O endpoint /results faz stream de um arquivo .jsonl: cada linha é um MessageBatchIndividualResponse com custom_id e result. Os resultados não são garantidos na ordem das requisições — use custom_id para casar. O result.type assume: "succeeded" (com message), "errored" (com error), "canceled" ou "expired".

    +
    Linha JSONL de resultado (succeeded) +
    {
    +  "custom_id": "req-1",
    +  "result": {
    +    "type": "succeeded",
    +    "message": {
    +      "id": "msg_abc123",
    +      "type": "message",
    +      "role": "assistant",
    +      "content": [{"type": "text", "text": "Olá!"}],
    +      "stop_reason": "end_turn",
    +      "usage": {"input_tokens": 11, "output_tokens": 4}
    +    }
    +  }
    +}
    +
    +
    +
    + +
    +
    +
    # Após .processing_status == "ended"
    +result_stream = client.messages.batches.results("msgbatch_abc123")
    +for entry in result_stream:
    +    if entry.result.type == "succeeded":
    +        print(entry.custom_id, entry.result.message.content)
    +    elif entry.result.type == "errored":
    +        print(entry.custom_id, "erro:", entry.result.error)
    +
    +
    +
    + + + + +
    +

    6. Models API

    +

    Determina quais modelos estão disponíveis para a sua conta. Modelos mais recentes aparecem primeiro. Dois endpoints: GET /v1/models (lista paginada) e GET /v1/models/{model_id} (recupera um).

    +
    Nota de fronteira: a tabela geral de modelos, capacidades e preços da API direta vive na Parte A — Modelos, e a referência detalhada da Models API em Parte A — Models API. Esta seção documenta o esquema do endpoint do ponto de vista REST/SDK, sem reproduzir a tabela de modelos. Os IDs específicos de plataforma (Bedrock/Vertex/Foundry, que diferem da API direta) são registrados na seção 9.
    + + +

    6.1. Listar modelos & paginação

    +

    Query params: before_id / after_id (cursores) e limit (default 20, de 1 a 1000). A resposta traz data[], has_more, first_id e last_id.

    +

    Cada ModelInfo traz: id, type: "model", display_name, created_at (RFC 3339), max_input_tokens, max_tokens e um objeto capabilities que reporta suporte a batch, citations, code_execution, context_management, effort (níveis low/medium/high/max/xhigh), image_input, pdf_input, structured_outputs e thinking (tipos adaptive/enabled).

    +
    +
    + + +
    +
    +
    curl https://api.anthropic.com/v1/models \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "x-api-key: $ANTHROPIC_API_KEY"
    +
    +
    +
    for model in client.models.list(limit=20):
    +    print(model.id, model.display_name, model.max_input_tokens)
    +
    +info = client.models.retrieve("claude-opus-4-8")
    +print(info.created_at, info.capabilities)
    +
    +
    +
    Resposta JSON (200) — recortada +
    {
    +  "data": [
    +    {
    +      "id": "claude-opus-4-8",
    +      "type": "model",
    +      "display_name": "Claude Opus 4.8",
    +      "created_at": "2025-11-01T00:00:00Z",
    +      "capabilities": {
    +        "batch": {"supported": true},
    +        "thinking": {"supported": true, "types": {"adaptive": {"supported": true}, "enabled": {"supported": true}}},
    +        "effort": {"supported": true, "low": {"supported": true}, "medium": {"supported": true}, "high": {"supported": true}, "max": {"supported": true}, "xhigh": {"supported": true}}
    +      }
    +    }
    +  ],
    +  "has_more": true,
    +  "first_id": "...",
    +  "last_id": "..."
    +}
    +
    +
    + + + + +
    +

    7. Files API (lado REST)

    +

    A Files API (beta — header anthropic-beta: files-api-2025-04-14) permite enviar arquivos uma vez e referenciá-los por file_id em múltiplas requisições, em vez de reenviar bytes. Os recursos são escopados por workspace. Endpoints sob /v1/files: upload, listar, recuperar metadados, baixar e deletar. O limite de tamanho de requisição da Files API é 500 MB.

    + +
    Nota: a profundidade conceitual da Files API (tipos de documento, citações, vínculo com blocos document) é coberta na Parte B. Aqui registramos o lado REST/SDK. No SDK Python, o upload aceita PathLike, tupla (filename, content, content_type) ou BinaryIO, via client.beta.files.upload(...).
    +
    +
    + +
    +
    +
    from pathlib import Path
    +from anthropic import Anthropic
    +
    +client = Anthropic()
    +
    +# Upload (beta)
    +f = client.beta.files.upload(file=Path("/caminho/relatorio.pdf"))
    +
    +# Referência por file_id na Messages API
    +resp = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "text", "text": "Resuma este documento."},
    +            {"type": "document", "source": {"type": "file", "file_id": f.id}},
    +        ],
    +    }],
    +    betas=["files-api-2025-04-14"],
    +)
    +
    +
    +
    + + + + +
    +

    7A. Skills API (REST) — CRUD de Skills e versões Beta

    +

    A Skills API (/v1/skills) é a superfície REST para criar, listar, recuperar e deletar Skills custom programaticamente e gerenciar suas versões. É o mecanismo de upload por trás da gestão de Skills custom citada na seção 7.2 (Parte C) — lá o foco é usar Skills via o bloco container.skills na Messages API; aqui é o CRUD do recurso Skill em si. Todas as chamadas a /v1/skills* exigem o header beta anthropic-beta: skills-2025-10-02.

    + + +
    Header beta obrigatório: toda requisição a /v1/skills* precisa de anthropic-beta: skills-2025-10-02 (além do padrão anthropic-version: 2023-06-01 e x-api-key). Os endpoints de criação (Skill e Skill Version) usam Content-Type: multipart/form-data e enviam os arquivos da Skill (SKILL.md + recursos) no campo files.
    + +

    7A.1. CRUD de Skills

    +
    + + + + + + + +
    OperaçãoMétodo & caminhoCorpo / queryDescrição
    Criar SkillPOST /v1/skillsmultipart/form-data, campo filesCria uma Skill custom a partir dos arquivos enviados (SKILL.md + recursos)
    Listar SkillsGET /v1/skillsquery: limit, page, sourceLista Skills, paginado
    Recuperar SkillGET /v1/skills/{skill_id}path: skill_idMetadados de uma Skill específica
    Deletar SkillDELETE /v1/skills/{skill_id}path: skill_idRemove a Skill
    + +

    Objeto Skill (retornado por criar, recuperar e em cada item de listar):

    +
    + + + + + + + + + +
    CampoTipoDescrição
    idstringIdentificador único, ex. skill_01JAbc… (o formato/tamanho de IDs pode mudar)
    type"skill"Tipo do objeto (sempre "skill")
    display_titlestringRótulo legível para humanos — não é incluído no prompt enviado ao modelo
    latest_versionstringIdentificador (timestamp epoch, ex. "1759178010641129") da versão mais recente
    source"custom" · "anthropic"custom: criada pelo usuário; anthropic: mantida pela Anthropic (ex. pptx, xlsx, docx, pdf)
    created_at · updated_atstring (ISO 8601)Timestamps de criação / última atualização
    + +
    +
    + + +
    +
    +
    # Criar Skill custom (multipart, campo "files" repetido por arquivo)
    +curl https://api.anthropic.com/v1/skills \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: skills-2025-10-02" \
    +  -F "files=@./minha-skill/SKILL.md" \
    +  -F "files=@./minha-skill/scripts/gerar.py"
    +
    +# Listar Skills (paginado; filtrando por source)
    +curl "https://api.anthropic.com/v1/skills?limit=20&source=custom" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: skills-2025-10-02"
    +
    +# Recuperar uma Skill
    +curl "https://api.anthropic.com/v1/skills/$SKILL_ID" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: skills-2025-10-02"
    +
    +# Deletar uma Skill
    +curl -X DELETE "https://api.anthropic.com/v1/skills/$SKILL_ID" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: skills-2025-10-02"
    +
    +
    +
    # O exemplo canônico e verificável é o curl (multipart). Os nomes exatos
    +# dos métodos do SDK Python para Skills devem ser conferidos na referência
    +# do SDK anthropic; o padrão segue o namespace client.beta.* usado por Files.
    +import requests, os
    +
    +BASE = "https://api.anthropic.com/v1/skills"
    +HEADERS = {
    +    "x-api-key": os.environ["ANTHROPIC_API_KEY"],
    +    "anthropic-version": "2023-06-01",
    +    "anthropic-beta": "skills-2025-10-02",
    +}
    +
    +# Criar (multipart: um campo "files" por arquivo)
    +files = [
    +    ("files", ("SKILL.md", open("minha-skill/SKILL.md", "rb"))),
    +    ("files", ("gerar.py", open("minha-skill/scripts/gerar.py", "rb"))),
    +]
    +skill = requests.post(BASE, headers=HEADERS, files=files).json()
    +print(skill["id"], skill["display_title"], skill["latest_version"], skill["source"])
    +
    +# Listar (paginação por token next_page)
    +page = requests.get(BASE, headers=HEADERS,
    +                    params={"limit": 20, "source": "custom"}).json()
    +for s in page["data"]:
    +    print(s["id"], s["display_title"], s["latest_version"])
    +# page["has_more"] / page["next_page"] controlam a paginação (page=<next_page>)
    +
    +# Recuperar / Deletar
    +requests.get(f"{BASE}/{skill['id']}", headers=HEADERS)
    +requests.delete(f"{BASE}/{skill['id']}", headers=HEADERS)
    +
    +
    +
    Sobre o exemplo da doc: a referência oficial mostra a forma simplificada -F files='["Example data"]' apenas para ilustrar o campo — no uso real, envie os bytes de cada arquivo com -F "files=@caminho/arquivo" (um files por arquivo), incluindo o SKILL.md.
    + +
    Resposta JSON — POST /v1/skills +
    {
    +  "id": "skill_01JAbcdefghijklmnopqrstuvw",
    +  "created_at": "2024-10-30T23:58:27.427722Z",
    +  "display_title": "My Custom Skill",
    +  "latest_version": "1759178010641129",
    +  "source": "custom",
    +  "type": "skill",
    +  "updated_at": "2024-10-30T23:58:27.427722Z"
    +}
    +
    +
    Resposta JSON — GET /v1/skills (paginada) +
    {
    +  "data": [
    +    {
    +      "id": "skill_01JAbcdefghijklmnopqrstuvw",
    +      "created_at": "2024-10-30T23:58:27.427722Z",
    +      "display_title": "My Custom Skill",
    +      "latest_version": "1759178010641129",
    +      "source": "custom",
    +      "type": "skill",
    +      "updated_at": "2024-10-30T23:58:27.427722Z"
    +    }
    +  ],
    +  "has_more": true,
    +  "next_page": "page_MjAyNS0wNS0xNFQwMDowMDowMFo="
    +}
    +
    +
    Resposta JSON — DELETE /v1/skills/{skill_id} +
    {
    +  "id": "skill_01JAbcdefghijklmnopqrstuvw",
    +  "type": "skill_deleted"
    +}
    +
    + +

    7A.2. Skill Versions

    +

    Cada Skill tem uma ou mais versões, identificadas por um timestamp Unix epoch (ex. "1759178010641129") — não por SemVer. Ao criar uma versão, name e description são extraídos do SKILL.md enviado, e directory é o nome do diretório de topo extraído dos arquivos do upload.

    +
    + + + + + + + +
    OperaçãoMétodo & caminhoCorpo / queryDescrição
    Criar versãoPOST /v1/skills/{skill_id}/versionsmultipart/form-data, campo filesPublica uma nova versão dos arquivos da Skill
    Listar versõesGET /v1/skills/{skill_id}/versionsquery: limit (1–1000, default 20), pageLista versões da Skill, paginado
    Recuperar versãoGET /v1/skills/{skill_id}/versions/{version}path: skill_id, versionMetadados de uma versão específica
    Deletar versãoDELETE /v1/skills/{skill_id}/versions/{version}path: skill_id, versionRemove uma versão específica
    + +
    Pegadinha — o limit difere entre os dois "listar": em GET /v1/skills o limit vai até 100; em GET /v1/skills/{skill_id}/versions vai de 1 a 1000. Ambos têm default 20 e paginam pelo token next_page (passado como page na próxima chamada). Não presuma o mesmo teto nos dois endpoints.
    + +

    Objeto SkillVersion:

    +
    + + + + + + + + + + + +
    CampoTipoDescrição
    idstringIdentificador único da versão, ex. skillver_01JAbc…
    type"skill_version"Tipo do objeto (sempre "skill_version")
    skill_idstringSkill a que esta versão pertence
    versionstringTimestamp epoch da versão, ex. "1759178010641129"
    namestringNome legível, extraído do SKILL.md
    descriptionstringDescrição extraída do SKILL.md
    directorystringNome do diretório de topo extraído dos arquivos enviados
    created_atstring (ISO 8601)Timestamp de criação da versão
    + +
    +
    + +
    +
    +
    # Criar nova versão de uma Skill existente
    +curl "https://api.anthropic.com/v1/skills/$SKILL_ID/versions" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: skills-2025-10-02" \
    +  -F "files=@./minha-skill/SKILL.md" \
    +  -F "files=@./minha-skill/scripts/gerar.py"
    +
    +# Listar versões (limit até 1000 aqui)
    +curl "https://api.anthropic.com/v1/skills/$SKILL_ID/versions?limit=50" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: skills-2025-10-02"
    +
    +# Recuperar versão específica
    +curl "https://api.anthropic.com/v1/skills/$SKILL_ID/versions/$VERSION" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: skills-2025-10-02"
    +
    +# Deletar versão específica
    +curl -X DELETE "https://api.anthropic.com/v1/skills/$SKILL_ID/versions/$VERSION" \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: skills-2025-10-02"
    +
    +
    + +
    Resposta JSON — POST /v1/skills/{skill_id}/versions +
    {
    +  "id": "skillver_01JAbcdefghijklmnopqrstuvw",
    +  "created_at": "2024-10-30T23:58:27.427722Z",
    +  "description": "A custom skill for doing something useful",
    +  "directory": "my-skill",
    +  "name": "my-skill",
    +  "skill_id": "skill_01JAbcdefghijklmnopqrstuvw",
    +  "type": "skill_version",
    +  "version": "1759178010641129"
    +}
    +
    +
    Resposta JSON — DELETE /v1/skills/{skill_id}/versions/{version} +
    {
    +  "id": "1759178010641129",
    +  "type": "skill_version_deleted"
    +}
    +
    + +
    Detalhe da doc oficial: nos exemplos de resposta das páginas de referência o campo type aparece renderizado como "type" (placeholder da doc). O valor real é o documentado na especificação do campo — "skill", "skill_deleted", "skill_version" e "skill_version_deleted", respectivamente. Trate como enum fechado por operação.
    + +
    Fluxo típico de gestão programática: (1) POST /v1/skills com o upload inicial cria o recurso Skill e sua primeira versão (o latest_version retornado é o epoch dessa versão); (2) a cada atualização dos arquivos, POST /v1/skills/{skill_id}/versions publica um novo epoch, e o latest_version da Skill avança; (3) na Messages API você referencia a Skill por skill_id + version (epoch específico ou latest) no bloco container.skills — ver seção 7.2 (Parte C). Fixe um epoch em produção para builds reproduzíveis; use latest só em dev.
    +
    + + + + +
    +

    8. Erros & rate limits

    + + +

    8.1. Códigos HTTP e tipos de erro

    +
    + + + + + + + + + + + + + +
    Statuserror.typeSignificado
    400invalid_request_errorFormato/conteúdo inválido (também outros 4XX não listados)
    401authentication_errorProblema com a chave da API (ou credenciais AWS no Claude Platform on AWS)
    402billing_errorProblema de billing/pagamento
    403permission_errorChave sem permissão para o recurso
    404not_found_errorRecurso não encontrado
    413request_too_largeExcede o tamanho máximo de bytes
    429rate_limit_errorAtingiu um rate limit
    500api_errorErro interno inesperado
    504timeout_errorTimeout durante o processamento (use streaming)
    529overloaded_errorAPI temporariamente sobrecarregada
    +

    Limites de tamanho de requisição: Messages 32 MB · Token Counting 32 MB · Batch 256 MB · Files 500 MB. Exceder retorna 413 (na API direta, devolvido pelo Cloudflare antes de chegar aos servidores).

    + +

    8.2. Formato do erro & request ID

    +

    Erros são sempre JSON com um objeto error de topo (type + message) e um request_id. Toda resposta inclui o header request-id (ex. req_018Ee...) — inclua-o em tickets de suporte. Nos SDKs, leia message._request_id.

    +
    {
    +  "type": "error",
    +  "error": {
    +    "type": "not_found_error",
    +    "message": "The requested resource could not be found."
    +  },
    +  "request_id": "req_011CSHoEeqs5C35K2UUqR7Fy"
    +}
    +
    Nota (Claude Platform on AWS): respostas trazem dois IDs — o AWS (x-amzn-requestid, primário, indexado no CloudTrail) e o Anthropic (request-id, secundário). Use o AWS para CloudTrail e o Anthropic para o suporte da Anthropic.
    + +

    8.3. Rate limit headers & retry/backoff

    +

    A API direta retorna headers de rate limit que permitem reagir antes do 429:

    +
    + + + + + + + +
    HeaderSignificado
    anthropic-ratelimit-requests-limit / -remaining / -resetLimite, restante e reset de requisições por minuto
    anthropic-ratelimit-input-tokens-limit / -remaining / -resetTokens de entrada por minuto
    anthropic-ratelimit-output-tokens-limit / -remaining / -resetTokens de saída por minuto
    retry-afterSegundos a esperar antes de tentar novamente (em 429)
    +
    Atenção: erros 529 podem ocorrer sob alta carga global. Um aumento abrupto de uso pode gerar 429 por limites de aceleração — aumente o tráfego gradualmente. Implemente retry com backoff exponencial (os SDKs já fazem 2 tentativas por padrão em conexão, 408, 409, 429 e ≥500). Em streaming SSE, um erro pode ocorrer após o 200, fora do mecanismo padrão.
    +
    Nota: Microsoft Foundry não inclui os headers de rate limit da Anthropic — gerencie via ferramentas do Azure. Veja a Rate Limits API para ler programaticamente os limites configurados.
    + +
    + + + + +
    +

    9. Plataformas: Bedrock, Vertex AI, Foundry & Claude Platform on AWS

    +

    Os SDKs oficiais suportam quatro plataformas além da API de primeira parte. Todas usam o mesmo formato da Messages API; o que muda é a base URL, a autenticação e os IDs de modelo.

    +
    + + + + + + + +
    PlataformaQuem opera o stackBase URLAuthClient SDK (Python)
    Claude in Amazon BedrockAWSbedrock-mantle.{region}.api.awsIAM/SigV4 (ou bearer token)AnthropicBedrockMantle
    Claude on Vertex AIGoogle Cloud (parceiro){location}-aiplatform.googleapis.comCredenciais GCP (ADC)AnthropicVertex
    Claude in Microsoft FoundryAnthropic (billing via Azure){resource}.services.ai.azure.com/anthropicAPI key ou Entra IDAnthropicFoundry
    Claude Platform on AWSAnthropic (billing via AWS Marketplace)aws-external-anthropic.{region}.api.awsIAM/SigV4 ou API keyAnthropicAWS Beta
    + + +

    9.1. Amazon Bedrock

    +

    Claude in Amazon Bedrock roda em infraestrutura gerenciada pela AWS com zero operator access da Anthropic, servindo a Messages API em /anthropic/v1/messages. IDs de modelo carregam o prefixo anthropic. — ex. anthropic.claude-opus-4-8 e anthropic.claude-haiku-4-5 (ambos abertos a todos os clientes Bedrock).

    +

    Autenticação: três caminhos — service role do Bedrock (recomendado), IAM assumed roles (sessão máx. 12h) e bearer tokens (12h, menos preferido). Instalação: pip install -U "anthropic[bedrock]" (Python) ou npm install @anthropic-ai/bedrock-sdk.

    +
    +
    + + +
    +
    +
    from anthropic import AnthropicBedrockMantle
    +
    +client = AnthropicBedrockMantle(aws_region="us-east-1")
    +
    +message = client.messages.create(
    +    model="anthropic.claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +print(message.content[0].text)
    +
    +
    +
    curl https://bedrock-mantle.us-east-1.api.aws/anthropic/v1/messages \
    +  --aws-sigv4 "aws:amz:us-east-1:bedrock-mantle" \
    +  --user "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" \
    +  -H "x-amz-security-token: $AWS_SESSION_TOKEN" \
    +  -H "content-type: application/json" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -d '{
    +    "model": "anthropic.claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{"role": "user", "content": "Olá, Claude"}]
    +  }'
    +
    +
    +
    Nota: Bedrock oferece endpoints Global (roteamento dinâmico, sem prêmio) e Regional (data residency, prêmio de 10%). Cota padrão: 2 milhões de input TPM (até 4 milhões sem aprovação adicional da Anthropic). Recursos não suportados no Bedrock incluem: Files API, server-side tools (code execution, web search/fetch, advisor), Agent Skills, MCP connector, Batches, Models, Admin/Compliance e Managed Agents. A integração legada (InvokeModel/Converse) usa o client AnthropicBedrock e tem formato de request/response próprio; este guia foca a integração atual (Messages API) — para o mapeamento de shapes da legada, consulte a página oficial. + claude-in-amazon-bedrock · legada: claude-on-amazon-bedrock-legacy
    + +

    9.2. Google Vertex AI

    +

    A API Vertex é quase idêntica à Messages API, com duas diferenças no formato: (1) model não vai no corpo — é parte da URL do endpoint GCP; (2) anthropic_version vai no corpo (não no header) e deve valer vertex-2023-10-16. IDs de modelo: claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5@20251001 (datado). Instalação: pip install -U google-cloud-aiplatform "anthropic[vertex]".

    +
    +
    + + +
    +
    +
    from anthropic import AnthropicVertex
    +
    +# Antes: gcloud auth application-default login
    +client = AnthropicVertex(project_id="MY_PROJECT_ID", region="global")
    +
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=100,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +print(message)
    +
    +
    +
    MODEL_ID=claude-opus-4-8
    +LOCATION=global
    +PROJECT_ID=MY_PROJECT_ID
    +
    +curl -X POST \
    +  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    +  -H "Content-Type: application/json" \
    +  "https://$LOCATION-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/anthropic/models/${MODEL_ID}:streamRawPredict" \
    +  -d '{
    +    "anthropic_version": "vertex-2023-10-16",
    +    "messages": [{"role": "user", "content": "Olá, Claude"}],
    +    "max_tokens": 100
    +  }'
    +
    +
    +
    Nota: Vertex oferece endpoints global, multi-region e regional (estes últimos com prêmio de 10%). Payload limitado a 30 MB. Claude Opus 4.8 e Sonnet 4.6 têm janela de 1M tokens no Vertex. Recursos não suportados são semelhantes aos do Bedrock (sem Files, code execution/web fetch/advisor, Agent Skills, MCP connector, Batches, Models, Admin/Compliance, Managed Agents).
    + +

    9.3. Microsoft Foundry

    +

    Em Foundry, os modelos rodam na infraestrutura da Anthropic; é uma integração comercial para billing/acesso via Azure. Hierarquia: resource (segurança/billing) contém deployments (instâncias do modelo). O nome do deployment é o valor passado em model. Base URL: https://{resource}.services.ai.azure.com/anthropic/v1/*. Auth: API key (header api-key ou x-api-key) ou Entra ID (Authorization: Bearer). Suportado pelos SDKs C#, Java, PHP, Python e TypeScript (Go e Ruby não têm suporte nativo).

    +
    +
    + + +
    +
    +
    import os
    +from anthropic import AnthropicFoundry
    +
    +client = AnthropicFoundry(
    +    api_key=os.environ.get("ANTHROPIC_FOUNDRY_API_KEY"),
    +    resource="example-resource",  # nome do resource
    +)
    +
    +message = client.messages.create(
    +    model="claude-opus-4-8",   # nome do deployment
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá!"}],
    +)
    +print(message.content)
    +
    +
    +
    curl https://{resource}.services.ai.azure.com/anthropic/v1/messages \
    +  -H "content-type: application/json" \
    +  -H "api-key: YOUR_AZURE_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -d '{
    +    "model": "claude-opus-4-8",
    +    "max_tokens": 1024,
    +    "messages": [{"role": "user", "content": "Olá!"}]
    +  }'
    +
    +
    +
    Nota: Claude Opus 4.8 e Sonnet 4.6 têm janela de 1M tokens no Foundry. Recursos não suportados: Admin API, Compliance API, Models API e Message Batches API. Para suporte, forneça request-id e apim-request-id. Não há headers de rate limit da Anthropic — use o monitoramento do Azure.
    + +

    9.4. Claude Platform on AWS

    +

    Dá a experiência completa da plataforma Anthropic (Messages API, Agent Skills, code execution, features beta) operada pela Anthropic, acessada via conta AWS com billing pelo AWS Marketplace. Diferente do Bedrock (onde a AWS opera o stack), aqui a AWS provê apenas a camada de auth (SigV4/API key), controle IAM e billing.

    +

    Setup obrigatório (uma vez por conta AWS): habilitar outbound web identity federation com aws iam enable-outbound-web-identity-federation — sem isso toda requisição retorna "Outbound web identity federation is disabled for your account". É preciso um workspace ID (formato wrkspc_..., vinculado a uma região AWS) e definir ANTHROPIC_AWS_WORKSPACE_ID + AWS_REGION. Instalação: pip install -U "anthropic[aws]".

    +
    +
    + +
    +
    +
    from anthropic import AnthropicAWS
    +
    +# Lê ANTHROPIC_AWS_WORKSPACE_ID e resolve credenciais via cadeia padrão AWS (SigV4)
    +client = AnthropicAWS(aws_region="us-west-2")
    +
    +message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +print(message.content[0].text)
    +
    +
    +
    Atenção: precedência de credenciais do client AnthropicAWS: (1) api_key → x-api-key; (2) aws_access_key+aws_secret_access_key → SigV4; (3) aws_profile → SigV4; (4) ANTHROPIC_AWS_API_KEY → x-api-key; (5) cadeia padrão de credenciais AWS → SigV4. A região é obrigatória (sem fallback). As chaves de API são geradas no AWS Console (não no Claude Console). Tokens de curto prazo (12h) podem ser gerados pelas bibliotecas token-generator da AWS.
    +
    Nota: escolha Bedrock (não Claude Platform on AWS) se precisar de FedRAMP High, IL4/IL5, HIPAA-ready ou que a AWS seja o único processador de dados. Claude Platform on AWS suporta AWS PrivateLink e o parâmetro inference_geo.
    +
    + + + + +
    +

    10. Claude Managed Agents

    +

    Os Claude Managed Agents são um harness de agente pré-construído e configurável que roda em infraestrutura gerenciada — ideal para tarefas longas e trabalho assíncrono. Em vez de construir seu próprio loop de agente, execução de ferramentas e runtime, você obtém um ambiente onde o Claude lê arquivos, roda comandos, navega na web e executa código com segurança, com prompt caching e compactação embutidos.

    + +
    Atenção (beta): Managed Agents está em Beta. Todas as requisições exigem o header anthropic-beta: managed-agents-2026-04-01 (o SDK define automaticamente). Por ser stateful (sessões longas com histórico e estado server-side), não é elegível a ZDR nem a BAA HIPAA. Dreams exige adicionalmente dreaming-2026-04-21. Rate limits: 300 req/min em endpoints de criação, 600 req/min em leitura.
    +
    Novidades de 09/06/2026: (1) scheduled deployments — sessões executadas em agenda cron sem scheduler próprio (doc: managed-agents/scheduled-deployments); (2) vaults agora suportam credenciais por variável de ambiente, injetadas com segurança no sandbox (para CLIs/SDKs/serviços que autenticam via env var); (3) os eventos de webhook session.thread_* ganharam o campo session_thread_id, identificando a thread multi-agente que disparou o evento.
    + +

    10.1. Conceitos centrais

    +
    + + + + + + + +
    ConceitoDescrição
    AgentModelo + system prompt + tools + servidores MCP + skills. Criado uma vez e referenciado por ID; é versionado
    EnvironmentOnde as sessões rodam: container cloud gerenciado pela Anthropic ou self_hosted (sua infra)
    SessionInstância de um agente em um environment, executando uma tarefa e gerando outputs; mantém histórico
    EventsMensagens trocadas entre sua aplicação e o agente (turnos de usuário, resultados de tools, status)
    + +

    10.2. Quickstart: agente → environment → sessão → eventos

    +

    O fluxo é: criar um agente (com o toolset agent_toolset_20260401 que habilita bash, operações de arquivo, web search etc.), criar um environment, iniciar uma sessão e então enviar eventos user.message, recebendo respostas via SSE.

    +
    +
    + + +
    +
    +
    from anthropic import Anthropic
    +
    +client = Anthropic()  # define o beta header automaticamente
    +
    +# 1) Agente
    +agent = client.beta.agents.create(
    +    name="Coding Assistant",
    +    model="claude-opus-4-8",
    +    system="Você é um assistente de código. Escreva código limpo e documentado.",
    +    tools=[{"type": "agent_toolset_20260401"}],
    +)
    +
    +# 2) Environment (container cloud)
    +env = client.beta.environments.create(
    +    name="quickstart-env",
    +    config={"type": "cloud", "networking": {"type": "unrestricted"}},
    +)
    +
    +# 3) Sessão
    +session = client.beta.sessions.create(
    +    agent=agent.id,
    +    environment_id=env.id,
    +    title="Sessão quickstart",
    +)
    +print(agent.id, env.id, session.id)
    +
    +
    +
    # 1) Criar agente
    +curl https://api.anthropic.com/v1/agents \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: managed-agents-2026-04-01" \
    +  -H "content-type: application/json" \
    +  -d '{
    +    "name": "Coding Assistant",
    +    "model": "claude-opus-4-8",
    +    "system": "Você é um assistente de código.",
    +    "tools": [{"type": "agent_toolset_20260401"}]
    +  }'
    +
    +# 3) Iniciar sessão (após criar environment)
    +curl https://api.anthropic.com/v1/sessions \
    +  -H "x-api-key: $ANTHROPIC_API_KEY" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "anthropic-beta: managed-agents-2026-04-01" \
    +  -H "content-type: application/json" \
    +  -d '{"agent": "'"$AGENT_ID"'", "environment_id": "'"$ENVIRONMENT_ID"'"}'
    +
    +
    + +

    10.3. Environments & containers

    +

    Um environment é criado uma vez e referenciado por ID a cada sessão; várias sessões compartilham o environment, mas cada uma recebe um container isolado. Containers cloud vêm com Ubuntu 22.04, x86_64, até 8 GB de RAM e 10 GB de disco, e rede desabilitada por padrão (habilite via networking na config). Vêm pré-instalados Python 3.12+, Node.js 20+, Go, Rust, Java 21+, Ruby, PHP, C/C++, clientes SQLite/PostgreSQL/Redis e utilitários (git, curl, jq, ripgrep etc.).

    + + +

    10.4. Self-hosted sandboxes & modelo de segurança

    +

    Os self-hosted sandboxes mantêm a orquestração na Anthropic mas movem a execução de tools para infra que você controla — o código, filesystem e egress de rede do agente nunca saem do seu ambiente. Um environment worker (processo seu) consome itens da fila de trabalho do environment self_hosted, baixa as skills do agente, roda tool calls localmente e devolve resultados. Filesystem: /workspace (trabalho/skills) e /mnt/session/outputs (outputs finais).

    + +
    Cuidado (modelo de responsabilidade compartilhada): ao self-hospedar, você é responsável pela qualidade/hardening da imagem do container, controles de egress de rede, armazenamento e rotação do ANTHROPIC_ENVIRONMENT_KEY (a chave que autoriza o polling da fila — guarde em secret manager, nunca em env files ou imagens), isolamento de workloads não confiáveis e retenção/redação dos logs e conteúdo de sessão. A Anthropic não inspeciona sua imagem, não consegue revogar uma chave vazada antes de você detectá-la e não isola tools dentro do seu container.
    + +

    10.5. Eventos & streaming

    +

    A comunicação é baseada em eventos ({domain}.{action}). Você envia eventos de usuário; recebe eventos de agente, sessão e span.

    +
    + + + + + + + +
    DireçãoEventos (exemplos)
    User (envia)user.message · user.interrupt · user.custom_tool_result · user.tool_confirmation · user.define_outcome · user.tool_result (self-hosted)
    Agent (recebe)agent.message · agent.thinking · agent.tool_use · agent.tool_result · agent.mcp_tool_use · agent.custom_tool_use · agent.thread_context_compacted
    Session (recebe)session.status_running · session.status_idle (com stop_reason) · session.status_rescheduled · session.status_terminated · session.updated · session.error
    Span (recebe)span.model_request_start · span.model_request_end (com model_usage) · span.outcome_evaluation_*
    + + +

    10.6. Tools, skills, permission policies, memory, vaults, outcomes

    +
    + + + + + + + + + + + + + +
    RecursoO que faz
    Tools (agent_toolset_20260401)Toolset pré-construído: bash, operações de arquivo, web search/fetch; mais mcp_toolset e custom tools
    SkillsPacotes de capacidade carregados no container (baixados para /workspace/skills/<nome>/)
    Permission policiesalways_allow (executa sem confirmação) ou always_ask (pausa e aguarda aprovação via user.tool_confirmation). Custom tools não são governadas por políticas
    Memory storesColeção de documentos texto escopada por workspace, montada como diretório na sessão; cada alteração cria uma memory version imutável (audit trail). Requer o agent toolset
    Vaults & credentialsRegistram credenciais de terceiros uma vez e referenciam por ID na criação da sessão (per-user). Workspace-scoped
    Define outcomesDefine o "pronto" e uma rubrica; o harness provisiona um grader em janela de contexto separada que avalia e devolve gaps para o agente iterar
    Dreams Research PreviewJob assíncrono que lê uma memory store + transcrições e produz uma nova store reorganizada (dedup, atualização, novos insights); a store de entrada nunca é modificada
    GitHubMonta repositório no container e conecta ao GitHub MCP para clonar, ler e abrir PRs (repos são cacheados entre sessões)
    Multi-agentUm coordenador delega a outros agentes em session threads isoladas; compartilham container, filesystem e vault, mas têm contexto/tools próprios. Padrões: paralelização, especialização, escalonamento
    WebhooksNotificam mudanças de estado sem polling; entregam type+id (busque o objeto via GET). Assinados com header X-Webhook-Signature e segredo whsec_...; valide com o helper unwrap() do SDK
    + +
    Nota de fronteira: a Parte C também cobre Managed Agents do ângulo de ferramentas/skills/MCP. Aqui o foco é a superfície REST/governança (endpoints /v1/agents, /v1/sessions, /v1/environments, eventos, segurança self-hosted, retenção). Coordene com a Parte C para evitar duplicação de conteúdo conceitual de tools.
    +
    + + + + +
    +

    11. Governança & Admin

    +

    O plano de governança gerencia membros, workspaces, chaves, limites, custos, retenção e residência de dados. A maior parte usa a Admin API, que exige uma chave especial sk-ant-admin... (distinta das chaves padrão) provisionável apenas por membros com role admin.

    + +

    11.1. Admin API

    +

    Permite gerenciar programaticamente os recursos da organização: membros e roles, convites, workspaces e seus membros, e chaves de API. Indisponível para contas individuais (configure uma organização). Endpoints sob /v1/organizations/*, autenticados com x-api-key: $ANTHROPIC_ADMIN_KEY.

    + +

    Roles de organização:

    +
    + + + + + + + + +
    RolePermissões
    userUsar o Workbench
    claude_code_userWorkbench + Claude Code
    developerWorkbench + gerenciar chaves de API
    billingWorkbench + gerenciar billing
    adminTudo acima + gerenciar usuários
    +
    +
    + +
    +
    +
    # Listar membros da organização
    +curl "https://api.anthropic.com/v1/organizations/users?limit=10" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
    +
    +# Info da organização
    +curl "https://api.anthropic.com/v1/organizations/me" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
    +
    +
    +
    Atenção: novas chaves de API só podem ser criadas no Claude Console (não via Admin API). Admins de organização não podem ser removidos via API. Convites expiram em 21 dias. No Claude Platform on AWS, apenas os endpoints de workspace (/v1/organizations/workspaces) estão disponíveis.
    + +

    11.2. Workspaces

    +

    Workspaces organizam o uso da API dentro de uma organização — separam projetos/ambientes/times mantendo billing centralizado. IDs usam o prefixo wrkspc_. Máximo de 100 workspaces por organização (arquivados não contam). O Default Workspace não pode ser renomeado/arquivado/deletado e não tem ID (aparece como null em relatórios).

    + +

    Chaves de API são escopadas a um único workspace. Recursos escopados por workspace incluem Files, Message Batches e Skills; o prompt cache é isolado por workspace na API direta, Claude Platform on AWS e Foundry (por organização no Bedrock/Vertex). Roles de workspace: Workspace User, Limited Developer, Developer, Admin e Billing (herdada). Limites de workspace podem ser menores (não maiores) que os da organização.

    + +

    11.3. Autenticação: API keys vs Workload Identity Federation

    +

    Há dois métodos de autenticação, com o mesmo acesso aos endpoints:

    +
    + + + + + +
    MétodoCredencialMelhor para
    API keySegredo longo sk-ant-api... no header x-api-keyDev local, protótipos, scripts, servidores single-tenant
    Workload Identity Federation (WIF)Token bearer de curta duração trocado do JWT do seu IdPProdução em nuvem (AWS, GCP, Azure), CI/CD, Kubernetes — elimina segredos estáticos
    + + +

    11.4. Workload Identity Federation (WIF)

    +

    WIF permite que cargas de trabalho autentiquem com tokens OIDC de curta duração emitidos por um IdP que você já opera (AWS IAM, Google Cloud, ou qualquer emissor OIDC como GitHub Actions, Kubernetes, SPIFFE, Microsoft Entra ID, Okta), em vez de chaves estáticas sk-ant-.... O workload troca seu JWT em POST /v1/oauth/token (grant jwt-bearer da RFC 7523) por um token de acesso sk-ant-oat01-... de curta duração, que o SDK renova automaticamente.

    + +

    Três recursos no Console expressam "tokens assinados pelo emissor X, com claims Y, podem agir como service account Z":

    +
    + + + + + + +
    RecursoPrefixoPapel
    Service accountsvac_...Identidade não-humana que o token federado representa; ativa-se ao ser adicionada a um workspace
    Federation issuerfdis_...Registra o IdP (URL do iss + fonte JWKS: discovery/explicit_url/inline)
    Federation rulefdrl_...Ponte: match (subject_prefix/audience/claims/CEL) → target (service account) → authorization (scope, default workspace:developer; token_lifetime_seconds 60–86400, default 3600)
    +

    O corpo da troca de token (POST /v1/oauth/token) exige: grant_type (urn:ietf:params:oauth:grant-type:jwt-bearer), assertion (o JWT), federation_rule_id, organization_id, service_account_id e workspace_id (condicional). A resposta segue OAuth 2.0 (access_token, token_type, expires_in, scope).

    +
    +
    + + +
    +
    +
    from anthropic import Anthropic, WorkloadIdentityCredentials, IdentityTokenFile
    +
    +client = Anthropic(
    +    credentials=WorkloadIdentityCredentials(
    +        identity_token_provider=IdentityTokenFile("/var/run/secrets/anthropic.com/token"),
    +        federation_rule_id="fdrl_...",
    +        organization_id="00000000-0000-0000-0000-000000000000",
    +        service_account_id="svac_...",
    +        workspace_id="wrkspc_...",
    +    ),
    +)
    +
    +message = client.messages.create(
    +    model="claude-sonnet-4-6",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +print(message.content[0].text)
    +
    +
    +
    # 1) Trocar JWT do IdP por token de acesso Anthropic
    +RESPONSE=$(curl -sS https://api.anthropic.com/v1/oauth/token \
    +  -H "content-type: application/json" \
    +  --data '{
    +    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    +    "assertion": "'"$JWT"'",
    +    "federation_rule_id": "fdrl_...",
    +    "organization_id": "00000000-0000-0000-0000-000000000000",
    +    "service_account_id": "svac_...",
    +    "workspace_id": "wrkspc_..."
    +  }')
    +ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r .access_token)
    +
    +# 2) Chamar a API com Authorization: Bearer
    +curl https://api.anthropic.com/v1/messages \
    +  -H "authorization: Bearer $ACCESS_TOKEN" \
    +  -H "anthropic-version: 2023-06-01" \
    +  -H "content-type: application/json" \
    +  --data '{"model":"claude-sonnet-4-6","max_tokens":1024,"messages":[{"role":"user","content":"Olá"}]}'
    +
    +
    +

    Provedores de identidade suportados (guias dedicados): AWS · Google Cloud · Microsoft Azure · GitHub Actions · Kubernetes · SPIFFE · Okta.

    +
    Atenção (precedência): ANTHROPIC_API_KEY fica acima dos tiers de federação na cadeia de precedência — uma chave esquecida no ambiente silenciosamente sobrescreve o WIF. Ao migrar, confirme que ANTHROPIC_API_KEY está removida em todo lugar (env do container, secrets de CI, perfis de shell). Use ant auth status para ver qual fonte venceu. O token mintado vive o menor entre o token_lifetime_seconds da regra e o dobro da vida restante do JWT (piso de 60s); o SDK renova em expiração-120s (advisory) e expiração-30s (mandatória).
    + +

    11.5. Rate Limits API

    +

    Lê programaticamente os limites configurados para a organização e workspaces (mesma informação da página Limits do Console). Parte da Admin API (chave sk-ant-admin...). Endpoint org: GET /v1/organizations/rate_limits; workspace: GET /v1/organizations/workspaces/{id}/rate_limits (só retorna overrides; ausências são herdadas). É somente leitura — para alterar, use a aba Limits do Console.

    + +

    Cada entrada é um grupo de rate limit com group_type (model_group, batch, token_count, files, skills, web_search) e uma lista limits de pares {type, value} — requests_per_minute, input_tokens_per_minute, output_tokens_per_minute, enqueued_batch_requests etc. Filtre por ?model= (apenas no endpoint org) ou ?group_type=.

    + +

    11.6. Usage & Cost API

    +

    Acesso programático granular a uso e custo históricos. Parte da Admin API. Dois endpoints: GET /v1/organizations/usage_report/messages (uso — tokens por modelo/workspace/service tier; buckets 1m/1h/1d) e GET /v1/organizations/cost_report (custo em USD, granularidade diária). Dados aparecem em ~5 minutos; polling recomendado: 1×/min.

    + +
    +
    + +
    +
    +
    # Uso diário por modelo (últimos 7 dias)
    +curl "https://api.anthropic.com/v1/organizations/usage_report/messages?\
    +starting_at=2026-05-01T00:00:00Z&\
    +ending_at=2026-05-08T00:00:00Z&\
    +group_by[]=model&bucket_width=1d" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
    +
    +# Custo por workspace (mensal)
    +curl "https://api.anthropic.com/v1/organizations/cost_report?\
    +starting_at=2026-05-01T00:00:00Z&ending_at=2026-05-31T00:00:00Z&\
    +group_by[]=workspace_id&group_by[]=description" \
    +  --header "anthropic-version: 2023-06-01" \
    +  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"
    +
    +
    +
    Nota: filtros/grupos incluem api_key_ids[], workspace_ids[], models[], service_tiers[], context_window[], inference_geo (valores global/us/not_available) e speed (beta, exige fast-mode-2026-02-01). Custos de Priority Tier e de code execution não aparecem no endpoint de custo (use o de uso). Para custos por usuário do Claude Code, use a Claude Code Analytics API. Integrações prontas: CloudZero, Datadog, Grafana Cloud, Honeycomb, Vantage.
    + +

    11.7. Retenção de dados (ZDR & HIPAA)

    +

    A Anthropic oferece dois arranjos de tratamento de dados para a Claude API: Zero Data Retention (ZDR) — dados do cliente não são armazenados em repouso após a resposta, exceto onde exigido por lei ou para combater abuso — e HIPAA readiness — para PHI, com BAA assinado e organização HIPAA-enabled.

    + +

    ZDR cobre as APIs de Mensagens e Token Counting (e Claude Code com chaves Commercial/Enterprise). Não cobre: Console/Workbench, Managed Agents (stateful), produtos de consumo, Teams/Enterprise (exceto Claude Code via Enterprise com ZDR) e integrações de terceiros. HIPAA readiness é imposta no nível da organização: requisições com features não-elegíveis retornam 400.

    +

    Elegibilidade de features (recorte):

    +
    + + + + + + + + + + + +
    FeatureZDRHIPAA
    Messages API / Token countingSimSim
    Prompt caching / Extended & adaptive thinking / Citations / 1M contextSimSim
    Structured outputsSim (qualificado)Sim (sem PHI no schema)
    Context management (compaction/editing)SimNão
    Web fetch / Advisor / Computer use / Tool searchSimNão
    Batch processingNãoNão
    Code execution / Programmatic tool callingNãoNão
    Files API / Agent skills / MCP connector / Managed Agents / MCP tunnelsNãoNão
    +
    Atenção: CORS não é suportado para organizações com ZDR — use um backend proxy e nunca exponha chaves no JavaScript do navegador. Mesmo com ZDR/HIPAA, dados podem ser retidos por até 2 anos se sinalizados por violação de política. Bedrock/Vertex têm o provedor de nuvem como processador (consulte suas próprias políticas); Claude Platform on AWS segue a política da API direta (ZDR sob demanda; HIPAA indisponível).
    + +

    11.8. Residência de dados

    +

    Dois controles independentes: Inference geo (onde a inferência roda, por requisição, via inference_geo) e Workspace geo (onde dados são armazenados em repouso, fixado na criação do workspace — atualmente só "us").

    + +

    Valores de inference_geo: "global" (default) e "us" (só infra dos EUA). A resposta reporta onde rodou em usage.inference_geo. Suportado em Claude Opus 4.8, Sonnet 4.6 e posteriores (modelos anteriores retornam 400). Configurável por workspace via allowed_inference_geos e default_inference_geo (campo data_residency na Admin API).

    +
    Nota (pricing): inferência US-only (inference_geo: "us") custa 1,1× a tarifa padrão em todas as categorias de token (e drena 1,1 token por token no burndown de Priority Tier). Roteamento global usa preço padrão. Disponível na API direta e Claude Platform on AWS; suportado também na Batch API (por requisição). Em Bedrock/Vertex/Foundry, a região é determinada pela URL/inference profile (parâmetro não se aplica).
    + +

    11.9. Compliance API

    +

    Acesso programático à atividade, chats, arquivos, projetos e usuários da organização para auditoria e governança. Habilitada sob demanda: organizações Claude Enterprise têm acesso completo; organizações Claude Console têm acesso apenas ao Activity Feed. Endpoints sob /v1/compliance/*, autenticados por x-api-key.

    + +

    Dois tipos de chave: uma Compliance Access Key (sk-ant-api01-..., criada no claude.ai) alcança todos os endpoints; uma Admin API key (sk-ant-admin01-...) alcança apenas o Activity Feed. Scopes: read:compliance_activities (feed), read:compliance_user_data (chats/arquivos/projetos/usuários), read:compliance_org_data (organizações/roles/grupos) e delete:compliance_user_data (deletes). Limite: 600 req/min por organização-pai. O Activity Feed retém 6 anos e novos eventos são consultáveis em ~1 min.

    +
    +
    + +
    +
    +
    # Evento de atividade mais recente
    +curl "https://api.anthropic.com/v1/compliance/activities?limit=1" \
    +  --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY"
    +
    +
    +
    Nota: o Activity Feed registra quem fez o quê e quando (autenticação, criação de chat/arquivo, ações administrativas) — não captura texto de prompt nem respostas. Para corpos de mensagem e conteúdo de arquivo, use os endpoints de conteúdo com uma Compliance Access Key (read:compliance_user_data), que servem apenas dados do claude.ai. Deletes são imediatos e irreversíveis. Padrões de consumo: window polling (com created_at.gte/.lt) ou cursor-driven (persistindo first_id/before_id); correlacione com SIEM por actor.user_id/email_address/ip_address/created_at.
    +
    + + + + + + + + +
    +

    Parte E — SDK Python (anthropic): referência exaustiva

    +

    Cobertura completa e fiel do SDK oficial anthropic para Python, extraída de + platform.claude.com/docs/en/api/sdks/python, + do api.md do repositório oficial e da referência da API. Aprofunda o que a + Parte D (D1 · SDKs) resume: instalação e extras, clientes síncrono/assíncrono e todas as + opções de construtor, mensagens, streaming, ferramentas, batches, contagem de tokens, arquivos, modelos, + paginação automática, hierarquia de erros, retries/timeouts, respostas cruas, sistema de tipos, logging, + requisições não documentadas, cliente HTTP customizado, namespace beta e os cinco clientes de plataforma. + Todos os exemplos usam os modelos atuais (claude-opus-4-8, claude-sonnet-4-6, + claude-haiku-4-5).

    +
    + +
    +

    E1. Instalação, requisitos e extras

    +

    O SDK anthropic dá acesso conveniente à API REST da Anthropic a partir de Python, com suporte a + operações síncronas e assíncronas, streaming e integrações com Amazon Bedrock, Vertex AI, Microsoft Foundry e + Claude Platform on AWS. Requer Python 3.9 ou superior.

    +
    # Instalação base
    +pip install anthropic
    +
    +# Extras por integração de plataforma
    +pip install "anthropic[bedrock]"   # Amazon Bedrock
    +pip install "anthropic[vertex]"    # Google Vertex AI
    +pip install "anthropic[aws]"       # Claude Platform on AWS
    +# Microsoft Foundry já vem incluso no pacote base
    +
    +# Backend assíncrono alternativo (melhor concorrência)
    +pip install "anthropic[aiohttp]"
    +
    + + + + + + + +
    ExtraHabilita
    anthropic[bedrock]Clientes AnthropicBedrockMantle / AnthropicBedrock
    anthropic[vertex]Cliente AnthropicVertex
    anthropic[aws]Cliente AnthropicAWS (beta)
    anthropic[aiohttp]Backend HTTP DefaultAioHttpClient (assíncrono)
    +

    E1.1 Versão instalada em tempo de execução

    +

    Se um recurso novo não aparece, confirme a versão efetivamente carregada no ambiente Python:

    +
    import anthropic
    +print(anthropic.__version__)
    +
    Dica: use python-dotenv + para carregar ANTHROPIC_API_KEY="..." de um arquivo .env e manter a chave fora do controle de versão.
    +

    O pacote segue SemVer, mas mudanças que afetam apenas tipos estáticos, internos públicos não + documentados, ou que não impactam a maioria dos usuários, podem sair como minor.

    + +
    + +
    +

    E2. Inicializando o cliente (síncrono e assíncrono)

    +

    O cliente síncrono é Anthropic; o assíncrono é AsyncAnthropic + (mesma interface, com await). Ambos leem a chave de ANTHROPIC_API_KEY por padrão.

    +
    +
    + + +
    +
    +
    import os
    +from anthropic import Anthropic
    +
    +client = Anthropic(
    +    api_key=os.environ.get("ANTHROPIC_API_KEY"),  # padrão; pode ser omitido
    +)
    +
    +message = client.messages.create(
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +    model="claude-opus-4-8",
    +)
    +print(message.content)
    +
    +
    +
    import os, asyncio
    +from anthropic import AsyncAnthropic
    +
    +client = AsyncAnthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))
    +
    +async def main() -> None:
    +    message = await client.messages.create(
    +        max_tokens=1024,
    +        messages=[{"role": "user", "content": "Olá, Claude"}],
    +        model="claude-opus-4-8",
    +    )
    +    print(message.content)
    +
    +asyncio.run(main())
    +
    +
    + +

    E2.1 Opções do construtor

    +
    + + + + + + + + + + + +
    OpçãoTipoPadrão / EnvDescrição
    api_keystrANTHROPIC_API_KEYChave da API (header x-api-key).
    auth_tokenstr—Token Bearer (ex.: Workload Identity Federation) como alternativa à API key.
    base_urlstrANTHROPIC_BASE_URLSobrescreve a URL base (ex.: gateway/proxy).
    timeoutfloat · httpx.Timeout600 s (10 min)Timeout global; aceita granularidade por fase.
    max_retriesint2Retentativas automáticas com backoff exponencial.
    default_headersdict—Headers padrão em todas as requisições.
    default_querydict—Query params padrão em todas as requisições.
    http_clientDefaultHttpxClient · DefaultAioHttpClienthttpxCliente HTTP customizado (proxies, transporte, backend).
    + +

    E2.2 Backend aiohttp (melhor concorrência assíncrona)

    +
    import os, asyncio
    +from anthropic import AsyncAnthropic, DefaultAioHttpClient
    +
    +async def main() -> None:
    +    async with AsyncAnthropic(
    +        api_key=os.environ.get("ANTHROPIC_API_KEY"),
    +        http_client=DefaultAioHttpClient(),
    +    ) as client:
    +        message = await client.messages.create(
    +            max_tokens=1024,
    +            messages=[{"role": "user", "content": "Olá, Claude"}],
    +            model="claude-opus-4-8",
    +        )
    +        print(message.content)
    +
    +asyncio.run(main())
    + +

    E2.3 Gerenciando recursos HTTP

    +

    Por padrão, as conexões são fechadas quando o cliente é coletado pelo GC. Para controle explícito, use + .close() ou um context manager:

    +
    from anthropic import Anthropic
    +
    +with Anthropic() as client:
    +    message = client.messages.create(
    +        max_tokens=1024,
    +        messages=[{"role": "user", "content": "Olá, Claude"}],
    +        model="claude-opus-4-8",
    +    )
    +# cliente HTTP fechado automaticamente ao sair do bloco
    + +
    + +
    +

    E3. Mensagens e usage

    +

    O método central é client.messages.create(...) → retorna um objeto Message (modelo Pydantic). + O texto fica em message.content (lista de blocos); o consumo de tokens, em message.usage.

    +
    message = client.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Explique a teoria das cordas em 1 parágrafo."}],
    +)
    +print(message.content[0].text)
    +print(message.usage)   # Usage(input_tokens=25, output_tokens=13, ...)
    +print(message.stop_reason)
    +print(message._request_id)  # id da requisição (ver E13)
    +
    Tipos: os parâmetros aninhados são TypedDict (ex.: MessageParam, + ContentBlockParam); as respostas são modelos Pydantic (Message, TextBlock, + ToolUseBlock, ThinkingBlock, Usage). Veja a Parte D (D3) para o schema REST completo de parâmetros.
    + +
    + +
    +

    E4. Streaming (duas abordagens)

    +

    O SDK oferece duas formas de streaming via SSE — escolha conforme a necessidade:

    +
    + + + + + +
    AbordagemO que retornaQuando usar
    messages.create(..., stream=True)Iterável de eventos brutos (não monta o objeto final). Menos memória.Quando você só quer os deltas e cuida da acumulação.
    messages.stream(...) (context manager)Helper com .text_stream, acumulação e .get_final_message().Quando quer o texto incremental E o objeto Message final pronto.
    + +

    E4.1 Iterável de eventos (stream=True)

    +
    +
    + + +
    +
    +
    stream = client.messages.create(
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +    model="claude-opus-4-8",
    +    stream=True,
    +)
    +for event in stream:
    +    print(event.type)   # message_start, content_block_delta, ...
    +
    +
    +
    stream = await client.messages.create(
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +    model="claude-opus-4-8",
    +    stream=True,
    +)
    +async for event in stream:
    +    print(event.type)
    +
    +
    + +

    E4.2 Helper com acumulação (messages.stream)

    +
    import asyncio
    +from anthropic import AsyncAnthropic
    +
    +client = AsyncAnthropic()
    +
    +async def main() -> None:
    +    async with client.messages.stream(
    +        max_tokens=1024,
    +        messages=[{"role": "user", "content": "Diga olá!"}],
    +        model="claude-opus-4-8",
    +    ) as stream:
    +        async for text in stream.text_stream:    # apenas os deltas de texto
    +            print(text, end="", flush=True)
    +        print()
    +        message = await stream.get_final_message()  # objeto Message acumulado
    +        print(message.to_json())
    +
    +asyncio.run(main())
    +

    O stream() retorna um MessageStreamManager; o objeto de stream expõe também eventos + específicos do SDK além de .text_stream. Veja a Parte A (A5) para os tipos de evento SSE.

    + +
    + +
    +

    E5. Ferramentas como funções Python (@beta_tool + tool_runner)

    +

    Além de definir ferramentas manualmente (ver Parte C), o SDK gera o schema da + ferramenta a partir da assinatura e do docstring de uma função Python via o decorador @beta_tool, e + executa o laço de tool use automaticamente com client.beta.messages.tool_runner(...).

    +
    import json
    +from anthropic import Anthropic, beta_tool
    +
    +client = Anthropic()
    +
    +@beta_tool
    +def get_weather(location: str) -> str:
    +    """Obtém o clima de um local.
    +
    +    Args:
    +        location: cidade e estado, ex.: San Francisco, CA
    +    Returns:
    +        String JSON com local, temperatura e condição.
    +    """
    +    return json.dumps({"location": location, "temperature": "68°F", "condition": "Sunny"})
    +
    +# tool_runner cuida automaticamente das chamadas de ferramenta
    +runner = client.beta.messages.tool_runner(
    +    max_tokens=1024,
    +    model="claude-opus-4-8",
    +    tools=[get_weather],
    +    messages=[{"role": "user", "content": "Como está o tempo em SF?"}],
    +)
    +for message in runner:
    +    print(message)
    +

    A cada iteração é feita uma requisição à API; se o Claude quiser chamar uma ferramenta dada, ela é executada + automaticamente e o resultado volta ao modelo na próxima iteração.

    + +
    + +
    +

    E6. Message Batches no SDK (client.messages.batches)

    +

    Conceito e limites na Parte A (A12) e o lado REST na Parte D (D5). + No SDK, cada requisição tem um custom_id e os mesmos params da Messages API.

    +
    batch = client.messages.batches.create(
    +    requests=[
    +        {"custom_id": "req-1", "params": {
    +            "model": "claude-opus-4-8", "max_tokens": 1024,
    +            "messages": [{"role": "user", "content": "Olá, mundo"}]}},
    +        {"custom_id": "req-2", "params": {
    +            "model": "claude-opus-4-8", "max_tokens": 1024,
    +            "messages": [{"role": "user", "content": "Oi de novo, amigo"}]}},
    +    ]
    +)
    +
    +# Quando batch.processing_status == "ended", itere os resultados (stream JSONL):
    +for entry in client.messages.batches.results(batch.id):
    +    if entry.result.type == "succeeded":
    +        print(entry.custom_id, entry.result.message.content)
    +
    + + + + + + + + + +
    MétodoCaminho RESTRetorno
    batches.create(requests=[...])POST /v1/messages/batchesMessageBatch
    batches.retrieve(id)GET /v1/messages/batches/{id}MessageBatch
    batches.list(**params)GET /v1/messages/batchesSyncPage[MessageBatch]
    batches.cancel(id)POST /v1/messages/batches/{id}/cancelMessageBatch
    batches.delete(id)DELETE /v1/messages/batches/{id}DeletedMessageBatch
    batches.results(id)GET /v1/messages/batches/{id}/resultsJSONLDecoder[MessageBatchIndividualResponse]
    + +
    + +
    +

    E7. Contagem de tokens (count_tokens e usage)

    +

    Veja o consumo real de qualquer resposta em message.usage, ou estime antes de enviar com + messages.count_tokens(...):

    +
    # Uso real, após a resposta
    +message = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
    +                                 messages=[{"role": "user", "content": "Olá"}])
    +print(message.usage)            # Usage(input_tokens=25, output_tokens=13)
    +
    +# Estimativa antes do envio
    +count = client.messages.count_tokens(
    +    model="claude-opus-4-8",
    +    messages=[{"role": "user", "content": "Hello, world"}],
    +)
    +print(count.input_tokens)       # 10  (retorna MessageTokensCount)
    + +
    + +
    +

    E8. Upload de arquivos (client.beta.files)

    +

    Parâmetros que correspondem a uploads aceitam várias formas: um objeto PathLike (ex.: + pathlib.Path), uma tupla (filename, content, content_type), ou um objeto file-like + BinaryIO. No cliente assíncrono, PathLike é lido de forma assíncrona automaticamente.

    +
    from pathlib import Path
    +from anthropic import Anthropic
    +
    +client = Anthropic()
    +
    +# Por caminho
    +f = client.beta.files.upload(file=Path("/caminho/relatorio.pdf"))
    +
    +# Por bytes (tupla)
    +client.beta.files.upload(file=("nota.txt", b"meus bytes", "text/plain"))
    +
    +# Referenciando o arquivo numa mensagem (header beta obrigatório)
    +resp = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": [
    +        {"type": "text", "text": "Resuma este documento."},
    +        {"type": "document", "source": {"type": "file", "file_id": f.id}},
    +    ]}],
    +    betas=["files-api-2025-04-14"],
    +)
    +
    + + + + + + + + +
    MétodoCaminho RESTRetorno
    beta.files.upload(file=...)POST /v1/filesFileMetadata
    beta.files.list(**params)GET /v1/filesSyncPage[FileMetadata]
    beta.files.retrieve_metadata(file_id)GET /v1/files/{id}FileMetadata
    beta.files.download(file_id)GET /v1/files/{id}/contentBinaryAPIResponse
    beta.files.delete(file_id)DELETE /v1/files/{id}DeletedFile
    +

    Profundidade de visão/PDF/documentos na Parte B (Files, PDF, Vision).

    + +
    + +
    +

    E9. Models API no SDK (client.models)

    +
    # Listar modelos disponíveis (paginado — ver E10)
    +for m in client.models.list(limit=20):
    +    print(m.id, m.display_name)
    +
    +# Recuperar um modelo específico e suas capacidades
    +info = client.models.retrieve("claude-opus-4-8")
    +print(info.max_input_tokens, info.max_output_tokens)
    +print(info.capabilities)   # ModelCapabilities: thinking, effort, context_management, ...
    +
    + + + + + +
    MétodoCaminhoRetorno
    models.list(**params)GET /v1/modelsSyncPage[ModelInfo]
    models.retrieve(model_id)GET /v1/models/{model_id}ModelInfo
    +

    Tipos: ModelInfo, ModelCapabilities, CapabilitySupport, + ThinkingCapability, EffortCapability, ContextManagementCapability. + Tabela canônica de modelos na Parte A (A3).

    + +
    + +
    +

    E10. Paginação automática

    +

    Métodos list são paginados. A forma idiomática é iterar diretamente — o SDK busca as páginas + seguintes conforme necessário (SyncPage / AsyncPage):

    +
    +
    + + +
    +
    +
    all_batches = []
    +for batch in client.messages.batches.list(limit=20):  # busca páginas automaticamente
    +    all_batches.append(batch)
    +
    +
    +
    all_batches = []
    +async for batch in client.messages.batches.list(limit=20):
    +    all_batches.append(batch)
    +
    +
    +

    Para controle granular de páginas:

    +
    first_page = client.messages.batches.list(limit=20)
    +if first_page.has_next_page():
    +    print(first_page.next_page_info())
    +    next_page = first_page.get_next_page()
    +    print(len(next_page.data))
    +
    +# Ou trabalhe diretamente com os dados da página
    +print(first_page.last_id)
    +for batch in first_page.data:
    +    print(batch.id)
    + +
    + +
    +

    E11. Tratamento de erros e hierarquia de exceções

    +

    Quando o SDK não consegue conectar, ou a API retorna 4xx/5xx, uma subclasse de APIError é levantada.

    +
    import anthropic
    +from anthropic import Anthropic
    +
    +client = Anthropic()
    +try:
    +    message = client.messages.create(
    +        max_tokens=1024,
    +        messages=[{"role": "user", "content": "Olá, Claude"}],
    +        model="claude-opus-4-8",
    +    )
    +except anthropic.APIConnectionError as e:
    +    print("Servidor inacessível")
    +    print(e.__cause__)              # exceção subjacente (httpx)
    +except anthropic.RateLimitError as e:
    +    print("429 recebido; aplicar backoff.")
    +except anthropic.APIStatusError as e:
    +    print("Outro status fora de 2xx:", e.status_code)
    +    print(e.response)
    +
    + + + + + + + + + + + + +
    Status HTTPExceção
    400BadRequestError
    401AuthenticationError
    403PermissionDeniedError
    404NotFoundError
    409ConflictError
    422UnprocessableEntityError
    429RateLimitError
    ≥ 500InternalServerError
    N/A (rede)APIConnectionError (e APITimeoutError)
    +

    Todas herdam de APIError; APIStatusError agrupa as que têm status_code e + response. Ver Parte D (D8) para o formato de erro REST e request-id.

    + +
    + +
    +

    E12. Retries, timeouts e requisições longas

    +

    E12.1 Retries

    +

    Por padrão, certos erros são retentados 2 vezes com backoff exponencial curto: + erros de conexão, 408, 409, 429 e ≥ 500.

    +
    from anthropic import Anthropic
    +
    +# Padrão para todas as requisições
    +client = Anthropic(max_retries=0)   # padrão é 2
    +
    +# Por requisição
    +client.with_options(max_retries=5).messages.create(
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +    model="claude-opus-4-8",
    +)
    +

    E12.2 Timeouts

    +

    Por padrão, as requisições expiram após 10 minutos. Aceita float ou + httpx.Timeout; em timeout, lança APITimeoutError (e a requisição é retentada).

    +
    import httpx
    +from anthropic import Anthropic
    +
    +client = Anthropic(timeout=20.0)  # 20 s (padrão = 10 min)
    +
    +# Granular por fase
    +client = Anthropic(timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0))
    +
    +# Por requisição
    +client.with_options(timeout=5.0).messages.create(
    +    max_tokens=1024, model="claude-opus-4-8",
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +
    Requisições longas: evite max_tokens alto sem streaming — + conexões ociosas podem cair. O SDK lança ValueError se uma requisição não-streaming for + estimada em mais de ~10 min; passar stream=True ou ajustar timeout desativa esse erro. + O SDK ativa TCP keep-alive para reduzir quedas por ociosidade (sobrescrevível via http_client).
    + +
    + +
    +

    E13. Resposta crua, streaming de corpo e Request ID

    +

    E13.1 Request ID

    +

    Todo objeto de resposta expõe ._request_id (do header request-id) — útil para logar + falhas e reportar à Anthropic. É a única propriedade _ pública.

    +
    message = client.messages.create(max_tokens=1024, model="claude-opus-4-8",
    +    messages=[{"role": "user", "content": "Olá, Claude"}])
    +print(message._request_id)  # ex.: req_018EeWyXxfu5pfWkrYcMdjWG
    +

    E13.2 with_raw_response (headers + corpo já lido)

    +
    response = client.messages.with_raw_response.create(
    +    max_tokens=1024, model="claude-opus-4-8",
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +)
    +print(response.headers.get("request-id"))
    +message = response.parse()   # objeto que messages.create() retornaria
    +print(message.content)
    +

    E13.3 with_streaming_response (corpo sob demanda)

    +

    Diferente de with_raw_response (que lê o corpo inteiro de imediato), + with_streaming_response exige context manager e só lê ao chamar .read(), .text(), + .json(), .iter_bytes(), .iter_text(), .iter_lines() ou .parse().

    +
    with client.messages.with_streaming_response.create(
    +    max_tokens=1024, model="claude-opus-4-8",
    +    messages=[{"role": "user", "content": "Olá, Claude"}],
    +) as response:
    +    print(response.headers.get("request-id"))
    +    for line in response.iter_lines():
    +        print(line)
    + +
    + +
    +

    E14. Sistema de tipos (request/response)

    +
      +
    • Requisições: parâmetros aninhados são TypedDict — autocompletar e checagem no editor.
    • +
    • Respostas: modelos Pydantic, com .to_json() e .to_dict().
    • +
    +
    message = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá"}])
    +json_str = message.to_json()   # string JSON
    +data = message.to_dict()       # dict
    +
    +# Distinguir campo null vs ausente
    +if message.some_field is None:
    +    if "some_field" not in message.model_fields_set:
    +        print("campo ausente na resposta")
    +    else:
    +        print("campo veio como null")
    +
    +# Propriedades não documentadas
    +extra = message.model_extra     # dict com campos extras
    +
    VS Code: defina python.analysis.typeCheckingMode como + basic para ver erros de tipo cedo.
    + +
    + +
    +

    E15. Logging, requisições não documentadas e cliente HTTP custom

    +

    E15.1 Logging

    +

    O SDK usa o módulo logging padrão. Habilite com a variável de ambiente:

    +
    export ANTHROPIC_LOG=debug   # ou info
    +

    E15.2 Endpoints/params não documentados

    +
    # Endpoint não documentado (respeita retries/timeout do cliente)
    +import httpx
    +response = client.post("/foo", cast_to=httpx.Response, body={"my_param": True})
    +print(response.json())
    +
    +# Param/header/query extra (sobrescrevem os documentados de mesmo nome!)
    +client.messages.create(
    +    model="claude-opus-4-8", max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá"}],
    +    extra_headers={"X-Custom": "1"},
    +    extra_query={"debug": "true"},
    +    extra_body={"experimental": {"flag": True}},
    +)
    +
    Segurança: extra_headers/extra_query/extra_body + sobrescrevem parâmetros documentados de mesmo nome — use apenas com dados confiáveis.
    +

    E15.3 Cliente HTTP customizado (proxies, transporte)

    +
    import httpx
    +from anthropic import Anthropic, DefaultHttpxClient
    +
    +client = Anthropic(
    +    base_url="http://meu.servidor.example.com:8083",  # ou env ANTHROPIC_BASE_URL
    +    http_client=DefaultHttpxClient(
    +        proxy="http://meu.proxy.example.com",
    +        transport=httpx.HTTPTransport(local_address="0.0.0.0"),
    +    ),
    +)
    +# Por requisição:
    +client.with_options(http_client=DefaultHttpxClient())
    +
    Use DefaultHttpxClient / DefaultAsyncHttpxClient + (e não httpx.Client cru) para preservar timeouts e limites de conexão padrão do SDK.
    +

    E15.4 Header de versão

    +

    O SDK envia automaticamente anthropic-version: 2023-06-01. Sobrescrever via + default_headers ou extra_headers pode causar comportamento indefinido — evite salvo necessidade real.

    + +
    + +
    +

    E16. Namespace beta

    +

    Recursos beta ficam sob client.beta.*. Para habilitar uma feature beta, inclua o + beta header apropriado + no campo betas ao criar a mensagem.

    +
    resp = client.beta.messages.create(
    +    model="claude-opus-4-8", max_tokens=1024,
    +    messages=[{"role": "user", "content": "..."}],
    +    betas=["files-api-2025-04-14"],   # ex.: Files API
    +)
    +
    + + + + + + + + + + + +
    Namespace betaPrincipais métodos
    client.beta.messages · .batchescreate, count_tokens, tool_runner; batches create/retrieve/list/cancel/delete/results
    client.beta.modelslist, retrieve
    client.beta.filesupload, list, retrieve_metadata, download, delete
    client.beta.agents · .versionscreate/retrieve/update/list/archive (Managed Agents — ver Parte D)
    client.beta.sessions · .events/.resources/.threadscreate/retrieve/update/list/delete/archive; eventos list/send/stream
    client.beta.vaults · .credentialscreate/retrieve/update/list/delete/archive; mcp_oauth_validate
    client.beta.memory_stores · .memoriescreate/retrieve/update/list/delete
    client.beta.skills · client.beta.user_profiles · client.beta.environmentsCRUD de skills, perfis de usuário e ambientes
    +

    Tipos beta espelham os estáveis com prefixo Beta (ex.: BetaMessage, BetaUsage, + BetaModelInfo, FileMetadata).

    + +
    + +
    +

    E17. Clientes de plataforma (Bedrock, Vertex, Foundry, AWS)

    +

    Os cinco clientes vêm no pacote base anthropic (alguns exigem extras). Detalhes de cada plataforma + na Parte D (D9).

    +
    + + + + + + + + +
    ProvedorClasse (import de anthropic)Extra
    Bedrock (novo)AnthropicBedrockMantleanthropic[bedrock]
    Bedrock (InvokeModel legado)AnthropicBedrockanthropic[bedrock]
    Vertex AIAnthropicVertexanthropic[vertex]
    Microsoft FoundryAnthropicFoundry—
    Claude Platform on AWS BetaAnthropicAWSanthropic[aws]
    +
    # Exemplos de inicialização
    +from anthropic import AnthropicBedrockMantle, AnthropicVertex, AnthropicAWS
    +
    +bedrock = AnthropicBedrockMantle()           # novo padrão p/ Bedrock
    +vertex  = AnthropicVertex(region="us-east5", project_id="meu-projeto")
    +aws     = AnthropicAWS(workspace_id="...")   # ou env ANTHROPIC_AWS_WORKSPACE_ID (beta)
    +
    +msg = bedrock.messages.create(
    +    model="anthropic.claude-opus-4-8",       # IDs com prefixo de plataforma — ver Parte D
    +    max_tokens=1024,
    +    messages=[{"role": "user", "content": "Olá"}],
    +)
    +
    Recomendação: use AnthropicBedrockMantle em projetos novos; + AnthropicBedrock permanece para apps existentes que usam a API InvokeModel do Bedrock.
    + +
    + + + + +
    +

    Parte F — SDK JavaScript/TypeScript (@anthropic-ai/sdk): referência exaustiva

    +

    Cobertura completa e fiel do SDK oficial @anthropic-ai/sdk, extraída de + platform.claude.com/docs/en/api/sdks/typescript + e do repositório oficial. Espelha a Parte E (SDK Python) para o ecossistema + JS/TS: instalação e runtimes suportados, cliente e todas as opções, mensagens e tipos, streaming + (iterável e por event handlers), helpers de ferramentas (Zod/JSON + ToolError), + helpers de MCP, batches, contagem de tokens, upload de arquivos (toFile), modelos e paginação, + hierarquia de erros, retries/timeouts (incluindo a fórmula dinâmica), respostas cruas, logging, + requisições não documentadas, fetch/proxy customizado, namespace beta, pacotes de plataforma + e o aviso de uso no navegador. Todos os exemplos usam os modelos atuais + (claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5).

    +
    + +
    +

    F1. Instalação e runtimes suportados

    +
    npm install @anthropic-ai/sdk
    +# ou: pnpm add @anthropic-ai/sdk · yarn add @anthropic-ai/sdk · bun add @anthropic-ai/sdk
    +

    Requer TypeScript ≥ 4.9. Runtimes oficialmente suportados:

    +
    + + + + + + + + + + + + +
    RuntimeSuporte
    Node.js20 LTS+ (versões não-EOL)
    Denov1.28.0+
    Bun1.0+
    Cloudflare WorkersSim
    Vercel Edge RuntimeSim
    Nitrov2.6+
    Jest28+ com ambiente "node" ("jsdom" não suportado)
    Navegador (browser)Desabilitado por padrão — habilite com dangerouslyAllowBrowser: true (ver F18)
    React NativeNão suportado
    +
    SemVer: o pacote segue SemVer, mas mudanças que afetam apenas tipos + estáticos, internos públicos não documentados, ou de impacto mínimo, podem sair como minor.
    + +
    + +
    +

    F2. Inicializando o cliente e opções

    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic({
    +  apiKey: process.env["ANTHROPIC_API_KEY"], // padrão; pode ser omitido
    +});
    +
    +const message = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Olá, Claude" }],
    +});
    +console.log(message.content);
    +

    F2.1 Opções do construtor

    +
    + + + + + + + + + + + + + + + +
    OpçãoTipoPadrão / EnvDescrição
    apiKeystringANTHROPIC_API_KEYChave da API (header x-api-key).
    authTokenstringANTHROPIC_AUTH_TOKENToken Bearer (ex.: WIF) como alternativa à API key.
    baseURLstringhttps://api.anthropic.com · ANTHROPIC_BASE_URLSobrescreve a URL base.
    timeoutnumber (ms)600000 (10 min; dinâmico p/ max_tokens alto — ver F12)Timeout da requisição.
    maxRetriesnumber2Retentativas automáticas com backoff.
    defaultHeadersobject—Headers padrão em todas as requisições.
    defaultQueryobject—Query params padrão.
    fetchOptionsRequestInit—Opções repassadas ao fetch (proxy, agent — ver F15).
    fetchfunçãoglobalThis.fetchImplementação de fetch customizada.
    logLevelstring'warn' · ANTHROPIC_LOGdebug | info | warn | error | off.
    loggerLoggerglobalThis.consoleLogger custom (pino, winston, bunyan…).
    dangerouslyAllowBrowserbooleanfalseHabilita execução no navegador (ver F18).
    + +
    + +
    +

    F3. Mensagens, tipos e usage

    +

    A biblioteca inclui definições TypeScript para todos os params de requisição e campos de resposta — + importáveis via o namespace Anthropic.*. Documentação de cada método/param aparece no hover do editor.

    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic();
    +
    +const params: Anthropic.MessageCreateParams = {
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Olá, Claude" }],
    +};
    +const message: Anthropic.Message = await client.messages.create(params);
    +
    +console.log(message.content[0]);   // ContentBlock (ex.: TextBlock)
    +console.log(message.usage);        // { input_tokens: 25, output_tokens: 13 }
    +console.log(message.stop_reason);  // "end_turn" | "max_tokens" | "tool_use" | ...
    +console.log(message._request_id);  // ver F13
    + +
    + +
    +

    F4. Streaming (iterável e por event handlers)

    +

    Duas abordagens, como no Python: create({stream:true}) retorna um async iterable de eventos + (menos memória); messages.stream(...) adiciona event handlers e acumulação.

    +

    F4.1 Iterável de eventos (stream: true)

    +
    const stream = await client.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Olá, Claude" }],
    +  stream: true,
    +});
    +for await (const event of stream) {
    +  console.log(event.type);   // message_start, content_block_delta, ...
    +}
    +// Para cancelar: break no loop, ou stream.controller.abort()
    +

    F4.2 Helper com event handlers (messages.stream)

    +
    const stream = client.messages
    +  .stream({
    +    model: "claude-opus-4-8",
    +    max_tokens: 1024,
    +    messages: [{ role: "user", content: "Diga olá!" }],
    +  })
    +  .on("text", (text) => process.stdout.write(text))      // delta de texto
    +  .on("streamEvent", (event) => { /* evento bruto SSE */ })
    +  .on("contentBlock", (block) => { /* bloco completo */ })
    +  .on("message", (msg) => { /* mensagem parcial acumulada */ })
    +  .on("finalMessage", (msg) => { /* mensagem final */ });
    +
    +const message = await stream.finalMessage();   // Promise<Message>
    +console.log(message);
    +
    Handlers disponíveis: text, streamEvent, + contentBlock, message, finalMessage. O objeto de stream também é + async iterable (for await … of stream). Tipos de evento SSE na Parte A (A5).
    + +
    + +
    +

    F5. Helpers de ferramentas (Zod / JSON Schema + ToolError)

    +

    O SDK JS facilita criar e executar ferramentas com esquemas Zod ou JSON Schema, executadas + via client.beta.messages.toolRunner() — que passa os inputs do modelo à função certa e devolve o + resultado ao modelo automaticamente.

    +
    import Anthropic from "@anthropic-ai/sdk";
    +import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
    +import { z } from "zod";
    +
    +const anthropic = new Anthropic();
    +
    +const weatherTool = betaZodTool({
    +  name: "get_weather",
    +  description: "Obtém o clima atual de um local",
    +  inputSchema: z.object({ location: z.string() }),
    +  run: (input) => `O tempo em ${input.location} está nublado, 16°C`,
    +});
    +
    +const finalMessage = await anthropic.beta.messages.toolRunner({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1000,
    +  messages: [{ role: "user", content: "Como está o tempo em São Paulo?" }],
    +  tools: [weatherTool],
    +});
    +console.log(finalMessage.content);
    +

    F5.1 Erros de ferramenta (ToolError)

    +

    Para reportar um erro ao modelo, lance ToolError de dentro do run — diferente de um + Error comum, ele aceita content blocks (texto, imagem) na resposta de erro. Um Error + comum é convertido num bloco de texto.

    +
    import { ToolError } from "@anthropic-ai/sdk/lib/tools/BetaRunnableTool";
    +
    +const screenshotTool = betaZodTool({
    +  name: "take_screenshot",
    +  inputSchema: z.object({ url: z.string() }),
    +  run: async (input) => {
    +    if (!isValidUrl(input.url)) throw new ToolError(`URL inválida: ${input.url}`);
    +    const result = await takeScreenshot(input.url);
    +    if (result.error) {
    +      throw new ToolError([
    +        { type: "text", text: `Falha ao carregar: ${result.error}` },
    +        { type: "image", source: { type: "base64", data: result.screenshot, media_type: "image/png" } },
    +      ]);
    +    }
    +    return { type: "image", source: { type: "base64", data: result.screenshot, media_type: "image/png" } };
    +  },
    +});
    +

    Também é possível definir ferramentas manualmente via input_schema (JSON Schema) em + messages.create({tools:[...]}) — ver Parte C.

    + +
    + +
    +

    F6. Helpers de MCP (Model Context Protocol)

    +

    O SDK JS converte tipos MCP para tipos da Claude API, reduzindo boilerplate ao usar ferramentas, + prompts e recursos de servidores MCP locais. (Para servidores MCP remotos por URL + com suporte só a ferramentas, prefira o parâmetro mcp_servers — ver Parte C (MCP).)

    +
    import Anthropic from "@anthropic-ai/sdk";
    +import { mcpTools, mcpMessages, mcpResourceToContent, mcpResourceToFile }
    +  from "@anthropic-ai/sdk/helpers/beta/mcp";
    +import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    +import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
    +
    +const anthropic = new Anthropic();
    +const transport = new StdioClientTransport({ command: "mcp-server", args: [] });
    +const mcpClient = new Client({ name: "my-client", version: "1.0.0" });
    +await mcpClient.connect(transport);
    +
    +// Prompts MCP → mensagens
    +const { messages } = await mcpClient.getPrompt({ name: "my-prompt" });
    +await anthropic.beta.messages.create({
    +  model: "claude-opus-4-8", max_tokens: 1024, messages: mcpMessages(messages),
    +});
    +
    +// Ferramentas MCP com toolRunner
    +const { tools } = await mcpClient.listTools();
    +await anthropic.beta.messages.toolRunner({
    +  model: "claude-opus-4-8", max_tokens: 1024,
    +  messages: [{ role: "user", content: "Use as ferramentas disponíveis" }],
    +  tools: mcpTools(tools, mcpClient),
    +});
    +
    +// Recurso MCP como conteúdo / como arquivo
    +const resource = await mcpClient.readResource({ uri: "file:///doc.txt" });
    +mcpResourceToContent(resource);
    +await anthropic.beta.files.upload({ file: mcpResourceToFile(resource) });
    +
    Erros: as funções de conversão lançam UnsupportedMCPValueError + se um valor MCP não for suportado (tipo de conteúdo/MIME inválido, recurso não-http/https).
    + +
    + +
    +

    F7. Message Batches (client.messages.batches)

    +
    const batch = await client.messages.batches.create({
    +  requests: [
    +    { custom_id: "req-1", params: {
    +        model: "claude-opus-4-8", max_tokens: 1024,
    +        messages: [{ role: "user", content: "Olá, mundo" }] } },
    +    { custom_id: "req-2", params: {
    +        model: "claude-opus-4-8", max_tokens: 1024,
    +        messages: [{ role: "user", content: "Oi de novo, amigo" }] } },
    +  ],
    +});
    +
    +// Quando batch.processing_status === "ended":
    +const results = await client.messages.batches.results(batch.id);
    +for await (const entry of results) {
    +  if (entry.result.type === "succeeded") console.log(entry.result.message.content);
    +}
    +

    Conceito e limites na Parte A (A12); schema REST na Parte D (D5).

    + +
    + +
    +

    F8. Contagem de tokens (countTokens)

    +
    const count = await client.messages.countTokens({
    +  model: "claude-opus-4-8",
    +  messages: [{ role: "user", content: "Hello, world" }],
    +});
    +console.log(count.input_tokens);
    +
    +// Uso real após a resposta:
    +const message = await client.messages.create(/* ... */);
    +console.log(message.usage); // { input_tokens: 25, output_tokens: 13 }
    + +
    + +
    +

    F9. Upload de arquivos (toFile e variantes)

    +

    Parâmetros de upload aceitam: um File (ou objeto equivalente), uma Response do + fetch, um fs.ReadStream, ou o retorno do helper toFile. + Defina o content-type explicitamente — a Files API não o infere.

    +
    import fs from "fs";
    +import Anthropic, { toFile } from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic();
    +
    +// fs.ReadStream
    +await client.beta.files.upload({
    +  file: await toFile(fs.createReadStream("/caminho/data.json"), undefined, { type: "application/json" }),
    +});
    +// Web File API
    +await client.beta.files.upload({ file: new File(["meus bytes"], "file.txt", { type: "text/plain" }) });
    +// Response do fetch
    +await client.beta.files.upload({ file: await fetch("https://site/arquivo") });
    +// Buffer / Uint8Array
    +await client.beta.files.upload({ file: await toFile(Buffer.from("meus bytes"), "file", { type: "text/plain" }) });
    +

    Profundidade de visão/PDF/documentos na Parte B; endpoints REST na Parte D (D7).

    + +
    + +
    +

    F10. Models API e paginação automática

    +
    // Recuperar
    +const model = await client.models.retrieve("claude-opus-4-8");
    +
    +// Listar com auto-paginação (busca páginas conforme necessário)
    +for await (const m of client.models.list({ limit: 20 })) console.log(m.id);
    +
    +// Uma página por vez + navegação manual
    +let page = await client.messages.batches.list({ limit: 20 });
    +for (const item of page.data) console.log(item);
    +while (page.hasNextPage()) { page = await page.getNextPage(); }
    +
    +// Iterar páginas
    +for await (const p of client.models.list().iterPages()) console.log(p.data);
    +

    Tabela canônica de modelos na Parte A (A3).

    + +
    + +
    +

    F11. Tratamento de erros

    +
    const message = await client.messages
    +  .create({ model: "claude-opus-4-8", max_tokens: 1024,
    +            messages: [{ role: "user", content: "Olá, Claude" }] })
    +  .catch((err) => {
    +    if (err instanceof Anthropic.APIError) {
    +      console.log(err.status);  // 400
    +      console.log(err.name);    // BadRequestError
    +      console.log(err.headers); // { server: 'nginx', ... }
    +    } else { throw err; }
    +  });
    +
    + + + + + + + + + + + + + +
    StatusClasse
    400BadRequestError
    401AuthenticationError
    403PermissionDeniedError
    404NotFoundError
    409ConflictError
    422UnprocessableEntityError
    429RateLimitError
    ≥ 500InternalServerError
    redeAPIConnectionError
    timeoutAPIConnectionTimeoutError
    +

    Todas herdam de Anthropic.APIError. Formato de erro REST na Parte D (D8).

    + +
    + +
    +

    F12. Retries e timeouts (incl. fórmula dinâmica)

    +

    F12.1 Retries

    +

    Padrão: 2 retentativas com backoff (conexão, 408, 409, 429, ≥500).

    +
    const client = new Anthropic({ maxRetries: 0 });   // padrão é 2
    +// por requisição:
    +await client.messages.create({ /* ... */ }, { maxRetries: 5 });
    +

    F12.2 Timeouts

    +

    Padrão: 10 minutos. Porém, se max_tokens for grande e você não estiver + usando streaming, o timeout default é calculado dinamicamente (até ~60 min):

    +
    // fórmula do default dinâmico (não-streaming, max_tokens grande):
    +const minimum = 10 * 60;
    +const calculated = (60 * 60 * maxTokens) / 128_000;
    +const timeoutMs = (calculated < minimum ? minimum : calculated) * 1000;
    +
    +const client = new Anthropic({ timeout: 20 * 1000 }); // 20 s (override do default)
    +await client.messages.create({ /* ... */ }, { timeout: 5 * 1000 }); // por requisição
    +

    Em timeout lança APIConnectionTimeoutError (e a requisição é retentada). Para requisições longas, + prefira streaming; passar stream:true ou timeout desativa o erro de "requisição > 10 min".

    + +
    + +
    +

    F13. Request ID e resposta crua (asResponse / withResponse)

    +
    // Request ID (header request-id) — para logar/correlacionar com o suporte
    +const message = await client.messages.create({ /* ... */ });
    +console.log(message._request_id); // req_018Ee...
    +
    +// .asResponse(): retorna o Response cru assim que os headers chegam (não consome o corpo)
    +const response = await client.messages.create({ /* ... */ }).asResponse();
    +console.log(response.headers.get("request-id"));
    +
    +// .withResponse(): consome o corpo e devolve { data, response }
    +const { data, response: raw } = await client.messages.create({ /* ... */ }).withResponse();
    +console.log(raw.headers.get("request-id"), data.content);
    + +
    + +
    +

    F14. Logging

    +

    Configure por variável de ambiente ANTHROPIC_LOG ou pela opção logLevel (que sobrescreve + a env). Níveis: debug ▸ info ▸ warn (padrão) ▸ error ▸ off. + No nível debug, todas as requisições/respostas HTTP são logadas (alguns headers de auth são redigidos).

    +
    // via opção
    +const client = new Anthropic({ logLevel: "debug" });
    +
    +// logger custom (pino, winston, bunyan, consola, signale, @std/log)
    +import pino from "pino";
    +const logger = pino();
    +new Anthropic({ logger: logger.child({ name: "Anthropic" }), logLevel: "debug" });
    +
    ANTHROPIC_LOG=debug node script.js
    + +
    + +
    +

    F15. Requisições não documentadas, fetch e proxies

    +

    F15.1 Endpoints/params não documentados

    +
    // endpoint não documentado (respeita retries/opções do cliente)
    +await client.post("/some/path", { body: { some_prop: "foo" }, query: { arg: "bar" } });
    +
    +// param extra: use @ts-expect-error (não validado em runtime; enviado as-is)
    +client.messages.create({
    +  model: "claude-opus-4-8", max_tokens: 1024, messages: [/* ... */],
    +  // @ts-expect-error baz ainda não é público
    +  baz: "opção não documentada",
    +});
    +

    F15.2 fetch customizado e fetchOptions

    +
    import Anthropic from "@anthropic-ai/sdk";
    +import myFetch from "my-fetch";
    +
    +const client = new Anthropic({
    +  fetch: myFetch,                 // ou globalThis.fetch = myFetch
    +  fetchOptions: { /* RequestInit */ },
    +});
    +

    F15.3 Proxies por runtime

    +
    +
    + + + +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +import * as undici from "undici";
    +
    +const proxyAgent = new undici.ProxyAgent("http://localhost:8888");
    +const client = new Anthropic({ fetchOptions: { dispatcher: proxyAgent } });
    +
    +
    +
    import Anthropic from "@anthropic-ai/sdk";
    +
    +const client = new Anthropic({ fetchOptions: { proxy: "http://localhost:8888" } });
    +
    +
    +
    import Anthropic from "npm:@anthropic-ai/sdk";
    +
    +const httpClient = Deno.createHttpClient({ proxy: { url: "http://localhost:8888" } });
    +const client = new Anthropic({ fetchOptions: { client: httpClient } });
    +
    +
    + +
    + +
    +

    F16. Namespace beta

    +
    const response = await client.beta.messages.create({
    +  model: "claude-opus-4-8",
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: [
    +    { type: "text", text: "Resuma este documento." },
    +    { type: "document", source: { type: "file", file_id: "file_abc123" } },
    +  ]}],
    +  betas: ["files-api-2025-04-14"],   // habilita a feature beta via header
    +});
    +

    Ative cada feature beta incluindo o beta header em betas: [...]. Espelha o namespace beta do Python (E16).

    + +
    + +
    +

    F17. Pacotes de plataforma (npm separados)

    +

    Diferente do Python (clientes no pacote base), no JS cada plataforma é um pacote npm separado:

    +
    + + + + + + + +
    PlataformaPacote npmCliente
    Amazon Bedrock@anthropic-ai/bedrock-sdkAnthropicBedrockMantle (novo) · AnthropicBedrock (path bedrock-runtime/InvokeModel legado)
    Google Vertex AI@anthropic-ai/vertex-sdkAnthropicVertex
    Microsoft Foundry@anthropic-ai/foundry-sdkAnthropicFoundry
    Claude Platform on AWS Beta@anthropic-ai/aws-sdkAnthropicAws (workspaceId ou ANTHROPIC_AWS_WORKSPACE_ID)
    +
    import AnthropicBedrock from "@anthropic-ai/bedrock-sdk";
    +import AnthropicVertex from "@anthropic-ai/vertex-sdk";
    +
    +const bedrock = new AnthropicBedrock({ awsRegion: "us-east-1" });
    +const vertex  = new AnthropicVertex({ projectId: "meu-projeto", region: "us-east5" });
    +
    +const msg = await bedrock.messages.create({
    +  model: "anthropic.claude-opus-4-8",  // IDs com prefixo de plataforma — ver Parte D
    +  max_tokens: 1024,
    +  messages: [{ role: "user", content: "Olá" }],
    +});
    +

    Detalhes por plataforma (IDs, auth) na Parte D (D9).

    + +
    + +
    +

    F18. Uso no navegador (dangerouslyAllowBrowser)

    +
    Perigo: habilitar dangerouslyAllowBrowser: true expõe sua + chave secreta no código client-side. Qualquer usuário com acesso ao navegador pode inspecionar e extrair as + credenciais. Use apenas em cenários controlados: ferramentas internas com usuários confiáveis, + ou desenvolvimento/depuração com credenciais efêmeras e rotacionadas — nunca com a chave de produção.
    +
    const client = new Anthropic({ apiKey: "...", dangerouslyAllowBrowser: true });
    +

    Padrão recomendado: faça as chamadas a partir de um backend e exponha apenas um endpoint seu ao navegador.

    + +
    +
    +

    Apêndice

    +

    Notebooks do cookbook oficial, glossário consolidado e histórico deste guia.

    +
    +
    +

    Cookbook — notebooks & exemplos oficiais

    +

    Exemplos executáveis mantidos pela Anthropic. Use sempre os modelos atuais + (claude-opus-4-8, claude-sonnet-4-6, claude-haiku-4-5) ao rodar.

    + +
    +
    +

    Glossário

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TermoDefinição
    Divulgação progressivaEstratégia das Skills de carregar metadados sempre, instruções ao acionar e recursos sob demanda.
    Managed AgentHarness gerenciado (Agent, Environment, Session, Events) para tarefas longas/assíncronas.
    MCP tunnelsForma outbound-only de expor servidores MCP de rede privada ao Claude, via cloudflared + proxy.
    SigV4Assinatura de requisição AWS usada por Bedrock e Claude Platform on AWS.
    SKILL.mdArquivo com frontmatter YAML (name, description) que define uma Agent Skill; carregado por divulgação progressiva.
    WIF (Workload Identity Federation)Autenticação por token OIDC de curta duração via POST /v1/oauth/token (grant jwt-bearer).
    ZDR (Zero Data Retention)Arranjo em que dados não são armazenados em repouso após a resposta da API.
    @anthropic-ai/sdkPacote npm oficial do SDK JavaScript/TypeScript da Anthropic.
    @beta_toolDecorador que gera o schema da ferramenta a partir da assinatura/docstring de uma função Python.
    _request_idID da requisição (header request-id); única propriedade _ pública.
    adaptive thinkingModo de raciocínio em que o modelo decide quando/quanto pensar; recomendado para Opus 4.8 (thinking: {type:"adaptive"}).
    agent_toolset_20260401Toolset pré-construído de Managed Agents: bash, operações de arquivo, web search/fetch.
    allowed_callersArray que define quem chama a ferramenta: "direct" (modelo) e/ou "code_execution_20260120" (sandbox).
    Anthropic / AsyncAnthropicClasses de cliente síncrono e assíncrono do SDK Python.
    anthropic-betaHeader que habilita features beta (ex. managed-agents-2026-04-01, files-api-2025-04-14).
    anthropic-versionCabeçalho obrigatório de versão da API; valor atual: 2023-06-01.
    ANTHROPIC_ENVIRONMENT_KEYChave que autoriza o worker self-hosted a consumir a fila de trabalho do environment.
    ANTHROPIC_LOGVariável de ambiente para logging (debug | info).
    AnthropicBedrockMantleCliente recomendado para Amazon Bedrock em projetos novos.
    APIConnectionTimeoutErrorExceção lançada quando uma requisição expira (timeout) no SDK JS.
    asResponse() / withResponse()Acessam o Response cru do fetch (headers); withResponse devolve { data, response }.
    betasLista de beta headers passada em client.beta.messages.create para habilitar features beta.
    betaZodToolHelper que define uma ferramenta a partir de um schema Zod, com função run() executada pelo toolRunner.
    budget_tokensOrçamento fixo de tokens de pensamento no modo manual (thinking.type: "enabled").
    cache_controlMarca breakpoint de prompt caching ({"type":"ephemeral"}, opcional "ttl":"1h").
    cache_creation_input_tokensTokens escritos no cache; se ele e cache_read_input_tokens são 0, não houve cache.
    cache_miss_reasonMotivo do cache miss, retornado com a beta cache-diagnosis-2026-04-07.
    cache_read_input_tokensTokens lidos do cache (cobrados a 0,1× do input base).
    citationsHabilita citações verificáveis ({"enabled": true}) em document/search_result.
    clear_thinking_20251015Edit que remove blocos de pensamento antigos do contexto.
    clear_tool_uses_20250919Edit que remove resultados de ferramenta antigos do contexto.
    compact_20260112Edit que resume o histórico antigo (compaction) em vez de removê-lo.
    containerParâmetro da Messages API usado para referenciar Skills (skill_id/type/version) e reusar contêineres de code execution.
    context windowJanela de contexto: total de tokens referenciáveis (Opus 4.8 / Sonnet 4.6: 1M; Haiku 4.5: 200k).
    context_managementControla edição/compactação de contexto via edits (betas context-management-2025-06-27 / compact-2026-01-12).
    count_tokensEndpoint /v1/messages/count_tokens que estima input_tokens antes do envio.
    custom_idIdentificador único (1–64 chars) de cada request num Message Batch.
    dangerouslyAllowBrowserHabilita o SDK no navegador (expõe a chave — usar só em cenários controlados).
    DefaultHttpxClient / DefaultAioHttpClientClientes HTTP do SDK (httpx padrão; aiohttp para concorrência assíncrona).
    defer_loadingPropriedade que exclui a ferramenta do prompt inicial, carregando-a sob demanda via tool search; preserva o prompt cache.
    displayComo o pensamento volta na resposta: summarized ou omitted (padrão no Opus 4.8).
    documentBloco de conteúdo para PDF/texto/conteúdo customizado; suporta citations e cache_control.
    eager_input_streamingHabilita fine-grained tool streaming (sem buffering/validação de JSON) em ferramentas de usuário.
    effortEm output_config.effort: controla o gasto de tokens (low, medium, high, xhigh, max). Padrão = high. xhigh disponível em Opus 4.8/4.7, Sonnet 5, Fable 5, Mythos 5; max em todos com adaptive thinking (inclui Sonnet 5 e Sonnet 4.6).
    fetchOptionsRequestInit repassado ao fetch (proxy/agent/dispatcher por runtime).
    file_idIdentificador de arquivo da Files API (beta files-api-2025-04-14) referenciável por source.type: "file".
    imageBloco de conteúdo de imagem com source base64/url/file.
    inference_geoControle de residência de inferência por requisição: global (default) ou us.
    input_examplesExemplos de input válidos para guiar o Claude; não disponível em ferramentas server-side.
    iterPages()Itera páginas inteiras (JS); hasNextPage()/getNextPage() para navegação manual.
    max_retriesRetentativas automáticas (padrão 2) para erros de conexão/408/409/429/≥500.
    max_tokensMáximo de tokens a gerar numa resposta; limitado pelo teto do modelo (Opus 4.8 / Sonnet 4.6: 128k; Haiku 4.5: 64k). Na Batch API, Opus 4.8/4.7/4.6 e Sonnet 4.6 chegam a 300k com o header beta output-300k-2026-03-24.
    maxRetries (JS)Opção do cliente/requisição; padrão 2.
    MCP connectorRecurso que conecta a Messages API a servidores MCP remotos sem cliente MCP separado (beta mcp-client-2025-11-20).
    mcp_toolsetEntrada no array tools que configura quais ferramentas de um servidor MCP habilitar.
    mcpTools / mcpMessagesHelpers que convertem tipos MCP (ferramentas/prompts/recursos) para tipos da Claude API.
    messages.stream()Context manager de streaming com .text_stream e get_final_message() (acumula o Message final).
    messages.stream().on(...)Streaming com event handlers (text, streamEvent, contentBlock, message, finalMessage) + finalMessage().
    ModelInfoMetadados de modelo na Models API: id, display_name, created_at, max_input_tokens, capabilities.
    output_config.formatJSON outputs (structured outputs): força a resposta a seguir um JSON Schema.
    pause_turnMotivo de parada que indica que um turno de ferramenta server-side foi pausado; reenvie a conversa para continuar.
    processing_statusEstado de um Message Batch: in_progress → ended.
    redacted_thinkingBloco de pensamento criptografado por segurança; reenvie sem modificar.
    search_resultBloco de resultado de busca para RAG com citações nativas (source/title/content).
    search_result_locationLocalização de citação que aponta para search_result_index e blocos.
    server_tool_useBloco que aparece quando uma ferramenta server-side roda; id prefixado por srvtoolu_. Não exige tool_result.
    service_tierTier de capacidade: standard, priority ou batch.
    signatureCampo opaco com o pensamento completo criptografado, usado para verificar/reconstruir blocos reenviados.
    sk-ant-admin...Chave da Admin API (gerencia membros, workspaces, chaves).
    snapshot fixoCada model ID mapeia para pesos imutáveis; a partir da 4.6 os IDs são sem data, mas ainda assim pinned (não evergreen).
    speed: "fast"Fast mode (beta): saída até 2,5× mais rápida em Opus 4.8 a 6× o preço; header fast-mode-2026-02-01.
    stop_reasonMotivo do término da geração: end_turn, max_tokens, stop_sequence, tool_use, pause_turn, refusal, model_context_window_exceeded.
    strictPropriedade que força (grammar-constrained sampling) os inputs da ferramenta a casarem com o JSON Schema.
    strict: trueStrict tool use: valida os inputs de uma ferramenta contra seu input_schema via sampling guiado por gramática.
    svac_ / fdis_ / fdrl_Prefixos de service account, federation issuer e federation rule (WIF).
    SyncPage / AsyncPageObjetos de página com auto-paginação (has_next_page, get_next_page, .data, .last_id).
    systemPrompt de sistema — instruções/persona enviadas como campo de topo, não como turno de messages.
    task_budgetTeto de tokens para a tarefa inteira (várias requisições); beta task-budgets-2026-03-13.
    thinkingConfiguração de raciocínio estendido: adaptive (modelo decide), enabled (manual com budget_tokens) ou disabled.
    toFileHelper do SDK JS para criar uploads a partir de ReadStream/Buffer/Uint8Array com content-type explícito.
    tool_choiceControla a escolha de ferramentas: auto, any, tool ou none.
    tool_resultBloco na mensagem do usuário que devolve o resultado de uma ferramenta client-side, casado por tool_use_id. Pode ter is_error: true.
    tool_runnerclient.beta.messages.tool_runner — executa o laço de tool use automaticamente.
    tool_useBloco de conteúdo na resposta do assistente que representa a requisição do Claude para chamar uma ferramenta (com id, name, input). Acompanha stop_reason: "tool_use".
    ToolErrorErro lançável de dentro de uma tool que aceita content blocks (texto/imagem) na resposta de erro.
    toolRunnerclient.beta.messages.toolRunner — executa o laço de tool use automaticamente (JS).
    UsageObjeto de contagem de tokens: input/output, cache_creation/read, server_tool_use, service_tier, inference_geo.
    whsec_Segredo de assinatura de webhook de Managed Agents (header X-Webhook-Signature).
    with_options()Retorna um cliente com overrides por requisição (max_retries, timeout, http_client...).
    with_raw_responseAcessa headers/corpo crus; .parse() devolve o objeto tipado.
    with_streaming_responseLê o corpo sob demanda via context manager (.iter_lines, .read, .json...).
    wrkspc_Prefixo de ID de workspace.
    x-api-keyCabeçalho de autenticação com a chave do Claude Console.
    +
    +
    +

    Histórico deste guia

    +
      +
    • 2026-05-24 — Versão completa, produzida por um time de 4 agentes Claude Opus 4.7 + em paralelo (orquestração + revisão Claude). Parte A (Fundamentos, Modelos, Mensagens, streaming, + stop_reason, structured outputs, effort, contexto, embeddings, batch), Parte B (adaptive/extended + thinking, prompt caching, cache diagnostics, context editing, compaction, visão, PDF, Files, citations), + Parte C (tool use e todas as ferramentas, Agent Skills, MCP) e Parte D (SDKs, referência REST completa, + Message Batches, Models/Files API, Managed Agents, governança/WIF/compliance, Bedrock/Vertex/Foundry). + Apêndice com cookbook, glossário e este histórico.
    • +
    • 2026-05-24 (Parte E + setup) — Adicionada a Parte E — SDK Python + (anthropic), referência exaustiva extraída da página oficial do SDK Python e do + api.md do repositório (clientes sync/async e opções de construtor, streaming, @beta_tool/ + tool_runner, batches, paginação, hierarquia de erros, retries/timeouts, respostas cruas, tipos, + logging, namespace beta e clientes de plataforma). Incluído o bloco Setup em 4 passos e o cookbook + expandido a partir do repositório claude-cookbooks.
    • +
    • 2026-05-24 (Parte F + foco Python/JS) — Adicionada a Parte F — SDK + JavaScript/TypeScript (@anthropic-ai/sdk), referência exaustiva paralela à do Python + (runtimes suportados, opções do cliente, streaming por event handlers, helpers de ferramentas Zod/JSON + + ToolError, helpers de MCP, batches, toFile, paginação, erros, fórmula dinâmica de + timeout, asResponse/withResponse, logging, proxies por runtime, namespace beta, + pacotes de plataforma e dangerouslyAllowBrowser). A tabela de SDKs foi focada em + Python e JavaScript/TypeScript (as demais linguagens oficiais são citadas apenas como referência).
    • +
    • 2026-05-24 (política de modelos) — Restrito aos modelos gerais atuais: + claude-opus-4-7 e claude-sonnet-4-6 (geração 4.6+: o ID puro, sem data, + é o snapshot fixo — não é ponteiro evergreen) e + claude-haiku-4-5 (geração pré-4.6: alias do snapshot datado claude-haiku-4-5-20251001). + Todas as tabelas oficiais que citavam gerações anteriores foram reescritas.
    • +
    • 2026-05-24 (verificação de versionamento) — Corrigida a linha de snapshot da tabela + de modelos: o Opus 4.7 não usa um snapshot datado ...-20251101 (essa data + pertence ao Opus 4.5 legado); na geração 4.6+ o ID dateless é o próprio snapshot canônico. Confirmado em + models/overview e models/model-ids-and-versions.
    • +
    • 2026-06-03 (migração Opus 4.8) — A linha Opus do guia migrou de + claude-opus-4-7 para claude-opus-4-8 (recomendado atual; o 4.7 passou a + Legacy). Specs centrais confirmadas idênticas em models/overview: + 1M de contexto, 128k de saída, adaptive thinking (sem extended), $5/$25 por MTok; no 4.8 o + effort assume high por padrão em todas as superfícies. Créditos de produção e + notas datadas de 2026-05-24 preservados como registro histórico.
    • +
    • 2026-06-10 (varredura de atualização) — Verificação contra a documentação oficial. + Adicionado callout no catálogo de modelos: Claude Fable 5 (claude-fable-5, + GA em 2026-06-09 — $10/$50 por MTok, 1M de contexto, 128k de saída, adaptive thinking sempre ativo, + tokenizer do Opus 4.7, stop_reason "refusal" + fallbacks beta, retenção + obrigatória de 30 dias, cache mínimo de 512 tokens) e Claude Mythos 5 em + disponibilidade limitada; Opus 4.8 segue ativo e recomendado (o guia permanece centrado + nele). Registradas as aposentadorias de Sonnet 4 / Opus 4 (2026-06-15) e Opus 4.1 (2026-08-05) e o campo + usage.output_tokens_details.thinking_tokens (desde 2026-05-27). Corrigido o code execution: + GA sem header beta desde 2026-02-17 (o header legado code-execution-2025-08-25 + segue aceito por compatibilidade) e code_execution_20260120 disponível em + Opus 4.5+ e Sonnet 4.5+ (não Haiku 4.5), conforme a página oficial da ferramenta. + Marcadores de verificação atualizados para 2026-06-10.
    • +
    • 2026-06-11 (delta sweep) — Re-verificação contra os release notes oficiais da API. + Incorporado: stop_details.category ganha o valor "reasoning_extraction" no + Fable 5 (09/06 — bloqueio por engenharia reversa/duplicação de outputs sob os ToS); advisor tool aceita + tools[].max_tokens (02/06); a não-cobrança de refusals sem output gerado é política de toda a + Claude API desde 02/06 (não exclusiva do Fable 5); Managed Agents ganhou scheduled deployments, credenciais + de variável de ambiente em vaults e o campo session_thread_id nos eventos + session.thread_* (09/06).
    • +
    • 2026-06-16 (micro-sweep de versões) — SDKs Anthropic subiram para + 0.109.2 (Python) / 0.104.2 (TS), ambos em 15/06: removem os modelos + aposentados da API e dos SDKs (limpeza da retirada de 15/06). A 0.109.1 (09/06) já + havia adicionado a refusal category frontier_llm. Sem endpoint, parâmetro ou modelo + novo — apenas manutenção.
    • +
    • 2026-06-19 (micro-sweep de versões) — SDKs Anthropic subiram para + 0.111.0 (Python) / 0.105.0 (TS). A 0.110.0 (18/06) adicionou + o suporte tipado ao tool code_execution_20260120 — a capacidade já era + GA e está documentada na §4.5 — além de corrigir o merge de headers x-stainless-helper + e o tipo de evento de stream no Bedrock; a TS 0.105.0 também passou a parsear o JSON + parcial de tool input de forma lazy. A 0.111.0 (18/06) apenas marca requests de + fallback de recusa com fallback-refusal-middleware. Sem endpoint, parâmetro ou modelo + novo — apenas manutenção.
    • +
    • 2026-06-25 (varredura de freshness) — SDK anthropic em + 0.112.0 (Python, 24/06). Correção factual: a saída máxima do + Sonnet 4.6 é 128k (não 64k) na Messages API — alinhado a + models/overview; também documentado o teto de 300k na Batch API via header + output-300k-2026-03-24. O Claude Fable 5 segue GA (09/06) porém + indisponível no momento (confirmar status atual). Sem endpoint, parâmetro ou + modelo novo.
    • +
    • 2026-06-29 (varredura de freshness — changelogs oficiais reverificados) — SDK + anthropic 0.113.0 (Python, 29/06; adiciona web fetch/support tools + 20260318) e @anthropic-ai/sdk 0.107.0 (Node). Sampling + depreciado: temperature/top_p/top_k retornam 400 + com valor não-default em Opus 4.7/4.8 e Fable 5. Tokenizer novo (~30% mais tokens) em + Opus 4.7+/Fable 5. Depreciações de modelo: Opus 4.1 (claude-opus-4-1-20250805) + deprecado 05/06, retirement 05/08/2026 → Opus 4.8; Sonnet 4 e Opus 4 + (*-20250514) já retired em 15/06/2026; fast mode do Opus 4.7 removido + em 24/07/2026. Confirmado: Fable 5 = GA porém temporariamente indisponível para + usuários regulares; Sonnet 4.6 = 128k e Haiku 4.5 = 64k de saída máxima. Fonte: + platform.claude.com/docs/.../model-deprecations.
    • +
    • 2026-07-12 (varredura de freshness) — effort: tabela e intro + corrigidas para refletir o suporte real (Fable 5 / Opus 4.8 / 4.7 / Sonnet 5 (+ 4.6), + default high; Haiku 4.5 não suporta; max em + Fable 5/Opus 4.8-4.6/Sonnet 5-4.6; xhigh em Fable 5/Opus 4.8-4.7/Sonnet 5, não em Sonnet 4.6). + Combinação effort+thinking agora inclui Sonnet 5 (erro 400). + Adicionado code_execution_20260521 às tabelas de tipos e à §4.5, com nota literal de que o + Haiku 4.5 aceita os tipos 20260120/20260521 mas + não executa programmatic tool calling nem persistência de estado do REPL. + Structured output GA passa a listar Sonnet 5. Versões: anthropic + 0.116.0 (Python). Fonte: platform.claude.com/docs (effort, code-execution, structured-outputs).
    • +
    • 2026-07-05 (varredura de freshness) — Claude Sonnet 5 + (claude-sonnet-5) lançado em GA em 2026-06-30: passa a ser o Sonnet + recomendado e default de Free/Pro no claude.ai; 1M ctx, 128k saída, adaptive thinking ligado por + padrão, effort nos 5 níveis (low…max), tokenizer novo, cutoff Jan 2026. Preço intro + $2/$10 por MTok até 31/08/2026, depois $3/$15. O + Sonnet 4.6 foi rebaixado a "Legacy" na doc oficial (ainda suportado). Fable 5: + após suspensão global por controles de exportação dos EUA (12–30/06), foi reimplantado a partir + de 01/07/2026 com classificador de segurança reforçado (fallback automático p/ Opus 4.8) — model + ID/preço/specs inalterados; portanto o "indisponível" das entradas anteriores está resolvido. + SDKs: anthropic 0.116.0 (Python, 02/07) e @anthropic-ai/sdk + 0.110.0 (Node, 02/07 — 0.108.0 adicionou suporte a claude-sonnet-5; 0.109.0 + trouxe Managed Agents com streaming de eventos/overrides/webhooks; 0.110.0 introduziu o beta header + agent-memory-2026-07-22). Fonte: anthropic.com/news/claude-sonnet-5, + anthropic.com/news/redeploying-fable-5, PyPI e GitHub releases.
    • +
    +

    Fontes primárias: platform.claude.com/docs + (export llms-full.txt) e github.com/anthropics/anthropic-cookbook. + Verificado em 2026-07-12 — para fatos perecíveis (modelos, datas, preços, limites, headers beta), + consulte sempre a fonte oficial.

    +
    +
    +
    + +
    +
    +
    +
    Guia Claude API Anthropic · PT-BR
    +

    + Referência técnica construída a partir da documentação oficial pública em + 2026-06-11 (versões de SDK reconferidas em 2026-06-19). Para informações sempre atualizadas, consulte + platform.claude.com/docs. + Para fatos perecíveis (modelos, datas, preços, limites), a documentação oficial é a fonte autoritativa. +

    +
    +
    +
    Crédito de produção
    +
    Produzido por um time de 4 agentes Claude Opus 4.7
    +
    em paralelo · orquestração + revisão Claude · 2026-05-24
    +
    + anthropic + PT-BR + SOTA +
    +
    +
    +
    Navegação rápida
    + + + + +
    +
    +
    + + + + diff --git a/references/agents_tools_best_guides/guia_contexto_compactacao_estrategias.html b/references/agents_tools_best_guides/guia_contexto_compactacao_estrategias.html index 52c410f..bb352fb 100644 --- a/references/agents_tools_best_guides/guia_contexto_compactacao_estrategias.html +++ b/references/agents_tools_best_guides/guia_contexto_compactacao_estrategias.html @@ -637,6 +637,8 @@

    Sumário

  • Subdividir X
  • Topologia de sessão
  • Escada de compactação
  • +
  • Compactação server-side (OpenAI)
  • +
  • Compactação server-side (Anthropic)
  • Snapshots cumulativos
  • Skills antigas
  • Tool results e RAG
  • @@ -1061,6 +1063,200 @@

    5. Escada de compactação

    +
    +

    5A. Compactação server-side (OpenAI)

    +

    A escada da seção 5 é a estratégia que você implementa no seu orquestrador. A OpenAI também expõe compactação nativa do provedor na Responses API, em dois modos: automática no servidor (context_management + compact_threshold) e manual sob demanda (client.responses.compact()). É o par funcional do compaction da Anthropic (§5B) — mesma ideia de "resumir em vez de cortar" no servidor, com mecânica e payload diferentes.

    + +

    Modo 1 — automático, no responses.create()

    +

    Habilite context_management com um compact_threshold (contagem de tokens renderizados) direto na chamada responses.create(). Quando a contagem de tokens renderizados cruza o limiar, o servidor executa a compactação sozinho, emite um item de compactação criptografado e opaco no mesmo stream (não é resumo legível por humano) e poda o contexto antes de continuar a inferência. Encadeando com previous_response_id, você continua enviando apenas a mensagem nova do usuário a cada turno — não precisa reenviar o histórico nem chamar nenhum endpoint separado.

    + +
    conversation = [
    +    {"type": "message", "role": "user", "content": "Let's begin a long coding task."}
    +]
    +
    +while keep_going:
    +    response = client.responses.create(
    +        model="gpt-5.3-codex",
    +        input=conversation,
    +        store=False,
    +        context_management=[{"type": "compaction", "compact_threshold": 200000}],
    +    )
    +
    +    conversation.extend(response.output)
    +    conversation.append({
    +        "type": "message",
    +        "role": "user",
    +        "content": get_next_user_input(),
    +    })
    + +
    + Forma exata do parâmetro + context_management é uma lista contendo um objeto {"type": "compaction", "compact_threshold": N}, onde N é um inteiro de tokens renderizados (no exemplo oficial, 200000). É passado direto em client.responses.create() / POST /responses, junto com store=False para manter o fluxo compatível com ZDR. +
    + + + + + + + + + + + + + + + + + + +
    Encadeamento após compactação automática no servidor
    Estratégia de encadeamentoO que enviar no próximo turnoCuidado
    previous_response_idSó a mensagem nova do usuário; o ID carrega o resto.Não faça pruning manual do histórico — o servidor já é a fonte de verdade do que foi retido.
    Array de input (stateless)Anexe os itens de saída (incluindo os de compactação) ao próximo array, como de costume.Itens anteriores ao último item de compactação podem ser descartados do array para reduzir latência de cauda longa — o item de compactação já carrega o estado necessário para continuar.
    + +

    Modo 2 — manual, client.responses.compact()

    +

    Quando você mesmo gerencia o array completo de input (mensagens, tools e outros itens), chame client.responses.compact(model=..., input=...) diretamente. O endpoint é POST /responses/compact, é totalmente stateless e ZDR-friendly: recebe a janela completa e devolve uma nova janela compactada em compacted.output, que já inclui um item de compactação criptografado carregando o estado e o raciocínio prévio relevante em menos tokens (além de outros itens retidos da janela original — não é só o item de compactação sozinho).

    + +
    long_input_items_array = [...]  # janela completa de turnos anteriores
    +
    +compacted = client.responses.compact(
    +    model="gpt-5.6",
    +    input=long_input_items_array,
    +)
    +
    +next_input = [
    +    *compacted.output,  # usar a saída compactada como está
    +    {
    +        "type": "message",
    +        "role": "user",
    +        "content": user_input_message(),
    +    },
    +]
    +
    +next_response = client.responses.create(
    +    model="gpt-5.6",
    +    input=next_input,
    +    store=False,  # mantém o fluxo compatível com ZDR
    +)
    + +
    + Não edite o output compactado + compacted.output não é um resumo legível para revisão humana — é estado de máquina opaco e criptografado (item de compactação + itens retidos). Não pode ser podado nem reescrito: a única operação válida é repassá-lo como está para o próximo responses.create(), anexando apenas a nova mensagem do usuário. A janela que você envia ao /responses/compact ainda precisa caber na janela de contexto do modelo. +
    + + + + + + + + + + + + + + + + + + + + + + + +
    Modo automático vs. modo manual (OpenAI)
    AspectoAutomático (context_management)Manual (responses.compact())
    GatilhoServidor dispara sozinho ao cruzar compact_threshold, embutido no próprio responses.create() e emitido no mesmo stream.Você decide o momento e chama responses.compact() explicitamente — ex.: após fechar uma fase/milestone.
    Gerenciamento do históricoprevious_response_id (sem pruning manual) ou array stateless (com descarte opcional de itens pré-compactação).Você já gerencia o array de input completo por conta própria.
    ZDRZDR-friendly com store=False.Endpoint totalmente stateless e ZDR-friendly por natureza.
    + +
    + Onde isso encaixa na estratégia deste guia + A compactação server-side da OpenAI resolve a fatia conversa/tools do jeito do provedor — análoga ao degrau summarize_old/snapshot da escada (seção 5), mas decidida e executada pelo servidor, não pelo seu orquestrador. Ela não substitui o ledger canônico e os snapshots cumulativos (seção 6): o item de compactação é opaco e não serve como registro auditável do que foi preservado ou removido — para isso, continue mantendo seu próprio snapshot com preserved_ids/removed_ids/reclaimed_tokens em paralelo. +
    + +
    + Fontes oficiais + OpenAI — guia dedicado developers.openai.com/api/docs/guides/compaction; developers.openai.com/api/docs/guides/deployment-checklist (seção "Leverage compaction"); referência developers.openai.com/api/docs/api-reference/responses/compact. +
    +
    + +
    +

    5B. Compactação server-side (Anthropic)

    +

    A Anthropic expõe a mesma ideia na Messages API, como um edit de context_management: quando o input cruza um gatilho, o servidor gera um resumo, embute-o num bloco compaction e, nas requisições seguintes, descarta automaticamente todos os blocos de conteúdo anteriores a esse bloco, continuando a conversa a partir do resumo. É o par funcional da compactação da OpenAI (§5A) — mesma intenção, payload e billing diferentes.

    + +
    + Header e strategy (atenção ao formato) + Beta header anthropic-beta: compact-2026-01-12 (com hífens); a strategy em context_management.edits[] é {"type": "compact_20260112"} (sem hífens, como nos demais edits — clear_tool_uses_20250919, clear_thinking_20251015). Verificado na fonte oficial em 2026-07-12. +
    + +
    import anthropic
    +
    +client = anthropic.Anthropic()
    +
    +response = client.beta.messages.create(
    +    model="claude-opus-4-8",
    +    max_tokens=4096,
    +    betas=["compact-2026-01-12"],
    +    messages=conversation,               # histórico acumulado
    +    context_management={
    +        "edits": [
    +            {
    +                "type": "compact_20260112",
    +                "trigger": {"type": "input_tokens", "value": 150000},  # default; mín. 50 000
    +                # "instructions": "Preserve nomes de variáveis, decisões técnicas e próximos passos.",
    +                # "pause_after_compaction": False,
    +            }
    +        ]
    +    },
    +)
    +
    +# Nas próximas requisições, anexe response ao messages: a API ignora todos os
    +# blocos anteriores ao bloco `compaction` e continua a partir do resumo.
    +conversation.extend(response.content)
    + + + + + + + + + + + + + + + + + + + + + + + +
    Parâmetros de compact_20260112
    ParâmetroDefaultDescrição
    trigger{"type":"input_tokens","value":150000}input_tokens é o único tipo suportado; value precisa ser ≥ 50 000 — abaixo disso a API retorna erro.
    pause_after_compactionfalseSe true, a API para após gerar o resumo (stop_reason: "compaction"), permitindo injetar blocos (ex.: mensagens recentes a preservar) antes de continuar.
    instructionsnullPrompt de sumarização custom. Substitui por completo o prompt padrão (que instrui o modelo a envolver o resumo em <summary>…</summary>).
    + +
    + Modelos suportados + Fable 5, Mythos 5, Mythos Preview, Opus 4.8 / 4.7 / 4.6, Sonnet 5 e Sonnet 4.6 (lista verbatim da doc). ZDR-elegível — os dados enviados por essa feature não são retidos após a resposta. +
    + +
    + Billing: some usage.iterations + A compactação exige um passo extra de sampling que conta para rate limits e billing (não é grátis). O input_tokens/output_tokens de topo não incluem a iteração de compactação — cada entrada de usage.iterations[] tem type: "compaction" ou "message"; para o total cobrado, some todas as entradas. Reaplicar um bloco compaction já gerado (repassá-lo em turnos seguintes) não re-dispara custo de compactação. +
    + +
    + Onde isso encaixa + Como a §5A da OpenAI, a compactação da Anthropic resolve a fatia conversa no servidor — análoga ao degrau summarize_old/snapshot da escada (seção 5). Diferença material vs. OpenAI: aqui o bloco compaction traz um resumo em <summary> (não é opaco como o item criptografado da OpenAI), mas ainda não substitui o ledger canônico (seção 6) — mantenha seu snapshot auditável em paralelo. O gatilho é checado no início de cada iteração de sampling, então pode disparar mais de uma vez por request (ex.: com server tools iterando). +
    + +
    + Fontes oficiais + Anthropic — guia dedicado platform.claude.com/docs/en/build-with-claude/compaction; disponível também em Amazon Bedrock, Google Cloud (Vertex AI) e Microsoft Foundry. +
    +
    +

    6. Snapshots cumulativos e ledger original

    Compactar é criar uma visão menor para a próxima chamada. O original completo continua no ledger/storage; a compactação vira um snapshot cumulativo, versionado e auditável.

    diff --git a/references/agents_tools_best_guides/guia_deepagents.html b/references/agents_tools_best_guides/guia_deepagents.html index 13435d2..97edbb1 100644 --- a/references/agents_tools_best_guides/guia_deepagents.html +++ b/references/agents_tools_best_guides/guia_deepagents.html @@ -4,8 +4,8 @@ Guia Deep Agents — Referência completa (Python) - - + + - - - - -
    -
    -
    Guia Gemini Interactions API PT-BR · Referência completa + Migração
    -
    - Verificado em 2026-06-29 - google-genai - GA - -
    -
    -
    - -
    - - -
    - -
    -

    Guia Gemini Interactions API — Referência completa + Migração

    -

    - Documentação técnica exaustiva da Gemini Interactions API - (GA desde junho/2026 — a interface recomendada por padrão para novos projetos), - sucessora do método generateContent. - Cobre a anatomia da Interaction (timeline de steps), - texto, streaming SSE, multimodal (imagem/áudio/vídeo/PDF), - function calling, structured output, thinking, caching, Deep Research, - ferramentas server-side (Google Search, Maps, Code Execution, URL Context, - File Search, Computer Use, MCP), background tasks, webhooks - e a referência REST completa, além de uma seção dedicada com mapeamento - antes/depois e breaking changes de Maio 2026. -

    -

    - ⭐ Destaque: a Interactions API é agora GA (junho/2026) e o caminho - SOTA recomendado pela Google para todo projeto novo. Modelos recomendados: - gemini-3.5-flash (Flash estável, padrão) e gemini-3.1-pro-preview - (reasoning/multimodal avançado). SDK google-genai ≥ 2.0.0 (último 2.10.0). -

    -
    - google-genai · Python ≥ 2.0.0 (último 2.10.0) - @google/genai · JS ≥ 2.0.0 (último 2.10.0) - GA · jun/2026 - SOTA · 2026-06-29 - Schema steps · Api-Revision ignorado -
    -
    - -
    -

    Sobre este guia

    -

    - Este é um guia técnico exaustivo, em português brasileiro, da nova - Google Gemini Interactions API — a interface padrão recomendada - pela Google para novos projetos agênticos, conversas multiturno com estado - no servidor e fluxos com ferramentas. O método generateContent - continua suportado, mas a migração é incentivada e várias capacidades novas - (Deep Research, novos modelos da família Gemini 3.x) chegam apenas via Interactions. -

    -

    O guia é organizado em três partes e um apêndice:

    -
      -
    • Parte A — Conceitos & Guias: explica cada capacidade da API - com exemplos em Python, JavaScript e REST, no formato encontrado na documentação oficial.
    • -
    • Parte B — Referência REST: enumera todos os endpoints, schemas, - enums, tipos de step, tipos de content, tipos de tool e eventos SSE.
    • -
    • Parte C — Migração: par-a-par de antes (generateContent) - e depois (Interactions), tabela completa de mapeamento, - checklist e as breaking changes oficiais de Maio 2026.
    • -
    • Apêndice: notebooks do cookbook, glossário e histórico do guia.
    • -
    -
    - Como ler: cada capítulo expõe Python, JS e REST em paralelo, - preservando exatamente os exemplos oficiais. Se um detalhe divergir do - publicado em ai.google.dev, a documentação oficial é a fonte autoritativa. -
    -
    - Status: GA (junho/2026). A Interactions API é agora - generally available e a interface recomendada por padrão para - todo desenvolvimento novo — a própria landing page da Gemini API - recomenda interactions.create para novos projetos. Importante: o - endpoint permanece em /v1beta/interactions — o rótulo GA não - promoveu o caminho para /v1/. O conjunto de breaking changes de - Maio 2026 (ver seção dedicada) - já foi consumado em 08/06/2026: a matriz outputs foi - substituída por steps, os eventos SSE foram renomeados, - response_format absorveu response_mime_type e - image_config, o schema legado foi removido permanentemente, o header - Api-Revision passou a ser ignorado (a janela de rollback - com Api-Revision: 2026-05-07 fechou nessa data) e os SDKs 1.x falham nas - chamadas de Interactions. O método generateContent continua suportado, - mas várias capacidades novas (Deep Research, agentes gerenciados) chegam só via Interactions. -
    -
    - Superfície: Developer API (GA) vs Vertex / Gemini Enterprise Agent Platform (experimental). - Toda a documentação desta página e os exemplos REST abaixo usam a - Gemini Developer API (AI Studio): endpoint - generativelanguage.googleapis.com/v1beta/interactions e header - x-goog-api-key com chave do - AI Studio. - A Interactions API também existe na Vertex AI / Gemini Enterprise Agent Platform - (endpoint aiplatform.googleapis.com/v1beta1/projects/{project}/locations/global/interactions, - auth OAuth/ADC), porém rotulada como experimental — status diferente do - GA da Developer API. Nem toda ferramenta tem paridade documentada entre as duas: - code_execution dentro de Interactions é documentado/exemplificado só na Developer API; - na Vertex a execução de código é documentada via generateContent (ver - §17.3 e o guia de code tools). - Em produção na Vertex, valide a disponibilidade de cada recurso antes de migrar de - generateContent para Interactions. - Verificado em 2026-06-29, fontes oficiais Google. -
    -
    - -
    -

    Fontes oficiais

    - -

    - Última verificação contra estas fontes: 2026-06-19. - Sempre que houver divergência entre este guia e a documentação oficial em - produção, a documentação oficial é a fonte autoritativa. Capturas literais - de exemplos e tabelas preservam a acentuação PT-BR original. -

    -
    - -
    -

    TL;DR · Migração rápida

    -

    Se você já usa generateContent e precisa migrar, decore estes pontos:

    -
    - - - - - - - - - - - - - - - - - - - -
    AspectogenerateContent (legado)Interactions API (novo)
    EndpointPOST /v1beta/models/{model}:generateContentPOST /v1beta/interactions
    Streaming:streamGenerateContentmesmo endpoint + "stream": true
    Históricocliente reenvia array contentsservidor mantém via previous_interaction_id
    Resposta textoresponse.candidates[0].content.parts[0].textinteraction.output_text
    Estrutura da respostacandidates[].content.parts[]steps[] tipados
    Schema estruturadogenerationConfig.responseFormatresponse_format (top-level)
    Image configgeneration_config.image_configresponse_format: {type:"image", ...}
    Toolstools=[{google_search:{}}]tools=[{"type":"google_search"}]
    Function declaration{name, description, parameters} aninhado em function_declarations{"type":"function", name, description, parameters} direto em tools
    Function call IDnão garantidostep.id obrigatório (Gemini 3)
    CitaçõesgroundingMetadata.groundingSupports com índicesannotations[] inline em content[].annotations
    Tasks longasnão suportadasbackground=true + webhook_config
    Retençãon/a (stateless)55 dias pago / 1 dia free (padrão store=true)
    SDK Python mínimoqualquer google-genai≥ 2.0.0 (obrigatório desde 08/06/2026; SDKs 1.x falham nas chamadas de Interactions)
    SDK JS mínimoqualquer @google/genai≥ 2.0.0 (obrigatório desde 08/06/2026; SDKs 1.x falham nas chamadas de Interactions)
    -
    -
    - Datas críticas (Breaking changes Maio 2026): -
      -
    • 07/05/2026 — SDKs Python 2.0.0 e JS 2.0.0 publicados. Opt-in via cabeçalho Api-Revision: 2026-05-20.
    • -
    • 26/05/2026 — Novo schema virou padrão; rollback temporário possível via Api-Revision: 2026-05-07 (janela já encerrada).
    • -
    • 08/06/2026 — Schema legado removido permanentemente (consumado). Headers de rollback ignorados; SDKs 1.x falham.
    • -
    -
    -

    Detalhes completos em Parte C — Migração.

    -
    - - - - - - -
    -

    Parte A — Conceitos & Guias

    -

    Capítulos 1–23 cobrindo todos os conceitos públicos da Gemini Interactions API, em ordem de leitura recomendada da documentação oficial. Exemplos em Python (google-genai), JavaScript (@google/genai) e REST/cURL.

    -
    - -
    -

    1. Visão geral da Interactions API

    - -

    A API Interactions é a nova interface padrão do Gemini para fluxos agênticos, conversas multiturno com estado server-side e operações longas. Está em Beta e seus esquemas estão sujeitos a mudanças incompatíveis (ver breaking changes de Maio 2026). O método generateContent continua funcional e suportado, mas novos recursos (Deep Research, novos modelos da família Gemini 3.x exclusivos) chegam apenas via Interactions.

    - -

    1.1 Por que usar a Interactions API

    -
      -
    • Gerenciamento de histórico server-side: conversa multiturno via previous_interaction_id. O servidor ativa estado por padrão (store=true); para modo stateless, defina store=false.
    • -
    • Etapas de execução observáveis: a resposta é uma timeline tipada de steps (thought, function_call, function_result, model_output, google_search_call, etc.), facilitando depuração e renderização de UI para eventos intermediários.
    • -
    • Criado para fluxos agênticos: orquestração nativa multi-turno com ferramentas.
    • -
    • Tarefas longas em background: background=true habilita operações assíncronas (Deep Think, Deep Research) com integração a webhooks.
    • -
    • Acesso exclusivo a novos modelos: agentes Deep Research e outros lançamentos saem direto na Interactions.
    • -
    - -

    1.2 Quando usar cada API

    -
    - - - - - - - - -
    SituaçãoAPI recomendada
    Novo projeto ou aplicação agênticaInteractions API
    Integração existente em produção estávelgenerateContent
    Recursos ainda não disponíveis em Interactions (Batch, cache explícito)generateContent
    Deep Research, agentes nativos, background tasksInteractions API
    -
    -
    - Atualização (2026-06-10): a página oficial de migração - (migrate-to-interactions) - agora descreve a Interactions API como "the standard interface for building with Gemini" - e a recomenda para todo desenvolvimento novo. A página de visão geral mantém - o aviso de Beta e generateContent como caminho estável para produção — a tabela - acima reflete as duas fontes. -
    - -

    1.3 Propriedades de conveniência do SDK

    -
    - - - - - - - -
    PropriedadeTipoDescrição
    interaction.output_textstringÚltimos blocos TextContent consecutivos unidos automaticamente. Não captura texto separado por pensamentos, imagens, áudio ou tool calls.
    interaction.output_imageImageContent ou NoneÚltimo bloco de imagem gerado pelo modelo.
    interaction.output_audioAudioContent ou NoneÚltimo bloco de áudio gerado pelo modelo.
    -
    -
    - Quando iterar manualmente: para inspecionar pensamentos, function calls ou conteúdo intercalado (texto + imagem + áudio), itere interaction.steps. -
    - -

    1.4 SDKs & versões mínimas

    -
    - - - - - - - - - -
    LinguagemPacoteVersão mínimaInstalação
    Python (≥ 3.9)google-genai2.0.0 (SDKs 1.x falham desde 08/06/2026; último PyPI: 2.10.0)pip install -U google-genai
    JavaScript / TypeScript (Node ≥ 18)@google/genai2.0.0 (SDKs 1.x falham desde 08/06/2026; último npm: 2.10.0)npm install @google/genai
    Gogoogle.golang.org/genai—go get google.golang.org/genai
    Javacom.google.genai:google-genai1.0.0Maven artifact
    C#Google.GenAI—dotnet add package Google.GenAI
    -
    -

    Nota (2026-06-29): o último google-genai / @google/genai é 2.10.0 (ambos; 2026-06-24). A 2.9.0 reimplementou a Interactions internamente mantendo a API pública compatível e a 2.10.0 segue compatível, então os exemplos deste guia seguem válidos; mantenha o piso prático ≥ 2.0.0 (1.x falha desde 08/06/2026).

    -
    - Bibliotecas legadas descontinuadas em 30/11/2025: - google-generativeai (Python), @google/generativeai (JS), google.golang.org/generative-ai (Go), - google_generative_ai (Dart), generative-ai-swift, generative-ai-android. - Para Dart/Flutter e mobile (Swift/Android), a recomendação oficial passa a ser Firebase AI Logic, - e não o SDK google-genai. -
    - -

    1.5 Limitações conhecidas (vs. generateContent)

    -

    Recursos ainda ausentes em Interactions API (presentes em generateContent):

    -
      -
    • Metadados de vídeo (video_metadata: intervalos de corte, FPS customizado).
    • -
    • Batch API assíncrona em lote.
    • -
    • Chamada automática de função (Python apenas).
    • -
    • Cache explícito — porém cache implícito via previous_interaction_id está disponível.
    • -
    • MCP Remoto com Gemini 3 — "Gemini 3 não é compatível com MCP remoto, mas isso vai mudar em breve" (doc oficial). Além disso, apenas servidores Streamable HTTP são suportados — servidores baseados em SSE não são (e o name do servidor não pode conter -, use snake_case).
    • -
    - - -
    - -
    -

    2. Quickstart & SDKs

    - -

    2.1 Chave de API

    -

    Obtenha uma chave em aistudio.google.com/app/apikey. Em ambientes Python/JS o SDK lê automaticamente a variável GEMINI_API_KEY:

    -
    # macOS / Linux
    -export GEMINI_API_KEY="sk-..."
    -
    -# Windows PowerShell
    -$env:GEMINI_API_KEY = "sk-..."
    -
    -# Windows CMD
    -set "GEMINI_API_KEY=sk-..."
    - -

    2.2 Instalação

    -
    # Mínimo para usar a Interactions API hoje (schema steps, único desde 08/06/2026):
    -pip install -U "google-genai>=2.0.0"             # Python (último PyPI: 2.10.0)
    -npm install "@google/genai@>=2.0.0"              # Node / TypeScript (último npm: 2.10.0)
    -
    -# SDKs 1.x (google-genai < 2.0.0 / @google/genai < 2.0.0) falham nas
    -# chamadas de Interactions desde 08/06/2026 — schema legado removido.
    - -

    2.3 Primeira interação (Hello world)

    -

    Python

    -
    from google import genai
    -
    -client = genai.Client()
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="How does AI work?"
    -)
    -print(interaction.output_text)
    - -

    JavaScript

    -
    import { GoogleGenAI } from "@google/genai";
    -
    -const ai = new GoogleGenAI({});
    -
    -const interaction = await ai.interactions.create({
    -  model: "gemini-3.5-flash",
    -  input: "How does AI work?",
    -});
    -console.log(interaction.output_text);
    - -

    REST

    -
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H 'Content-Type: application/json' \
    -  -H "Api-Revision: 2026-05-20" \
    -  -d '{
    -    "model": "gemini-3.5-flash",
    -    "input": "How does AI work?"
    -  }'
    - -
    - Header Api-Revision (histórico): entre 07/05/2026 e 26/05/2026 ele controlou o opt-in no novo schema (2026-05-20) e, até 08/06/2026, o rollback temporário (2026-05-07). Desde 08/06/2026 o header é ignorado e pode ser omitido das chamadas — o schema steps é o único aceito. Os exemplos REST da doc oficial (incl. o novo quickstart) ainda o incluem; enviá-lo é inofensivo (no-op). -
    - - -
    - -
    -

    3. Anatomia de uma Interaction

    - -

    O recurso central da API é o objeto Interaction. Ele encapsula uma rodada completa de execução: as entradas do usuário, qualquer raciocínio (thoughts), chamadas de ferramentas, resultados e a resposta final do modelo — tudo organizado em uma timeline ordenada chamada steps.

    - -

    3.1 Campos principais

    -
    - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoDescrição
    idstringIdentificador único (v1_...) usado em previous_interaction_id.
    objectstringSempre "interaction".
    modelModelOptionID do modelo (ex.: gemini-3.5-flash). Obrigatório se agent não for fornecido.
    agentAgentOptionID do agente (ex.: deep-research-preview-04-2026, antigravity-preview-05-2026). Obrigatório se model não for fornecido.
    environment / environment_idstring | EnvironmentConfigSandbox de agente gerenciado: "remote" (novo), "env_..." (reuso) ou config completa. A resposta traz environment_id. Usado com agent (ver §18.9–18.10).
    statusInteractionStatusUm de in_progress, requires_action, completed, failed, cancelled, incomplete, budget_exceeded.
    created / updatedstring ISO 8601Timestamps.
    stepsStep[]Timeline ordenada de etapas (ver §3.2).
    inputContent / Content[] / Step[] / stringEntrada (texto livre, lista de blocks ou lista de steps em modo stateless).
    toolsTool[]Lista de ferramentas disponíveis para esta interação.
    response_formatResponseFormat / listConfigura saída estruturada e modalidades de resposta.
    system_instructionstringInstrução de sistema (precisa ser reespecificada por turno).
    generation_configGenerationConfigParâmetros de inferência (temperature, thinking_level, tool_choice, etc.).
    previous_interaction_idstringID da interação anterior para continuar o histórico.
    storebooleanArmazenamento server-side. Padrão true.
    backgroundbooleanExecuta em segundo plano (incompatível com store=false).
    webhook_configWebhookConfigURIs para notificação assíncrona.
    service_tierServiceTierflex | standard | priority.
    usageUsageContagem de tokens (entrada, saída, cache, thinking, ferramentas) por modalidade.
    -
    - -

    3.2 Tipos de step

    -

    Cada elemento de steps tem um campo type que discrimina seu papel. Veja a referência completa em Parte B — Step types. Os tipos mais comuns:

    -
    - - - - - - - - - - - - - - - -
    typeQuando apareceCampos principais
    user_inputApenas em GET /interactions/{id} com include_input=truecontent[]
    model_outputResposta final do modelocontent[] (text, image, audio, ...)
    thoughtRaciocínio interno (Gemini 3.x)signature, summary
    function_callModelo solicita execução de função do clienteid, name, arguments, signature
    function_resultCliente devolve resultadocall_id, name, result, is_error
    google_search_call / google_search_resultGrounding com Pesquisa Googlearguments.queries, result.search_suggestions
    code_execution_call / code_execution_resultExecução server-side de Pythonarguments.code, result, is_error
    url_context_call / url_context_resultLeitura de URLsarguments.urls, result.status
    google_maps_call / google_maps_resultGrounding com Google Mapsarguments.queries, result.places, widget_context_token
    file_search_call / file_search_resultRAG sobre File Search Storesid, call_id
    mcp_server_tool_call / mcp_server_tool_resultTool externa via MCP HTTP Streamingserver_name, name, arguments, result
    -
    - -

    3.3 Blocos de conteúdo (Content)

    -

    Dentro de step.content[] (e dentro de input multimodal) cada bloco tem type:

    -
    { "type": "text",     "text": "..." , "annotations": [ ... ] }
    -{ "type": "image",    "data": "<base64>",     "mime_type": "image/jpeg" }
    -{ "type": "image",    "uri":  "files/abc...",  "mime_type": "image/png"  }
    -{ "type": "audio",    "data": "<base64>",     "mime_type": "audio/mp3", "sample_rate": 16000, "channels": 1 }
    -{ "type": "document", "uri":  "files/abc...",  "mime_type": "application/pdf" }
    -{ "type": "video",    "uri":  "https://www.youtube.com/watch?v=..." }
    -{ "type": "video",    "uri":  "files/abc...",  "mime_type": "video/mp4", "resolution": "low" }
    - -

    3.4 Exemplo de resposta completa

    -
    {
    -  "id": "v1_ChdPU0F4YWFtNkFwS2kxZThQZ05lbXdROBIXT1NBeGFhbTZBcEtpMWU4UGdOZW13UTg",
    -  "object": "interaction",
    -  "model": "gemini-3.5-flash",
    -  "status": "completed",
    -  "created": "2025-11-26T12:25:15Z",
    -  "updated": "2025-11-26T12:25:15Z",
    -  "steps": [
    -    { "type": "thought",      "signature": "abc123..." },
    -    { "type": "model_output", "content": [
    -        { "type": "text", "text": "Hello! I'm functioning perfectly and ready to assist you.\n\nHow are you doing today?" }
    -    ]}
    -  ],
    -  "usage": {
    -    "input_tokens_by_modality": [{ "modality": "text", "tokens": 7 }],
    -    "total_input_tokens": 7,
    -    "total_output_tokens": 20,
    -    "total_thought_tokens": 22,
    -    "total_tokens": 49,
    -    "total_tool_use_tokens": 0,
    -    "total_cached_tokens": 0
    -  }
    -}
    - - -
    - -
    -

    4. Geração de texto

    - -

    A operação mais básica da Interactions API: enviar uma string ou lista de blocos como input e receber uma Interaction com a resposta nos steps.

    - -

    4.1 Exemplo mínimo

    -

    Python

    -
    from google import genai
    -
    -client = genai.Client()
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="How does AI work?"
    -)
    -print(interaction.output_text)
    - -

    JavaScript

    -
    import { GoogleGenAI } from "@google/genai";
    -
    -const ai = new GoogleGenAI({});
    -
    -const interaction = await ai.interactions.create({
    -  model: "gemini-3.5-flash",
    -  input: "How does AI work?",
    -});
    -console.log(interaction.output_text);
    - -

    REST

    -
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H 'Content-Type: application/json' \
    -  -H "Api-Revision: 2026-05-20" \
    -  -d '{
    -    "model": "gemini-3.5-flash",
    -    "input": "How does AI work?"
    -  }'
    - -

    4.2 System instruction

    -

    Use system_instruction para definir persona, política ou contexto. Lembre-se: instruções de sistema têm escopo por interação — você precisa reespecificá-las em cada turno (mesmo com previous_interaction_id) se quiser mantê-las.

    - -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    system_instruction="You are a cat. Your name is Neko.",
    -    input="Hello there"
    -)
    -print(interaction.output_text)
    - -

    4.3 Configuração de geração

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Explain how AI works",
    -    generation_config={
    -        "temperature": 1.0,
    -        "top_p": 0.95,
    -        "max_output_tokens": 1024,
    -        "stop_sequences": ["END"],
    -        "seed": 42
    -    }
    -)
    - -

    4.4 Pensando com o Gemini (thinking_level)

    -

    Nos modelos Gemini 3.x é possível ajustar o esforço de raciocínio. Veja a seção Thinking para a tabela completa de valores aceitos por modelo.

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="How does AI work?",
    -    generation_config={"thinking_level": "low"}
    -)
    -print(interaction.output_text)
    - -

    4.5 Entrada multimodal (imagem + texto)

    -
    from google import genai
    -client = genai.Client()
    -
    -uploaded_file = client.files.upload(file="path/to/organ.jpg")
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "text", "text": "Tell me about this instrument"},
    -        {"type": "image", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
    -    ]
    -)
    -print(interaction.output_text)
    - -

    4.6 Parâmetros principais

    -
    - - - - - - - - - - - - - - - -
    ParâmetroTipoDescrição
    modelstringModelo Gemini (ver ModelOption).
    inputstring · Content[] · Step[]Texto livre ou blocos multimodais.
    system_instructionstringInstrução de sistema.
    generation_configobjecttemperature, top_p, seed, thinking_level, max_output_tokens, stop_sequences...
    toolsTool[]Função, Google Search, Code Execution, etc.
    response_formatobject · arrayEstrutura de saída e modalidades.
    streambooleanSSE incremental.
    previous_interaction_idstringContinua histórico server-side.
    storebooleanPadrão true (servidor mantém estado).
    backgroundbooleanExecução assíncrona (Deep Research, Deep Think).
    service_tierstringflex · standard · priority.
    -
    - - -
    - -
    -

    5. Conversas multiturno

    - -

    A Interactions API gerencia o histórico no servidor por padrão. Para continuar uma conversa, basta passar o id da interação anterior em previous_interaction_id. Não é mais necessário reenviar o array contents inteiro como no generateContent.

    - -

    5.1 Padrão server-side (recomendado)

    -

    Python

    -
    from google import genai
    -
    -client = genai.Client()
    -
    -interaction1 = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="I have 2 dogs in my house.",
    -)
    -print(interaction1.output_text)
    -
    -interaction2 = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="How many paws are in my house?",
    -    previous_interaction_id=interaction1.id,
    -)
    -print(interaction2.output_text)
    - -

    JavaScript

    -
    const interaction1 = await ai.interactions.create({
    -  model: "gemini-3.5-flash",
    -  input: "I have 2 dogs in my house.",
    -});
    -
    -const interaction2 = await ai.interactions.create({
    -  model: "gemini-3.5-flash",
    -  input: "How many paws are in my house?",
    -  previous_interaction_id: interaction1.id,
    -});
    -console.log(interaction2.output_text);
    - -

    REST

    -
    RESPONSE1=$(curl -s -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H 'Content-Type: application/json' \
    -  -H "Api-Revision: 2026-05-20" \
    -  -d '{ "model": "gemini-3.5-flash", "input": "I have 2 dogs in my house." }')
    -
    -INTERACTION_ID=$(echo "$RESPONSE1" | jq -r '.id')
    -
    -curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H 'Content-Type: application/json' \
    -  -H "Api-Revision: 2026-05-20" \
    -  -d '{
    -    "model": "gemini-3.5-flash",
    -    "input": "How many paws are in my house?",
    -    "previous_interaction_id": "'$INTERACTION_ID'"
    -  }'
    - -
    - Parâmetros com escopo por interação: ao usar previous_interaction_id, alguns parâmetros precisam ser reespecificados a cada turno se ainda forem desejados — tools, system_instruction e generation_config (inclui thinking_level, temperature). -
    - -

    5.2 Modo sem estado (store=false)

    -

    Para conformidade ou casos onde você não quer armazenamento server-side, defina store=false. Nesse modo você é responsável por reenviar TODOS os steps gerados (incluindo thought com signature) em cada turno — caso contrário a continuidade de raciocínio quebra.

    -
    history = [
    -    {"type": "user_input", "content": [{"type": "text", "text": "I have 2 dogs."}]}
    -]
    -
    -interaction1 = client.interactions.create(
    -    model="gemini-3.5-flash", store=False, input=history
    -)
    -
    -for step in interaction1.steps:
    -    history.append(step.model_dump())
    -
    -history.append({
    -    "type": "user_input",
    -    "content": [{"type": "text", "text": "How many paws are in my house?"}]
    -})
    -
    -interaction2 = client.interactions.create(
    -    model="gemini-3.5-flash", store=False, input=history
    -)
    -print(interaction2.steps[-1].content[0].text)
    - -
    - Restrições de store=false: -
      -
    • Incompatível com background=true (Deep Research exige store=true).
    • -
    • Impede usar a interação como previous_interaction_id em chamadas subsequentes.
    • -
    • Você precisa preservar e reenviar todas as etapas geradas pelo modelo — incluindo assinaturas de thought.
    • -
    -
    - - -
    - -
    -

    6. Streaming (SSE)

    - -

    O streaming usa o mesmo endpoint POST /v1beta/interactions, apenas adicionando "stream": true no body. A resposta é um fluxo Server-Sent Events com eventos tipados por step. Não há mais o endpoint dedicado :streamGenerateContent.

    - -
    Transporte: a Interactions API é HTTP request-response (com estado no servidor via previous_interaction_id) e o streaming é SSE sobre HTTP — não há WebSocket nesse caminho. Interação bidirecional em tempo real (voz/vídeo, áudio-para-áudio) é a Live API sobre WebSocket (WSS, BidiGenerateContent, modelos como gemini-3.1-flash-live-preview) — uma superfície separada da Interactions API.
    - -

    6.1 Streaming básico

    -

    Python

    -
    stream = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Count from 1 to 25.",
    -    stream=True,
    -)
    -for event in stream:
    -    if event.event_type == "step.delta":
    -        if event.delta.type == "text":
    -            print(event.delta.text, end="", flush=True)
    - -

    JavaScript

    -
    const stream = await client.interactions.create({
    -  model: "gemini-3.5-flash",
    -  input: "Count from 1 to 25.",
    -  stream: true,
    -});
    -for await (const event of stream) {
    -  if (event.event_type === "step.delta" && event.delta.type === "text") {
    -    process.stdout.write(event.delta.text);
    -  }
    -}
    - -

    REST (SSE)

    -
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?alt=sse" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -H "Api-Revision: 2026-05-20" \
    -  --no-buffer \
    -  -d '{
    -    "model": "gemini-3.5-flash",
    -    "input": "Count from 1 to 25.",
    -    "stream": true
    -  }'
    - -

    6.2 Tipos de evento SSE

    -
    - - - - - - - - - - - -
    event_typeCarga principalQuando
    interaction.createdinteraction (id, status, model)Início do stream.
    interaction.status_updateinteraction_id, statusMudança de status. O campo status carrega o enum in_progress/requires_action/completed/failed/cancelled/incomplete/budget_exceeded (ver B8). Não existem eventos interaction.in_progress ou interaction.requires_action separados — essas são apenas valores de status.
    step.startindex, stepInicia um step (tipo: thought, model_output, function_call, etc.).
    step.deltaindex, deltaTrecho incremental do step atual.
    step.stopindexStep finalizado.
    interaction.completedinteraction com usageFinal do stream com contagem de tokens.
    errorerror.code, error.messageErro em tempo de execução.
    -
    -
    - Conjunto canônico de eventos SSE — schema novo (default desde 26/05/2026): interaction.created, interaction.in_progress, - interaction.requires_action, interaction.completed, step.start, step.delta, step.stop (mais error). No schema vigente, - interaction.in_progress e interaction.requires_action são eventos SSE distintos (cada um com seu event_type). O evento legado - interaction.status_update — que carregava o status num único evento — foi substituído por eles e foi removido junto do schema legado em 08/06/2026. - Verificado 2026-06-03 contra interactions-breaking-changes-may-2026#streaming (corrige a leitura anterior, baseada no schema legado). Os eventos de webhook (§19) são um namespace à parte e incluem - interaction.requires_action/cancelled. -
    - -

    6.3 Tipos de delta em step.delta

    -
    - - - - - - - - - - - - - -
    delta.typeCamposOnde aparece
    texttextmodel_output
    imagedata, uri, mime_type, resolutionmodel_output
    audiodata, uri, mime_type, sample_rate, channelsmodel_output
    documentdata, uri, mime_typemodel_output
    videodata, uri, mime_type, resolutionmodel_output
    thought_summarycontent (texto/imagem)thought
    thought_signaturesignaturethought (último delta)
    arguments_deltaarguments (string JSON parcial)function_call — exige acumulação até step.stop
    text_annotation_deltaannotations[]model_output (citações inline)
    -
    - -

    6.4 Exemplo de fluxo SSE completo

    -
    event: interaction.created
    -data: {"interaction":{"id":"v1_...","status":"in_progress","object":"interaction","model":"gemini-3.5-flash"},"event_type":"interaction.created"}
    -
    -event: interaction.in_progress
    -data: {"interaction_id":"v1_...","status":"in_progress","event_type":"interaction.in_progress"}
    -
    -event: step.start
    -data: {"index":0,"step":{"type":"thought"},"event_type":"step.start"}
    -
    -event: step.delta
    -data: {"index":0,"delta":{"signature":"...","type":"thought_signature"},"event_type":"step.delta"}
    -
    -event: step.stop
    -data: {"index":0,"event_type":"step.stop"}
    -
    -event: step.start
    -data: {"index":1,"step":{"type":"model_output"},"event_type":"step.start"}
    -
    -event: step.delta
    -data: {"index":1,"delta":{"text":"1, 2, 3, 4, 5, 6, ","type":"text"},"event_type":"step.delta"}
    -
    -event: step.delta
    -data: {"index":1,"delta":{"text":"7, 8, 9, 10","type":"text"},"event_type":"step.delta"}
    -
    -event: step.stop
    -data: {"index":1,"event_type":"step.stop"}
    -
    -event: interaction.completed
    -data: {"interaction":{"id":"v1_...","status":"completed","usage":{"total_tokens":346,"total_input_tokens":11,"total_output_tokens":90,"total_thought_tokens":245}},"event_type":"interaction.completed"}
    -
    -event: done
    -data: [DONE]
    - -

    6.5 Streaming com function calling

    -

    Diferente do generateContent, function calls em streaming chegam em partes: step.start entrega name e id, e cada step.delta com delta.type == "arguments_delta" traz um fragmento em delta.arguments (string JSON) que você precisa acumular até o step.stop.

    - -
    stream = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="What is the weather in Paris?",
    -    tools=[weather_tool],
    -    stream=True
    -)
    -
    -current_calls = {}
    -for event in stream:
    -    if event.event_type == "step.start" and event.step.type == "function_call":
    -        current_calls[event.index] = {
    -            "id": event.step.id,
    -            "name": event.step.name,
    -            "arguments": ""
    -        }
    -    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
    -        if event.index in current_calls:
    -            current_calls[event.index]["arguments"] += event.delta.arguments
    -
    -# Após interaction.completed, parse final
    -import json
    -for index, call in current_calls.items():
    -    call["arguments"] = json.loads(call["arguments"]) if call["arguments"] else {}
    -print(current_calls)
    - -

    6.6 Streaming com thinking summaries

    -
    stream = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="What is the greatest common divisor of 1071 and 462?",
    -    generation_config={"thinking_summaries": "auto"},
    -    stream=True,
    -)
    -for event in stream:
    -    if event.event_type == "step.delta":
    -        if event.delta.type == "thought_summary":
    -            if event.delta.content.type == "text":
    -                print(f"[Thought] {event.delta.content.text}", end="")
    -        elif event.delta.type == "text":
    -            print(event.delta.text, end="")
    - -

    6.7 Streaming de geração de imagem

    -
    stream = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="Search the history of the Colosseum and write a short illustrated story.",
    -    tools=[{"type": "google_search", "search_types": ["web_search", "image_search"]}],
    -    response_format=[{"type": "text"}, {"type": "image"}],
    -    stream=True,
    -)
    -for event in stream:
    -    if event.event_type == "step.delta":
    -        if event.delta.type == "text":
    -            print(event.delta.text, end="")
    -        elif event.delta.type == "image":
    -            print(f"[Image chunk: {len(event.delta.data)} bytes]")
    - -
    - Eventos desconhecidos: a política de versionamento da API admite novos tipos de eventos ao longo do tempo. Seu cliente deve registrar e pular tipos desconhecidos em vez de gerar erros. -
    - - -
    - -
    -

    7. Geração de imagens

    - -

    Modelos da família Nano Banana geram imagens nativamente como parte do fluxo Interactions. A imagem retorna como bloco image dentro de steps[].content[] e pode ser acessada via interaction.output_image.

    - -

    7.1 Modelos disponíveis

    -
    - - - - - - -
    Nome comercialModel IDFoco
    Nano Banana 2gemini-3.1-flash-imageGA desde 28/05/2026 (saiu de preview; o ID -preview é desligado em 25/06/2026). Geração/edição de imagem de alta eficiência e alto volume; suporta thinking_level e saída intercalada texto+imagem
    Nano Banana Progemini-3-pro-imageGA desde 28/05/2026. Qualidade máxima (estúdio): tipografia/texto precisos, composições complexas, até 4K; aceita mais imagens de referência por prompt
    -
    -

    Todas as imagens geradas incluem marca d'água SynthID.

    - -

    7.2 Limites técnicos

    -
      -
    • Aspect ratios: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9. Apenas gemini-3.1-flash-image: 1:4, 4:1, 1:8, 8:1.
    • -
    • Resoluções: 0.5K (apenas Flash 3.1), 1K (padrão), 2K, 4K. O image_size exige K maiúsculo (ex.: "2K") — inclusive o menor valor é "0.5K", não 512.
    • -
    • Imagens de referência: Flash 3.1 aceita até 10 objetos / 4 personagens; Pro 3 aceita até 6 objetos / 5 personagens.
    • -
    • MIME types: image/png, image/jpeg.
    • -
    - -

    7.3 Text-to-image

    -

    Python

    -
    from google import genai
    -import base64
    -
    -client = genai.Client()
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme",
    -)
    -
    -with open("generated_image.png", "wb") as f:
    -    f.write(base64.b64decode(interaction.output_image.data))
    - -

    JavaScript

    -
    import { GoogleGenAI } from "@google/genai";
    -import * as fs from "node:fs";
    -
    -const ai = new GoogleGenAI({});
    -
    -const interaction = await ai.interactions.create({
    -  model: "gemini-3.1-flash-image",
    -  input: "Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme",
    -});
    -if (interaction.output_image) {
    -  fs.writeFileSync("gemini-native-image.png",
    -    Buffer.from(interaction.output_image.data, "base64"));
    -}
    - -

    REST

    -
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -H "Api-Revision: 2026-05-20" \
    -  -d '{
    -    "model": "gemini-3.1-flash-image",
    -    "input": [{"type": "text", "text": "Create a picture of a nano banana dish..."}]
    -  }'
    - -

    7.4 Controle de proporção e resolução

    -
    interaction = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="Da Vinci style anatomical sketch of a dissected Monarch butterfly",
    -    response_format={
    -        "type": "image",
    -        "mime_type": "image/jpeg",
    -        "aspect_ratio": "1:1",
    -        "image_size": "1K"
    -    },
    -)
    - -

    7.5 Edição (text+image-to-image)

    -
    import base64
    -with open("/path/to/cat_image.png", "rb") as f:
    -    image_bytes = f.read()
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input=[
    -        {"type": "text", "text": "Replace the cat with a corgi wearing sunglasses."},
    -        {"type": "image", "data": base64.b64encode(image_bytes).decode('utf-8'),
    -         "mime_type": "image/png"}
    -    ],
    -)
    - -

    7.6 Edição multi-turn (conversacional)

    -
    interaction = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="Create a vibrant infographic that explains photosynthesis.",
    -    tools=[{"type": "google_search"}],
    -)
    -
    -interaction_2 = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="Update this infographic to be in Spanish. Do not change other elements.",
    -    previous_interaction_id=interaction.id,
    -    response_format={
    -        "type": "image",
    -        "mime_type": "image/jpeg",
    -        "aspect_ratio": "16:9",
    -        "image_size": "2K"
    -    },
    -)
    - -

    7.7 Saída intercalada (texto + imagens)

    -

    Modelos como gemini-3.1-flash-image podem gerar conteúdo intercalado. Você precisa iterar steps[].content[] em vez de usar output_image:

    -
    interaction = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="Write the story of the lifecycle of a monarch butterfly, interleave illustrations",
    -)
    -
    -image_counter = 1
    -for step in interaction.steps:
    -    if step.type == "model_output":
    -        for block in step.content:
    -            if block.type == "text":
    -                print(block.text)
    -            elif block.type == "image":
    -                with open(f"butterfly_lifecycle_{image_counter}.png", "wb") as f:
    -                    f.write(base64.b64decode(block.data))
    -                image_counter += 1
    - -

    7.8 Thinking durante geração de imagem

    -

    Thinking é ativado por padrão em modelos de imagem; não pode ser desativado. O modelo gera até dois "thought images" intermediários antes da imagem final. Tokens de thinking são cobrados normalmente.

    -
    interaction = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="A futuristic city built inside a giant glass bottle floating in space",
    -    generation_config={"thinking_level": "high"},
    -)
    -
    -# Inspecionar thought images intermediárias
    -for step in interaction.steps:
    -    if step.type == "thought":
    -        for content_block in step.summary or []:
    -            if content_block.type == "image":
    -                # base64 de thought image
    -                ...
    - -

    7.9 Grounding com Google Search (web + image search)

    -
    interaction = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="A detailed painting of a Timareta butterfly resting on a flower",
    -    tools=[{
    -      "type": "google_search",
    -      "search_types": ["web_search", "image_search"]
    -    }],
    -    response_format={"type": "image", "mime_type": "image/jpeg", "aspect_ratio": "16:9"}
    -)
    -
    - Ao usar Image Search é obrigatório exibir search_suggestions do step google_search_result na UI. -
    - - -
    - -
    -

    8. Compreensão de imagens

    - -

    8.1 Métodos de envio

    -
      -
    • Files API (recomendado para reuso e arquivos > 20 MB).
    • -
    • Inline Base64 (limite 20 MB no total do payload).
    • -
    • URI público / URL externo.
    • -
    - -

    8.2 Formatos suportados

    -
      -
    • image/png, image/jpeg, image/webp, image/heic, image/heif, image/gif, image/bmp, image/tiff.
    • -
    - -

    8.3 Limites e tokenização

    -
      -
    • Máximo: 3.600 imagens por requisição.
    • -
    • Tokens: imagens com ambas dimensões ≤ 384 px = 258 tokens; maiores são divididas em blocos de 768×768 px com 258 tokens cada.
    • -
    • tile_size = floor(min(width, height) / 1.5); blocos = ceil(width/tile_size) × ceil(height/tile_size).
    • -
    • Resolução: parâmetro media_resolution controla detalhe (custos mais altos).
    • -
    - -

    8.4 Exemplo — upload via Files API

    -
    from google import genai
    -client = genai.Client()
    -
    -my_file = client.files.upload(file="path/to/sample.jpg")
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "text", "text": "Caption this image."},
    -        {"type": "image", "uri": my_file.uri, "mime_type": my_file.mime_type}
    -    ]
    -)
    -print(interaction.output_text)
    - -

    8.5 Exemplo — inline Base64

    -
    import base64
    -with open('small.jpg', 'rb') as f:
    -    image_bytes = f.read()
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "text", "text": "Caption this image."},
    -        {"type": "image", "data": base64.b64encode(image_bytes).decode('utf-8'),
    -         "mime_type": "image/jpeg"}
    -    ]
    -)
    - -

    8.6 Múltiplas imagens

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "text", "text": "What is different between these two images?"},
    -        {"type": "image", "uri": "https://example.com/image1.jpg", "mime_type": "image/jpeg"},
    -        {"type": "image", "uri": "https://example.com/image2.jpg", "mime_type": "image/jpeg"}
    -    ]
    -)
    - -

    8.7 Detecção de objetos (bounding boxes)

    -

    Coordenadas no formato [ymin, xmin, ymax, xmax], normalizadas 0–1000. Redimensione para o tamanho real da imagem.

    -
    from pydantic import BaseModel, Field
    -from typing import List
    -
    -class BoundingBox(BaseModel):
    -    box_2d: List[int] = Field(description="[ymin, xmin, ymax, xmax] normalized 0-1000.")
    -    mask: List[List[int]] = Field(description="Segmentation mask as polygon of [x,y].")
    -    label: str
    -
    -class BoundingBoxes(BaseModel):
    -    boxes: List[BoundingBox]
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "text", "text": "Detect all prominent items. box_2d normalized 0-1000."},
    -        {"type": "image", "uri": "https://example.com/image.png", "mime_type": "image/png"}
    -    ],
    -    response_format={
    -        "type": "text",
    -        "mime_type": "application/json",
    -        "schema": BoundingBoxes.model_json_schema()
    -    }
    -)
    -detected = BoundingBoxes.model_validate_json(interaction.output_text)
    - -

    8.8 Segmentação

    -

    A máscara é um PNG codificado em base64 com valores 0–255. Recomenda-se thinking_level: "minimal" para melhores resultados.

    -
    Exceção de modelo: a segmentação de imagem não é suportada na família Gemini 3.x via Interactions API. Para esse workload, use o modelo dedicado gemini-robotics-er-1.6-preview (embodied reasoning).
    - - -
    - -
    -

    9. Áudio — compreensão & geração (TTS)

    - -

    9.1 Capacidades

    -

    Descrição, resumo, transcrição, tradução voz-texto, diarização de locutor, detecção de emoções, análise por timestamp (formato MM:SS).

    - -
    Qual modelo usar: não há modelo STT dedicado — a transcrição é compreensão de áudio em qualquer modelo multimodal 3.x. Use gemini-3.5-flash para qualidade máxima, ou gemini-3.1-flash-lite (multimodal, aceita áudio) como opção mais barata e rápida para transcrição em volume — a doc oficial o recomenda explicitamente. Não existe um modelo gemini-3.1-flash "puro". Para transcrição em tempo real, use a Live API (gemini-3.1-flash-live-preview) ou o Google Cloud Speech-to-Text.
    - -

    9.2 Especificações técnicas

    -
    - - - - - - - - - - -
    ParâmetroValor
    Tokens por segundo32 tokens/s
    1 minuto de áudio1.920 tokens
    Duração máxima9,5 horas
    Resolução16 Kbps
    CanaisMulticanal combinado em mono
    Tamanho máximo inline20 MB (total)
    -
    - -

    9.3 Formatos suportados

    -
      -
    • audio/wav, audio/mp3, audio/aiff, audio/aac, audio/ogg, audio/flac, audio/mpeg, audio/m4a, audio/l16, audio/opus, audio/alaw, audio/mulaw.
    • -
    - -

    9.4 Upload via Files API

    -
    from google import genai
    -client = genai.Client()
    -
    -uploaded_file = client.files.upload(file="path/to/sample.mp3")
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "text", "text": "Describe this audio clip"},
    -        {"type": "audio", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
    -    ]
    -)
    -print(interaction.output_text)
    - -

    9.5 Transcrição com diarização e emoção

    -
    response_schema = {
    -    "type": "object",
    -    "properties": {
    -        "summary": {"type": "string"},
    -        "segments": {
    -            "type": "array",
    -            "items": {
    -                "type": "object",
    -                "properties": {
    -                    "speaker": {"type": "string"},
    -                    "timestamp": {"type": "string"},
    -                    "content": {"type": "string"},
    -                    "language": {"type": "string"},
    -                    "emotion": {"type": "string",
    -                                "enum": ["happy", "sad", "angry", "neutral"]}
    -                },
    -                "required": ["speaker", "timestamp", "content", "emotion"]
    -            }
    -        }
    -    }
    -}
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "audio", "uri": uploaded_file.uri, "mime_type": "audio/mp3"},
    -        {"type": "text", "text": "Transcribe with diarization, language, emotion."}
    -    ],
    -    response_format={"type": "text", "mime_type": "application/json",
    -                     "schema": response_schema},
    -)
    -print(interaction.output_text)
    - -

    9.6 Consulta por timestamps

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "text", "text": "Provide a transcript from 02:30 to 03:29."},
    -        {"type": "audio", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
    -    ]
    -)
    - - - -

    9.7 Geração de áudio (TTS)

    -

    A Interactions API também gera áudio a partir de texto. Defina response_modalities=["audio"] e passe generation_config.speech_config; o modelo TTS atual é gemini-3.1-flash-tts-preview (Preview). Estilo, sotaque, ritmo e tom são controláveis por linguagem natural no próprio prompt. O áudio sai em interaction.output_audio.data (base64; PCM 24 kHz, 16-bit, mono).

    -

    Single-speaker — Python

    -
    from google import genai
    -import base64, wave
    -
    -client = genai.Client()
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.1-flash-tts-preview",
    -    input="Say cheerfully: Have a wonderful day!",
    -    response_modalities=["audio"],
    -    generation_config={"speech_config": [{"voice": "Kore"}]},
    -)
    -
    -pcm = base64.b64decode(interaction.output_audio.data)
    -with wave.open("out.wav", "wb") as wf:
    -    wf.setnchannels(1); wf.setsampwidth(2); wf.setframerate(24000)
    -    wf.writeframes(pcm)
    -

    REST

    -
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -H "Api-Revision: 2026-05-20" \
    -  -d '{
    -    "model": "gemini-3.1-flash-tts-preview",
    -    "input": "Say cheerfully: Have a wonderful day!",
    -    "response_modalities": ["audio"],
    -    "generation_config": {"speech_config": [{"voice": "Kore"}]}
    -  }'
    - -

    9.8 Multi-speaker (até 2 locutores)

    -

    Para diálogos, configure um item de speech_config por locutor (máximo 2), cada um com speaker (o nome usado no prompt) e voice.

    -
    prompt = """TTS the following conversation between Joe and Jane:
    -         Joe: How's it going today Jane?
    -         Jane: Not too bad, how about you?"""
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.1-flash-tts-preview",
    -    input=prompt,
    -    response_modalities=["audio"],
    -    generation_config={"speech_config": [
    -        {"speaker": "Joe", "voice": "Kore"},
    -        {"speaker": "Jane", "voice": "Puck"},
    -    ]},
    -)
    -pcm = base64.b64decode(interaction.output_audio.data)
    - -

    9.9 Vozes, idiomas & limites

    -
      -
    • 30 vozes pré-construídas no campo voice — ex.: Zephyr (bright), Puck (upbeat), Charon (informative), Kore (firm), Fenrir (excitable), Leda (youthful), Aoede (breezy), Achird (friendly), Sulafat (warm)… (lista completa na doc oficial).
    • -
    • Idioma automático: o modelo detecta o idioma da entrada; ~70 idiomas suportados (en, pt, es, fr, de, it, hi, ja, ko, ar, cmn…).
    • -
    • Saída: PCM 24 kHz, 16-bit, mono — recuperada via interaction.output_audio.data (base64).
    • -
    -
    Limitações do TTS: entrada somente texto, saída somente áudio; janela de contexto de 32k tokens; não suporta streaming; ocasionalmente o modelo retorna tokens de texto e o servidor falha com 500 (implemente retry automático); prompts vagos podem ser rejeitados (PROHIBITED_CONTENT) — adicione um preâmbulo claro instruindo a sintetizar fala e marque onde começa o texto a ser falado. A qualidade pode degradar após alguns minutos — divida transcrições longas.
    - -
    - -
    -

    10. Compreensão de vídeo

    - -

    10.1 Métodos de entrada

    -
    - - - - - - - - -
    MétodoTamanho máx.Uso
    Files API20 GB (pago) / 2 GB (free)Vídeos > 100 MB, longos (>10 min), reutilizáveis
    Cloud Storage2 GB / arquivo, sem limite totalGrandes, persistentes
    Inline (Base64)< 100 MBCurtos, uso único
    URLs YouTube—Vídeos públicos
    -
    - -

    10.2 Formatos suportados

    -

    video/mp4, video/mpeg, video/mov, video/avi, video/x-flv, video/mpg, video/webm, video/wmv, video/3gpp.

    - -

    10.3 Especificações técnicas

    -
    - - - - - - - - - - -
    AspectoValor
    Janela 1M tokens1 h (resolução padrão) ou 3 h (resolução baixa)
    Amostragem visual1 FPS
    Áudio (Files API)1 Kbps, mono
    Tokens — padrão~300 tokens/s (258 frame + 32 áudio + metadados)
    Tokens — baixa~100 tokens/s (66 frame + 32 áudio + metadados)
    Formato timestampMM:SS
    -
    - -

    10.4 Upload & espera por ACTIVE

    -
    from google import genai
    -import time, base64
    -client = genai.Client()
    -
    -myfile = client.files.upload(file="path/to/sample.mp4")
    -while not myfile.state or myfile.state.name != "ACTIVE":
    -    print("Processing video...")
    -    time.sleep(5)
    -    myfile = client.files.get(name=myfile.name)
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "video", "uri": myfile.uri, "mime_type": myfile.mime_type},
    -        {"type": "text", "text": "Summarize this video. Then create a quiz with key."}
    -    ]
    -)
    -print(interaction.steps[-1].content[0].text)
    - -

    10.5 YouTube URL

    -
    interaction = client.interactions.create(
    -    model='gemini-3.5-flash',
    -    input=[
    -        {"type": "text", "text": "Summarize the video in 3 sentences."},
    -        {"type": "video", "uri": "https://www.youtube.com/watch?v=9hE5-98ZeCg"}
    -    ]
    -)
    -
      -
    • Gratuito: até 8 h/dia.
    • -
    • Pago: sem limite.
    • -
    • Os modelos Gemini 3.x aceitam até 10 vídeos por requisição.
    • -
    • Apenas vídeos públicos.
    • -
    - -

    10.6 Inline (vídeos pequenos)

    -
    video_bytes = open("video.mp4", 'rb').read()
    -interaction = client.interactions.create(
    -    model='gemini-3.5-flash',
    -    input=[
    -        {"type": "text", "text": "Please summarize the video in 3 sentences."},
    -        {"type": "video", "data": base64.b64encode(video_bytes).decode('utf-8'),
    -         "mime_type": "video/mp4"}
    -    ]
    -)
    - -

    10.7 Timestamps e descrição multimodal

    -
    prompt = "Describe key events with audio and visual details. Include timestamps."
    -# ou: "What are the examples given at 00:05 and 00:10 supposed to show us?"
    - -
    - Limitação na Interactions API: o campo video_metadata (intervalos de corte, FPS customizado) presente em generateContent ainda não está disponível em Interactions. -
    - - -
    - -
    -

    11. Processamento de documentos (PDF)

    - -

    11.1 Capacidades

    -

    PDFs são processados com visão nativa: leitura de texto, imagens, diagramas, gráficos, tabelas, preservação de layout. Outros formatos (HTML, Markdown, CSV, etc.) são tratados como texto puro.

    - -

    11.2 Limites técnicos

    -
    - - - - - - - - - - -
    ParâmetroValor
    Tamanho máximo50 MB (inline)
    Páginas máximas1.000
    Tokens por página258
    Resolução máx.3072 × 3072 px
    Resolução mín.768 × 768 px
    Files API retention48 horas
    -
    - -

    11.3 Inline Base64

    -
    import base64
    -with open('path/to/document.pdf', 'rb') as f:
    -    pdf_bytes = f.read()
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "document",
    -         "data": base64.b64encode(pdf_bytes).decode('utf-8'),
    -         "mime_type": "application/pdf"},
    -        {"type": "text", "text": "Summarize this document"}
    -    ]
    -)
    -print(interaction.output_text)
    - -

    11.4 Files API (PDFs grandes)

    -
    import httpx, io
    -doc_io = io.BytesIO(httpx.get("https://arxiv.org/pdf/2312.11805").content)
    -sample_doc = client.files.upload(file=doc_io, config={'mime_type': 'application/pdf'})
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "document", "uri": sample_doc.uri, "mime_type": sample_doc.mime_type},
    -        {"type": "text", "text": "Summarize this document"}
    -    ]
    -)
    - -

    11.5 Múltiplos PDFs

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "document", "uri": sample_pdf_1.uri, "mime_type": "application/pdf"},
    -        {"type": "document", "uri": sample_pdf_2.uri, "mime_type": "application/pdf"},
    -        {"type": "text", "text": "Compare main benchmarks between these papers. Output as table."}
    -    ]
    -)
    - -

    11.6 Gemini 3 — media_resolution & texto nativo

    -
      -
    • media_resolution: unspecified (default), low, medium, high, ultra_high (só por item de conteúdo).
    • -
    • Texto nativo do PDF: agora extraído diretamente e fornecido ao modelo.
    • -
    • Faturamento: tokens de texto nativo não são cobrados; páginas processadas como imagem entram na modalidade IMAGE.
    • -
    • Por item de conteúdo (só Gemini 3): defina resolution dentro de cada bloco image/video/document para misturar resoluções no mesmo request.
    • -
    - -

    Tokens por valor de media_resolution (modelos Gemini 3) — fonte: ai.google.dev/gemini-api/docs/interactions/media-resolution:

    -
    - - - - - - - - - -
    MediaResolutionImagemVídeoPDF
    unspecified (default)112070560
    low28070280 + texto nativo
    medium56070560 + texto nativo
    high11202801120 + texto nativo
    ultra_high2240N/AN/A
    -
    -

    Recomendado: imagens high (1120); PDFs medium (560 — a qualidade satura aí para documentos comuns); vídeo geral low/medium (70/frame, tratados igual); vídeo com texto denso high (280/frame). ultra_high existe só por item de conteúdo e é voltado a Computer Use.

    - - -
    - -
    -

    12. Files API & métodos de entrada

    - -

    12.1 Quando usar cada método

    -
    - - - - - - - - -
    MétodoTamanho máx.PersistênciaIdeal para
    Inline (Base64)100 MB / 50 MB PDFsNenhumaTestes, arquivos pequenos, tempo real
    Files API2 GB / arquivo, 20 GB / projeto48 horasArquivos grandes, reuso
    GCS URI (gs://)2 GB / arquivo, sem limite totalRegistro: acesso por até 30 dias (não armazena; buscado por requisição)Já no Cloud Storage
    URLs externas100 MB / payloadBuscado por requisiçãoDados públicos, S3 pré-assinado, SAS Azure
    -
    - -

    12.2 Upload & uso

    -
    myfile = client.files.upload(file="path/to/sample.mp3")
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        {"type": "audio", "uri": myfile.uri, "mime_type": myfile.mime_type},
    -        {"type": "text", "text": "Describe this audio clip"}
    -    ]
    -)
    - -

    12.3 Listar / obter / excluir

    -
    for f in client.files.list(): print(f.name)
    -client.files.get(name=file_name)
    -client.files.delete(name=file_name)
    - -

    12.4 Registrar arquivos do GCS

    -
    from google.oauth2.service_account import Credentials
    -GCS_READ_SCOPES = [
    -  'https://www.googleapis.com/auth/devstorage.read_only',
    -  'https://www.googleapis.com/auth/cloud-platform'
    -]
    -credentials = Credentials.from_service_account_file('service-account.json',
    -                                                   scopes=GCS_READ_SCOPES)
    -
    -registered = client.files.register_files(
    -    uris=["gs://my_bucket/some_object.pdf"],
    -    auth=credentials
    -)
    -for f in registered.files:
    -    response = client.interactions.create(
    -        model="gemini-3.5-flash",
    -        input=[
    -            {"type": "document", "uri": f.uri, "mime_type": f.mime_type},
    -            {"type": "text", "text": "Summarize this file."}
    -        ]
    -    )
    - -
    - A Interactions API não aceita URLs externas (S3/SAS) como fonte de mídia — use upload inline ou a Files API. Arquivos na Files API expiram em 48 h. PDFs inline têm limite separado de 50 MB. -
    - - -
    - -
    -

    13. Function calling

    - -

    Function calling conecta o modelo a ferramentas/APIs externas. Em vez de produzir só texto, o modelo decide quando emitir uma step function_call com id, name e arguments. Seu app executa a função e devolve o resultado num step function_result.

    - -

    13.1 Esquema da declaração de função

    -
    - - - - - - - - - -
    CampoTipoObrigatórioDescrição
    typestringSimSempre "function" (no nível superior de tools).
    namestringSimsnake_case ou camelCase.
    descriptionstringSimExplicação clara da finalidade.
    parametersobjectSimJSON Schema (subset OpenAPI).
    parameters.requiredstring[]NãoLista de parâmetros obrigatórios.
    -
    - -

    13.2 Fluxo completo (4 etapas)

    -
      -
    1. Definir a declaração
    2. -
    3. Chamar o modelo com tools=[...]
    4. -
    5. Executar a função no cliente (lendo step.name e step.arguments)
    6. -
    7. Enviar function_result referenciando call_id
    8. -
    - -

    13.3 Exemplo — set_light_values

    -

    Python

    -
    set_light_values_declaration = {
    -    "type": "function",
    -    "name": "set_light_values",
    -    "description": "Sets the brightness and color temperature of a light.",
    -    "parameters": {
    -        "type": "object",
    -        "properties": {
    -            "brightness": {"type": "integer", "description": "0–100"},
    -            "color_temp": {"type": "string",
    -                           "enum": ["daylight", "cool", "warm"]},
    -        },
    -        "required": ["brightness", "color_temp"],
    -    },
    -}
    -
    -def set_light_values(brightness, color_temp):
    -    return {"brightness": brightness, "colorTemperature": color_temp}
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Turn the lights down to a romantic level",
    -    tools=[set_light_values_declaration],
    -)
    -
    -fc_step = next(s for s in interaction.steps if s.type == "function_call")
    -result = set_light_values(**fc_step.arguments)
    -
    -final = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[{
    -        "type": "function_result",
    -        "name": fc_step.name,
    -        "call_id": fc_step.id,
    -        "result": [{"type": "text", "text": str(result)}],
    -    }],
    -    tools=[set_light_values_declaration],
    -    previous_interaction_id=interaction.id,
    -)
    -print(final.output_text)
    - -

    JavaScript

    -
    const setLightValuesTool = {
    -  type: 'function',
    -  name: 'set_light_values',
    -  description: 'Sets the brightness and color temperature of a light.',
    -  parameters: {
    -    type: 'object',
    -    properties: {
    -      brightness: { type: 'number' },
    -      color_temp: { type: 'string', enum: ['daylight', 'cool', 'warm'] },
    -    },
    -    required: ['brightness', 'color_temp'],
    -  },
    -};
    -
    -const interaction = await client.interactions.create({
    -  model: 'gemini-3.5-flash',
    -  input: 'Turn the lights down to a romantic level',
    -  tools: [setLightValuesTool],
    -});
    -
    -const fcStep = interaction.steps.find(s => s.type === 'function_call');
    -const result = setLightValues(fcStep.arguments.brightness,
    -                              fcStep.arguments.color_temp);
    -
    -const final = await client.interactions.create({
    -  model: 'gemini-3.5-flash',
    -  input: [{
    -    type: 'function_result',
    -    name: fcStep.name,
    -    call_id: fcStep.id,
    -    result: [{ type: 'text', text: JSON.stringify(result) }]
    -  }],
    -  tools: [setLightValuesTool],
    -  previous_interaction_id: interaction.id,
    -});
    -console.log(final.output_text);
    - -

    13.4 Modos de tool_choice

    -
    - - - - - - - - -
    ModoComportamento
    auto (padrão)Modelo decide se chama função ou responde direto.
    anyModelo é forçado a chamar alguma função.
    noneModelo não pode chamar funções.
    validated (preview)Garante aderência ao schema.
    -
    -
    generation_config = {
    -    "tool_choice": {
    -        "allowed_tools": {
    -            "mode": "any",
    -            "tools": ["get_current_temperature"]
    -        }
    -    }
    -}
    - -

    13.5 Chamadas paralelas

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Turn this place into a party!",
    -    tools=[power_disco_ball, start_music, dim_lights],
    -    generation_config={"tool_choice": "any"},
    -)
    -for step in interaction.steps:
    -    if step.type == "function_call":
    -        print(f"{step.name}({step.arguments})")
    - -

    13.6 Chamadas composicionais

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="If it's warmer than 20°C in London, set the thermostat to 20°C, otherwise 18°C.",
    -    tools=[get_weather_forecast_declaration,
    -           set_thermostat_temperature_declaration],
    -)
    - -

    13.7 Function result multimodal (Gemini 3)

    -
    base64_image_data = base64.b64encode(image_bytes).decode("utf-8")
    -final = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    previous_interaction_id=interaction.id,
    -    input=[{
    -        "type": "function_result",
    -        "name": tool_call.name,
    -        "call_id": tool_call.id,
    -        "result": [
    -            {"type": "text",  "text": "instrument.jpg"},
    -            {"type": "image", "mime_type": "image/jpeg", "data": base64_image_data},
    -        ],
    -    }],
    -)
    - -

    13.8 MCP Server tools (HTTP Streaming)

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Check the status of my last server deployment.",
    -    tools=[{
    -        "type": "mcp_server",
    -        "name": "deployment_tracker",
    -        "url": "https://mcp.example.com/mcp",
    -        "headers": {"Authorization": "Bearer my-token"},
    -    }]
    -)
    -
    - Restrições do MCP remoto: apenas HTTP streaming (não SSE). Gemini 3 ainda não suporta MCP remoto. Nomes de servidor não podem conter - (use snake_case). -
    - -

    13.9 Streaming de function calling — acumular arguments_delta

    -
    stream = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="What is the weather in Paris?",
    -    tools=[weather_tool],
    -    stream=True
    -)
    -current_calls = {}
    -for event in stream:
    -    if event.event_type == "step.start" and event.step.type == "function_call":
    -        current_calls[event.index] = {"id": event.step.id, "name": event.step.name, "arguments": ""}
    -    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
    -        current_calls[event.index]["arguments"] += event.delta.arguments
    - -

    13.10 Limitações

    -
      -
    • Apenas subset OpenAPI suportado para parameters.
    • -
    • Em modo any, esquemas muito grandes podem ser rejeitados.
    • -
    • Recomendação: manter ≤ 10–20 ferramentas ativas.
    • -
    • Gemini 3 ainda não suporta MCP remoto.
    • -
    - - -
    - -
    -

    14. Saída estruturada

    - -

    Configure response_format com type: "text", mime_type: "application/json" e um schema (JSON Schema, Pydantic ou Zod) para forçar resposta estruturada.

    - -

    14.1 Exemplo — extrator de receitas

    -

    Python (Pydantic)

    -
    from pydantic import BaseModel, Field
    -from typing import List, Optional
    -
    -class Ingredient(BaseModel):
    -    name: str = Field(description="Name of the ingredient.")
    -    quantity: str = Field(description="Quantity with units.")
    -
    -class Recipe(BaseModel):
    -    recipe_name: str
    -    prep_time_minutes: Optional[int]
    -    ingredients: List[Ingredient]
    -    instructions: List[str]
    -
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Extract this recipe: ...",
    -    response_format={
    -        "type": "text",
    -        "mime_type": "application/json",
    -        "schema": Recipe.model_json_schema()
    -    },
    -)
    -recipe = Recipe.model_validate_json(interaction.output_text)
    - -

    JavaScript (Zod)

    -
    import * as z from "zod";
    -
    -const recipeJsonSchema = {
    -  type: "object",
    -  properties: {
    -    recipe_name: { type: "string" },
    -    ingredients: {
    -      type: "array",
    -      items: { type: "object", properties: {
    -        name: { type: "string" },
    -        quantity: { type: "string" }
    -      }, required: ["name", "quantity"] }
    -    },
    -    instructions: { type: "array", items: { type: "string" } }
    -  },
    -  required: ["recipe_name", "ingredients", "instructions"]
    -};
    -
    -const interaction = await ai.interactions.create({
    -  model: "gemini-3.5-flash",
    -  input: "Extract this recipe: ...",
    -  response_format: {
    -    type: 'text',
    -    mime_type: 'application/json',
    -    schema: recipeJsonSchema
    -  },
    -});
    -const recipeSchema = z.fromJSONSchema(recipeJsonSchema);
    -const recipe = recipeSchema.parse(JSON.parse(interaction.output_text));
    - -

    14.2 Streaming de saída estruturada

    -
    stream = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="The new UI is intuitive. Long summary please!",
    -    response_format={"type": "text", "mime_type": "application/json",
    -                     "schema": Feedback.model_json_schema()},
    -    stream=True
    -)
    -for event in stream:
    -    if event.event_type == "step.delta" and event.delta.text:
    -        print(event.delta.text, end="")
    - -

    14.3 Saída estruturada + ferramentas (Preview · Gemini 3)

    -
    interaction = client.interactions.create(
    -    model="gemini-3.1-pro-preview",
    -    input="Search for all details for the latest Euro.",
    -    tools=[{"type": "google_search"}, {"type": "url_context"}],
    -    response_format={
    -        "type": "text",
    -        "mime_type": "application/json",
    -        "schema": MatchResult.model_json_schema()
    -    },
    -)
    -

    Ferramentas compatíveis: google_search, url_context, code_execution, file_search e function calling. Apenas modelos Gemini 3.

    - -

    14.4 Tipos JSON Schema aceitos

    -
      -
    • string, number, integer, boolean, object, array.
    • -
    • Nullable: {"type": ["string", "null"]}.
    • -
    • enum, format (date-time, date, time) em strings.
    • -
    • minimum, maximum em números.
    • -
    • items, prefixItems, minItems, maxItems em arrays.
    • -
    • properties, required, additionalProperties em objetos.
    • -
    - - -
    - -
    -

    15. Thinking & assinaturas de pensamento

    - -

    Os modelos Gemini 3.x usam raciocínio em múltiplas etapas, expostos como steps thought em interaction.steps. Cada step contém signature (representação criptografada do estado interno) e opcionalmente summary (resumo em texto/imagem).

    - -

    15.1 Modelos & níveis de thinking

    -
    - - - - - - - - -
    ModeloThinking padrãoNíveis
    gemini-3.1-pro-previewAtivado (alto)low, medium, high
    gemini-3-flash-previewAtivado (alto)low, medium, high
    gemini-3.5-flashAtivado (médio, padrão)minimal, low, medium, high
    gemini-3.1-flash-liteminimal (padrão)minimal, low, medium, high
    -
    -

    O minimal não garante que o thinking esteja desligado; gemini-3.5-flash e gemini-3.1-flash-lite não suportam thinking-off completo (verificado 2026-06-03 na doc de thinking).

    - -

    15.2 Controlar nível

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Provide a list of 3 famous physicists and their key contributions",
    -    generation_config={"thinking_level": "low"}
    -)
    - -

    15.3 Resumos de pensamento (thinking_summaries)

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="What is the sum of the first 50 prime numbers?",
    -    generation_config={"thinking_summaries": "auto"}
    -)
    -for step in interaction.steps:
    -    if step.type == "thought":
    -        for block in step.summary or []:
    -            if block.type == "text":
    -                print("Thought:", block.text)
    -    elif step.type == "model_output":
    -        for block in step.content:
    -            if block.type == "text":
    -                print("Answer:", block.text)
    - -

    15.4 Streaming com raciocínio (dois tipos de delta)

    -
    - - - - - - -
    delta.typeCargaQuando
    thought_summarycontent (texto/imagem)Resumos incrementais.
    thought_signaturesignatureÚltimo delta antes de step.stop.
    -
    -
    stream = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Alice, Bob, Carol live in red/green/blue houses. ...",
    -    generation_config={"thinking_summaries": "auto"},
    -    stream=True
    -)
    -for event in stream:
    -    if event.event_type == "step.delta":
    -        if event.delta.type == "thought_summary":
    -            print(f"[Thought] {event.delta.content.text}", end="")
    -        elif event.delta.type == "text":
    -            print(event.delta.text, end="")
    - -

    15.5 Assinaturas de pensamento (signature)

    -

    São representações criptografadas do estado de raciocínio interno. Regra: se você receber uma assinatura em uma resposta, transmita-a exatamente como recebida ao enviar o histórico na próxima chamada. Em Gemini 3 isso é obrigatório em chamadas de função — omissão gera erro 400.

    - -
    - - - - - - -
    ModoComportamento
    store=true (server-side)SDK e servidor gerenciam assinaturas automaticamente. Nenhuma ação manual.
    store=false (stateless)Você precisa reenviar todos os blocos thought com signature exatamente como recebidos. Mudar ou pular = erro 400 em FC.
    -
    - -

    15.6 Preço & tokens de raciocínio

    -

    Custo = tokens de saída + tokens de raciocínio. O campo interaction.usage.total_thought_tokens expõe o total gerado. Apenas o resumo é exposto ao desenvolvedor — o conteúdo completo de raciocínio fica interno.

    - -

    15.7 Recomendações de nível

    -
    - - - - - - - -
    CenárioNível
    Fatos diretos, classificação trivialminimal
    Comparações, raciocínio criativoPadrão (medium)
    Programação avançada, matemática difícil, AIMEhigh
    -
    - - -
    - -
    -

    16. Caching (implícito)

    - -

    A Interactions API suporta apenas cache implícito. Cache explícito (criação manual de objetos de cache) não está disponível na Interactions; para isso continue usando generateContent com client.caches.create(...).

    - -

    16.1 Como funciona

    -
      -
    • Ativado por padrão nos modelos Gemini 3.x.
    • -
    • Economia de custo aplicada automaticamente em cache hits.
    • -
    • Reutilização via previous_interaction_id dispara o cache.
    • -
    - -

    16.2 Limites mínimos por modelo

    -
    - - - - - - - -
    ModeloTokens mínimos para cache
    Gemini 3.5 Flash1024
    Gemini 3.1 Flash-Lite1024
    Gemini 3.1 Pro Preview4096
    -

    Fonte oficial (caching, 2026-06-03): a tabela publicada lista os mínimos por nome de preview — Gemini 3 Flash Preview = 1024, Gemini 3 Pro Preview = 4096, Gemini 2.5 Flash = 1024, Gemini 2.5 Pro = 4096. O mínimo por ID GA não é publicado (o gemini-3.1-flash-lite não tem linha própria); os valores acima seguem o padrão por tier (Flash = 1024, Pro = 4096). [UNVERIFIED: mapeamento exato por ID GA]

    -
    - -

    16.3 Maximizar cache hits

    -
      -
    • Coloque grandes conteúdos comuns no início do prompt.
    • -
    • Envie requisições com prefixos semelhantes em curto intervalo.
    • -
    • Use previous_interaction_id para reutilizar histórico.
    • -
    - -

    16.4 Verificar tokens em cache

    -

    Disponível em interaction.usage.total_cached_tokens (na Interactions API o objeto é usage; usage_metadata/usageMetadata é a nomenclatura do generateContent).

    - - -
    - -
    -

    17. Ferramentas server-side

    - -

    Além de function calling (cliente), a Interactions API integra diversas ferramentas executadas pelo servidor do Google. Habilite com tools=[{"type": "<tool_name>"}] e elas aparecem como steps na timeline.

    - -

    17.1 Catálogo de ferramentas server-side

    -
    - - - - - - - - - - - -
    TooltypeCasos de uso
    Google Searchgoogle_searchEventos atuais, verificação de fatos, citações
    Google Mapsgoogle_mapsAssistentes com localização, itinerários, lugares
    Code Executioncode_executionCálculos precisos em Python sandbox
    URL Contexturl_contextLeitura/comparação de páginas/PDFs/JSON
    Computer Use (preview)computer_useAgentes que veem tela e clicam
    File Searchfile_searchRAG sobre file_search_stores
    MCP Servermcp_serverFerramentas externas via HTTP streaming
    -
    -
    - - - -
    -

    17.2 Google Maps (grounding)

    - -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="What are the best Italian restaurants within a 15-minute walk from here?",
    -    tools=[{
    -        "type": "google_maps",
    -        "enable_widget": True,
    -        "latitude": 34.050481,
    -        "longitude": -118.248526
    -    }]
    -)
    -for step in interaction.steps:
    -    if step.type == "google_maps_result":
    -        for place in step.result.places:
    -            print(f"- {place.name} ({place.url})")
    -        if step.result.widget_context_token:
    -            print(f"<gmp-place-contextual context-token='{step.result.widget_context_token}'></gmp-place-contextual>")
    - -

    Preços & cota

    -
      -
    • Preço: US$ 25 / 1.000 prompts fundamentados.
    • -
    • Nível gratuito: 500 requisições/dia.
    • -
    • Cobrado apenas quando retorna ≥ 1 lugar.
    • -
    - - -
    - -
    -

    17.3 Code Execution

    - -

    O modelo gera e executa Python em sandbox seguro. Steps code_execution_call trazem o código, e code_execution_result traz a saída.

    - -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="What is the sum of the first 50 prime numbers? Generate and run code.",
    -    tools=[{"type": "code_execution"}],
    -)
    -for step in interaction.steps:
    -    if step.type == "code_execution_call":
    -        print("CODE:\n", step.arguments.code)
    -    elif step.type == "code_execution_result":
    -        print("OUTPUT:", step.result)
    - -

    Limites

    -
      -
    • Tempo máximo de execução: 30 s.
    • -
    • Entrada máxima: ~1 M tokens (~2 MB texto).
    • -
    • Até 5 retentativas em erro.
    • -
    • Sandbox apenas com bibliotecas pré-instaladas; não é possível instalar próprias.
    • -
    • Apenas gráficos gerados com matplotlib são renderizados como imagem inline no resultado.
    • -
    - -

    Bibliotecas disponíveis (extrato)

    -

    matplotlib, numpy, pandas, scipy, scikit-learn, tensorflow, sympy, pillow, opencv-python, geopandas, pyPDF2, python-docx, python-pptx, openpyxl, xlrd, reportlab, fpdf, pylatex, jinja2, seaborn, chess, imageio, tabulate, jsonschema, ...

    - -
    Superfície (Developer API vs Vertex): como toda a Interactions API, este code_execution é documentado e exemplificado na Developer API. Na Vertex / Gemini Enterprise Agent Platform o CodeExecution consta apenas no schema (sem exemplo prático) e a execução de código é documentada via generateContent; em teste, code_execution via Interactions não funcionou sob auth Vertex. Em Vertex, use generateContent + code_execution. Detalhes no guia de code tools. (2026-06-19)
    - - -
    - -
    -

    17.4 URL Context

    - -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Compare ingredients of these recipes: https://... and https://...",
    -    tools=[{"type": "url_context"}]
    -)
    -for step in interaction.steps:
    -    if step.type == "url_context_result":
    -        print(step.result.url, "→", step.result.status)
    - -

    Limites & aceitação

    -
      -
    • Até 20 URLs por requisição.
    • -
    • Até 34 MB por URL.
    • -
    • Aceita PDF, HTML, JSON, CSS, JS, CSV, RTF, PNG/JPEG/BMP/WebP.
    • -
    • Não aceita: paywalls, vídeos do YouTube, Google Workspace, áudio/vídeo, localhost/redes privadas/ngrok/pinggy.
    • -
    - -

    Status (url_retrieval_status)

    -

    URL_RETRIEVAL_STATUS_SUCCESS, URL_RETRIEVAL_STATUS_UNSAFE.

    - - -
    - -
    -

    17.5 Computer Use (preview)

    - -

    Agentes que "veem" tela via screenshots e "agem" via ações de UI (cliques, digitação, scroll). Modelos suportados (usar outro modelo gera erro):

    -
      -
    • gemini-3-flash-preview — suporte nativo a Computer Use (não precisa de modelo separado para acessar a ferramenta).
    • -
    • gemini-2.5-computer-use-preview-10-2025 — modelo dedicado de Computer Use.
    • -
    -
    gemini-3.5-flash ainda não suporta Computer Use; use gemini-3-flash-preview (mais recente com suporte nativo).
    - -

    Ações disponíveis (resumo)

    -

    open_web_browser, navigate(url), click_at(x,y), type_text_at(x,y,text,press_enter), hover_at, scroll_at, scroll_document(direction), drag_and_drop, key_combination(keys), go_back, go_forward, wait_5_seconds, search.

    -
    - Coordenadas em escala 0–999; converta para pixels reais antes de executar. -
    - -

    Habilitar (Interactions API)

    -
    interaction = client.interactions.create(
    -    model="gemini-3-flash-preview",  # suporte nativo a Computer Use
    -    input="Find a flight to Tokyo",
    -    tools=[{
    -        "type": "computer_use",
    -        "environment": "browser",
    -        "excluded_predefined_functions": ["drag_and_drop"],
    -    }],
    -)
    - -

    Segurança

    -
      -
    • Algumas respostas trazem safety_decision: require_confirmation — implemente HITL.
    • -
    • Use sandbox (VM/Docker), allowlist de URLs e logs detalhados.
    • -
    • Não use para decisões críticas sem supervisão humana.
    • -
    - - -
    - - - -
    -

    17.7 MCP Server tools

    - -

    Conecte agentes a servidores MCP externos via HTTP streaming.

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Check status of latest deploy",
    -    tools=[{
    -        "type": "mcp_server",
    -        "name": "deployment_tracker",
    -        "url": "https://mcp.example.com/mcp",
    -        "headers": {"Authorization": "Bearer token"},
    -        "allowed_tools": {"mode": "auto", "tools": ["check_deploy"]}
    -    }]
    -)
    -
    - Restrições: apenas HTTP streaming (não SSE). Gemini 3 ainda não suporta MCP remoto. Nomes não podem conter -. -
    -
    - -
    -

    17.8 Combinando ferramentas (Preview · Gemini 3)

    - -
    -

    ✅ Sim: Gemini 3.x combina built-in tools + function calling no mesmo turno. Não é workaround — é uma feature Preview oficial da série Gemini 3, baseada em tool context circulation. O modelo pode, por exemplo, se ancorar em dados frescos da web (Google Search) antes de chamar a sua lógica de negócio (custom function) em uma única geração. Funciona tanto em client.models.generate_content(...) quanto aqui na Interactions API. [doc]

    -
    - -

    Como ligar: declare os built-in tools junto com as custom functions e ligue o flag include_server_side_tool_invocations=true. A cada turno, devolva todos os parts retornados (id, tool_type, thought_signature) exatamente como recebidos — omitir o thought_signature faz o modelo dar erro. O combo opera em modo VALIDATED (o AUTO não é suportado com o flag ligado).

    - -
    # Forma generate_content (clássica) — built-in (google_search) + custom (getWeather) no mesmo turno
    -from google import genai
    -from google.genai import types
    -
    -client = genai.Client()
    -getWeather = {
    -    "name": "getWeather",
    -    "description": "Gets the weather for a requested city.",
    -    "parameters": {"type": "object",
    -                   "properties": {"city": {"type": "string"}},
    -                   "required": ["city"]},
    -}
    -response = client.models.generate_content(
    -    model="gemini-3-flash-preview",
    -    contents="Qual a cidade mais ao norte dos EUA? Como está o tempo lá hoje?",
    -    config=types.GenerateContentConfig(
    -        tools=[types.Tool(
    -            google_search=types.ToolGoogleSearch(),   # built-in (server-side)
    -            function_declarations=[getWeather],        # custom (client-side)
    -        )],
    -        include_server_side_tool_invocations=True,     # liga a circulação de contexto
    -    ),
    -)
    -# A resposta traz toolCall/toolResponse (built-in) + functionCall (custom) para você executar.
    -# No próximo turno reenvie TODOS os parts (com thought_signature) + o functionResponse com o mesmo id.
    - -
    Na Interactions API: declare as tools como dicts ({"type":"google_search"}, {"type":"code_execution"}, …) ao lado das suas function tools; a circulação de contexto e o thought_signature são carregados automaticamente entre turnos quando você encadeia via previous_interaction_id. Para o caso vision-grounded (Code Execution + imagem), veja 17.9 Agentic Vision. Endpoint dedicado para bash + custom tools: gemini-3.1-pro-preview-customtools.
    - -

    Matriz de compatibilidade

    -
    - - - - - - - - - - - -
    FerramentaLadoSuporte à circulação de contexto
    Google SearchServidorSim
    Google MapsServidorSim
    URL ContextServidorSim
    File SearchServidorSim
    Code ExecutionServidorSim (executableCode+codeExecutionResult)
    Computer UseClienteSim (functionCall/functionResponse)
    Funções personalizadasClienteSim
    -
    - - -
    - -
    -

    17.9 Agentic Vision com gemini-3.5-flash (Code Execution + imagem)

    - -
    -

    ✅ Oficialmente suportado em Gemini 3 Flash. O modelo escreve e executa Python sobre a própria imagem (crop, zoom, threshold, edge detection, contagem, anotação) em vez de "chutar olhando o thumbnail". A doc oficial chama isso de Code Execution with images e lista três usos: zoom & inspect (detecta detalhe pequeno e re-examina em alta resolução), visual math (cálculo multi-passo por código) e image annotation (desenha setas/caixas para responder). Ativa-se habilitando Code Execution + Thinking. [doc]

    -

    ✅ Já funciona com gemini-3.5-flash — e pela Interactions API. Validamos este contrato em produção: agentic vision (Code Execution sobre a própria imagem) roda com gemini-3.5-flash via client.interactions.create — testado e funcionando, multi-turn inclusive. A doc oficial demonstra o recurso pelo generate_content; aqui é a mesma capacidade exposta pela Interactions API.

    -
    - -
    -

    ⚠️ Escopo do recurso — família Flash. (A capacidade já está confirmada com gemini-3.5-flash pela Interactions API, acima; aqui é só a delimitação de escopo.)

    -
      -
    • É um recurso da família Flash — não dos modelos Pro. A doc oficial documenta Code Execution with images apenas na linha Gemini 3 Flash; os exemplos oficiais usam o ID gemini-3-flash-preview.
    • -
    • Este guia usa gemini-3.5-flash — escolha validada por teste, não inferência. Rodamos o contrato com code_execution + thinking_level (testado até high) em benchmark de produção (n=198 derma 128 px; ~$0,005/caso em medium; p50 ~6 s) e funcionou. O gemini-3-flash-preview é apenas o ID dos exemplos da doc; o gemini-3.5-flash é o Flash estável atual da mesma família.
    • -
    -

    Reverificado na fonte oficial em 2026-06-04.

    -
    - -

    Diferenças entre as APIs (este guia × exemplo oficial)

    -
    -

    Atenção ao copiar código. A doc oficial demonstra Code Execution with images via client.models.generate_content; este guia usa a Interactions API (client.interactions.create), que tem nomes de campo e envelope diferentes. O recurso e o comportamento são os mesmos — muda só o formato da requisição/resposta.

    -
    -
    - - - - - - - - - - - - -
    Aspectogenerate_content (doc oficial)interactions.create (este guia)
    Modelo dos exemplosgemini-3-flash-previewgemini-3.5-flash (validado por teste)
    Imagem na entradacontents=[Part.from_bytes(data, mime_type), "prompt"]input=[{"type":"image","data":b64,"mime_type":…}, …]
    Resolução da imagemmedia_resolution = enum MEDIA_RESOLUTION_* (per-part é v1alpha/experimental)campo resolution no bloco de imagem (standard/high/ultra_high)
    Ativar Code Executionconfig.tools=[Tool(code_execution=ToolCodeExecution)]tools=[{"type":"code_execution"}]
    Thinkinghabilitar Thinking no configgeneration_config={"thinking_level":"minimal|low|medium|high"}
    Saída estruturada (JSON)response_mime_type="application/json" + response_schemaresponse_format={"type":"text","mime_type":"application/json","schema":…}
    Multi-turn / estadoclient.chats (history) ou reenviar id+thought_signature manualmente (REST)previous_interaction_id (o SDK reidrata a signature)
    Imagem anotada (saída)part.as_image().image_bytes nos partsresp.output_image.data
    Trace do códigopart.executable_code / part.code_execution_resultresp.steps (ModelOutputStep / code_execution_call)
    - -

    Esta seção descreve o contrato de agentic vision usado para delegar uma investigação visual a gemini-3.5-flash via client.interactions.create. A ideia central: Code Execution é o instrumento de medição do modelo, e a Interactions API dá memória multi-turn (raciocínio + traços de tool + thought_signature) através de previous_interaction_id.

    - -

    O loop, em uma figura

    -
    Orquestrador                                   gemini-3.5-flash
    -   │  turn 1: payload + imagem + prompt            │
    -   ├───────────────────────────────────────────────►│ THINK  (planeja a hipótese e a região)
    -   │                                                 │ ACT    ──► code_execution (crop/zoom/threshold/medir)
    -   │                                                 │ OBSERVE ◄── lê o crop transformado; itera se preciso
    -   │                                                 │ FINAL: plt.show(imagem anotada)
    -   │  {analysis, findings, measurements, boxes[]}    │
    -   │  + annotated_png (emitido pelo modelo)          │
    -   │  + interaction_id (para o próximo turno)        │
    -   │◄───────────────────────────────────────────────┤
    -   │  turn 2 (opcional): MESMOS bytes (audita SHA256!)│
    -   │            + previous_interaction_id + nova pergunta
    -   ├───────────────────────────────────────────────►│ retoma com thinking_signature + contexto de code_execution
    - -

    Invariantes obrigatórias (todo turno, sem exceção)

    -
      -
    1. A imagem vai em TODO turno. previous_interaction_id carrega raciocínio + assinatura + traços de tool, não os bytes da imagem. Reenvie os bytes e audite por sha256(png)[:16].
    2. -
    3. Assinatura de pensamento preservada verbatim. Ela é opaca e vive dentro dos step/content blocks da interaction — não há acessor top-level resp.thinking_signature no SDK google-genai atual. O SDK reidrata sozinho quando você define previous_interaction_id = resp.id; nunca reconstrua nem injete a assinatura à mão.
    4. -
    5. Schema fixo = AGENTIC_SCHEMA (abaixo), com additionalProperties: false e os quatro campos sempre exigidos.
    6. -
    7. Tool list = exatamente [{"type":"code_execution"}] no turno de vision. Quer multi-tool? Embrulhe o flash dentro de um agente maior que roda seu próprio loop e delega só a visão.
    8. -
    9. Trust framing no system prompt (o modelo é a fonte de verdade; o código é o instrumento). Autonomy framing ("decida se usa a tool") degradou calibração ~8,9 pp nos experimentos.
    10. -
    - -

    System prompt (trust framing — núcleo)

    -
    Você é o especialista de AGENTIC-VISION. Você É a fonte de verdade sobre esta
    -imagem — o orquestrador confia na sua leitura. O code execution é o SEU
    -INSTRUMENTO para fundamentar essa leitura; use-o liberalmente em vez de chutar
    -a partir de um thumbnail.
    -
    -Opere em um loop explícito THINK → ACT → OBSERVE:
    -  • THINK   — em 1–3 frases, planeje qual região e qual medida resolvem a questão.
    -  • ACT     — carregue a imagem e rode código: crop/zoom; realce de contraste
    -              (CLAHE/equalização); threshold (HSV costuma ser mais estável que RGB);
    -              edge detection (Canny/Sobel) ou blob analysis. DESCARREGUE qualquer
    -              contagem/área/distância para o Python. NÃO meça "no olho".
    -  • OBSERVE — leia o crop transformado; se não for decisivo, itere outro passo.
    -
    -PASSO FINAL — OBRIGATÓRIO: como última chamada de código, DESENHE sua(s) caixa(s)
    -e rótulo(s) sobre a imagem (cv2.rectangle / patches.Rectangle) e exiba com
    -plt.imshow(...); plt.show() para capturar a imagem anotada — é a sua trilha de auditoria.
    -
    -DISCIPLINA DE SAÍDA: preencha apenas analysis, findings_summary, measurements e
    -boxes (coordenadas em pixels da imagem ORIGINAL). Não emita diagnóstico final fora
    -do schema — o diagnóstico é responsabilidade do agente principal.
    - -

    Chamada (Interactions API)

    -
    import hashlib, base64, json
    -from google import genai
    -client = genai.Client()
    -
    -def sha16(b): return hashlib.sha256(b).hexdigest()[:16]
    -
    -def consult_flash(*, png_bytes, expected_hash, prompt, prior_id=None,
    -                  thinking_level="medium"):
    -    assert sha16(png_bytes) == expected_hash, "image drift antes do envio"
    -    payload = dict(
    -        model="gemini-3.5-flash",
    -        generation_config={"thinking_level": thinking_level},  # minimal|low|medium|high
    -        input=[
    -            {"type": "text",  "text": "Fonte da modalidade / caption"},
    -            {"type": "image", "data": base64.b64encode(png_bytes).decode(),
    -                              "mime_type": "image/png",
    -                              "resolution": "ultra_high"},     # crítico p/ lesão pequena
    -            {"type": "text",  "text": prompt},
    -        ],
    -        tools=[{"type": "code_execution"}],                    # SÓ isto no turno de vision
    -        response_format={"type": "text", "mime_type": "application/json",
    -                         "schema": AGENTIC_SCHEMA},
    -    )
    -    if prior_id:
    -        payload["previous_interaction_id"] = prior_id          # única diferença no multi-turn
    -    resp = client.interactions.create(**payload)
    -    parsed  = json.loads(resp.output_text) if resp.output_text else {}
    -    steps   = [type(s).__name__ for s in (resp.steps or [])]
    -    code_n  = sum(1 for s in steps if "CodeExecutionCall" in s)
    -    out_img = getattr(getattr(resp, "output_image", None), "data", None)
    -    return {
    -        "interaction_id": resp.id,
    -        "analysis": parsed.get("analysis", ""),
    -        "findings_summary": parsed.get("findings_summary", ""),
    -        "measurements": parsed.get("measurements", "none"),
    -        "boxes": parsed.get("boxes", []),
    -        "n_code_calls": code_n,
    -        "used_agentic": code_n > 0,        # 0 chamadas = modelo "fugiu" da tool
    -        "annotated_b64": out_img,          # PNG anotado emitido pelo próprio modelo
    -        "image_hash": expected_hash,
    -    }
    - -

    Schema autoritativo

    -
    AGENTIC_SCHEMA = {
    -    "type": "object",
    -    "properties": {
    -        "analysis":         {"type": "string"},
    -        "findings_summary": {"type": "string"},
    -        "measurements":     {"type": "string"},   # números concretos ou "none"
    -        "boxes": {
    -            "type": "array",
    -            "items": {
    -                "type": "object",
    -                "properties": {
    -                    "x0": {"type": "integer"}, "y0": {"type": "integer"},
    -                    "x1": {"type": "integer"}, "y1": {"type": "integer"},
    -                    "label": {"type": "string"},
    -                },
    -                "required": ["x0", "y0", "x1", "y1", "label"],
    -                "additionalProperties": False,
    -            },
    -        },
    -    },
    -    "required": ["analysis", "findings_summary", "measurements", "boxes"],
    -    "additionalProperties": False,
    -}
    -

    boxes em pixels da imagem original (nunca normalizados). measurements é string (conjunto aberto: área px², razão de assimetria, diâmetro mm…). additionalProperties: false em todo lugar — sem isso o flash inventa campos que o orquestrador descarta em silêncio.

    - -

    Multi-turn: o que você NÃO faz numa continuação

    -
      -
    1. Não remova a imagem do novo turno — mesmo com previous_interaction_id, os bytes precisam estar no payload.
    2. -
    3. Não reconstrua o system prompt inteiro num mega-prompt; envie só a instrução incremental — o contexto anterior vem pelo id.
    4. -
    5. Não levante/re-injete a "thinking signature" manualmente; setar previous_interaction_id = resp.id é o mecanismo suportado.
    6. -
    -

    Encadeie (previous_interaction_id) para aprofundar na MESMA imagem; comece do zero para outra imagem ou quando a pergunta muda de eixo (continuação serve para deepening, não para redirecionar). Se sha256 diverge entre turnos, aborte — é bug de drift de ground-truth.

    - -

    Tuning

    -
    - - - - - - -
    thinking_levelQuando
    minimal / lowTriagem em volume, passes de sanidade, consultas de rotina.
    mediumDefault para vision diagnóstico. medium → high não deu ganho de acurácia detectável no benchmark, mas ~80% mais caro.
    highCasos difíceis (lesão pequena, camadas OCT ambíguas); raramente necessário.
    -

    resolution: "ultra_high" é não-negociável para imagens diagnósticas ≤ 512 px (dermoscopia etc.); o default subamostra e perde o gradiente que dirige a decisão. Distribuição empírica: mediana de 3 passos de código por caso; se o flash emite < 2 chamadas de rotina, suba o thinking_level ou torne o THINK obrigatório no prompt.

    -

    Campo na Interactions API: a resolução vai no próprio bloco de imagem do input, no campo resolution (string). Valores validados em produção:

    -
    - - - - - - -
    resolutionQuando usar
    standardImagens macroscópicas grandes (ex.: raio-X de tórax).
    highOCT, ultrassom.
    ultra_highDermoscopia e qualquer imagem ≤ 512 px (preserva o gradiente de pigmentação que o default subamostra).
    -

    Equivalência no generate_content: o parâmetro é media_resolution com o enum MEDIA_RESOLUTION_{LOW,MEDIUM,HIGH,ULTRA_HIGH}. O ULTRA_HIGH é per-part, experimental (v1alpha), ~2240 tokens/imagem; a doc oficial recomenda HIGH para a maioria dos casos e ULTRA_HIGH só quando o teste mostra ganho claro sobre HIGH (ex.: computer use ou detalhe diagnóstico minúsculo). [doc]

    - -

    Anti-padrões (não faça)

    -
      -
    • Adicionar google_search ao turno de vision. Misturar busca introduz confound (regressão de ~10 pp medida em gemini-3.5-flash em derma). Mantenha o turno de visão só visão; busca é outra tool, orquestrada à parte.
    • -
    • Re-renderizar as boxes quando output_image existe — o PNG anotado pelo próprio modelo é melhor que o render por coordenadas (ele "viu" as medidas do código).
    • -
    • Pedir veredito diagnóstico final ao flash. Ele é instrumento de visão; o diagnóstico é do agente principal. Misturar os papéis infla a confiança dele nas próprias caixas.
    • -
    • Usar gemini-3.1-flash-image para isto — essa variante é de geração de imagem, não de raciocínio vision-grounded. Use o gemini-3.5-flash normal.
    • -
    • Reaproveitar previous_interaction_id entre imagens diferentes "para economizar tokens" — o flash conflaciona os casos. Imagem nova = interaction nova.
    • -
    - -
    -

    Leitura honesta do ganho. No benchmark de referência (n=198, derma 128px), o ganho marginal de agentic vision em cima do trust framing é quase-zero: a melhora observada vem do framing, não da tool. Trate agentic vision como instrumento de explicabilidade/auditoria (caixas + medidas que mostram por que o modelo decidiu), não como alavanca de acurácia por si só. Detecte "tool-dodge": n_code_calls == 0 + boxes == [] + measurements == "none" ⇒ rebaixe a contribuição do flash, não trate como negativo confiante.

    -
    - - -
    - -
    -

    18. Agentes: Deep Research & Antigravity

    - -

    A Interactions API expõe agentes gerenciados via parâmetro agent (no lugar de model): os agentes Deep Research (§18.1–18.8), o agente de propósito geral Antigravity (§18.9) e agentes custom construídos sobre ele — todos executando server-side. Deep Research é um agente assíncrono que pesquisa, planeja, lê, sintetiza e produz relatórios longos. Disponível apenas via Interactions API.

    - -

    18.1 Agentes Deep Research

    -
    - - - - - - -
    IdentificadorDescrição
    deep-research-preview-04-2026Deep Research — planeja e executa pesquisa multi-etapa com relatórios citados
    deep-research-max-preview-04-2026Deep Research Max — máxima abrangência de coleta e síntese entre centenas de fontes
    -
    - -

    18.2 Como invocar

    -
    import time
    -interaction = client.interactions.create(
    -    input="Research the history of Google TPUs.",
    -    agent="deep-research-preview-04-2026",
    -    background=True,
    -)
    -
    -while True:
    -    interaction = client.interactions.get(interaction.id)
    -    if interaction.status == "completed":
    -        print(interaction.output_text); break
    -    elif interaction.status == "failed":
    -        print("Failed:", interaction.error); break
    -    time.sleep(10)
    - -

    18.3 agent_config

    -
    - - - - - - - - -
    CampoTipoPadrãoDescrição
    typestringobrigatórioSempre "deep-research"
    thinking_summariesstring"none""auto" habilita raciocínio intermediário no stream
    visualizationstring"auto""auto" gera tabelas/gráficos; "off" desativa
    collaborative_planningbooleanfalseAtiva revisão do plano antes de executar
    -
    - -

    18.4 Planejamento colaborativo (3 etapas)

    -
      -
    1. Solicitar plano (collaborative_planning: true).
    2. -
    3. Refinar plano (mesmo collaborative_planning: true, com previous_interaction_id).
    4. -
    5. Aprovar e executar (collaborative_planning: false).
    6. -
    - -

    18.5 Ferramentas suportadas

    -

    Ativadas por padrão: google_search, url_context, code_execution. Opcionalmente: mcp_server, file_search.

    - -

    18.6 Reconexão de stream

    -
    # Salve last_event_id e reconecte com:
    -stream = client.interactions.get(
    -    id=interaction_id, stream=True, last_event_id=last_event_id
    -)
    - -

    18.7 Custos & limites

    -
    Estimativas de preview (sujeitas a mudança): custos e nº de consultas abaixo são aproximados (~) e baseados em preview rates — a doc oficial avisa que podem mudar. Tempo máximo de pesquisa: 60 min (maioria das tarefas em ~20 min).
    -
    - - - - - - -
    VersãoConsultasTokens entradaTokens saídaCusto estimado
    deep-research-preview-04-2026~80~250k (50–70% cache)~60kUS$ 1,00–3,00 / tarefa
    deep-research-max-preview-04-2026~160~900k (50–70% cache)~80kUS$ 3,00–7,00 / tarefa
    -
    -
      -
    • Tempo máximo: 60 minutos por tarefa (maioria conclui em ~20 min).
    • -
    • background=true exige store=true.
    • -
    • Function calling personalizado não é suportado (use MCP).
    • -
    • Saída estruturada não é suportada atualmente.
    • -
    - -

    18.8 Follow-up sobre relatório

    -
    followup = client.interactions.create(
    -    input="Can you elaborate on the second point?",
    -    model="gemini-3.1-pro-preview",
    -    previous_interaction_id="COMPLETED_INTERACTION_ID"
    -)
    - -

    18.9 Antigravity agent (preview) — agente gerenciado de propósito geral

    -

    O Antigravity (antigravity-preview-05-2026) é um agente gerenciado de propósito geral movido por gemini-3.5-flash: uma única chamada dispara um loop autônomo de raciocínio, execução de código, gestão de arquivos e navegação web dentro de um sandbox Linux hospedado (ver §18.10). Disponível via Interactions API e Google AI Studio.

    -
    interaction = client.interactions.create(
    -    agent="antigravity-preview-05-2026",
    -    input="Analyze this CSV and produce a summary report.",
    -    environment="remote",   # sandbox novo com defaults
    -)
    -print(interaction.output_text)
    -print(interaction.environment_id)  # reutilize para continuar com os mesmos arquivos/estado
    -

    O parâmetro environment aceita três formas:

    -
    - - - - - - - -
    FormaComportamento
    "remote"Cria um sandbox novo com configurações padrão.
    "env_abc123"Reutiliza um environment existente pelo ID — arquivos e estado preservados.
    {...} (EnvironmentConfig)Configuração completa: fontes Git/GCS/inline e regras de rede (allowlist).
    -
    -

    Capacidades: execução de código (Bash, Python, Node.js — instala pacotes, roda testes), gestão de arquivos persistente entre interações, acesso web (Google Search + URL Context) e compactação automática de contexto (disparada em ~135k tokens). Ferramentas tipadas suportadas: code_execution, google_search e url_context (todas ativas por padrão — restrinja passando só o necessário em tools); o filesystem é habilitado automaticamente pelo environment.

    -

    Customização: passe um AGENTS.md com instruções, monte skills em .agents/skills/ no sandbox ou configure inline na interação; o resultado pode ser salvo como agente gerenciado (custom agent).

    -
    Limitações (preview): entrada apenas text e image (base64 inline) — sem áudio, vídeo ou documentos; os parâmetros temperature, top_p, top_k, stop_sequences e max_output_tokens retornam 400; sem saída estruturada; sem file_search, computer_use, google_maps, function calling custom ou MCP; background=true não é suportado e store=true é obrigatório. Schemas podem mudar.
    -
    Custos (estimativas de preview, pay-as-you-go): tarefas típicas usam 100k–500k tokens de entrada (50–70% em cache) e 10k–50k de saída — US$ 0,25–1,30 por tarefa; processamento de dados pode chegar a 300k–3M de entrada (US$ 0,70–3,25) e workflows complexos a 3–5M tokens (~US$ 5/interação). A computação do sandbox não é cobrada durante o preview.
    - -

    18.10 Environments (sandboxes de agente)

    -

    Cada agente gerenciado roda em uma VM Linux isolada (Ubuntu, Python 3.12, Node.js 22) onde raciocina, executa código, gerencia arquivos e navega na web. Rede de saída liberada por padrão (configurável via allowlist). A VM hiberna por inatividade e restaura o estado na próxima requisição (cold start); é deletada permanentemente após 7 dias de inatividade. Limite: 1.000 agentes gerenciados. Agentes custom são construídos sobre a base do Antigravity — ver custom-agents e o quickstart de managed agents nas fontes abaixo.

    - - -
    - -
    -

    19. Background & webhooks

    - -

    Para operações longas (Deep Research, Deep Think), defina background=true. A interação fica em estado in_progress até concluir, e você pode:

    -
      -
    • Fazer polling via GET /interactions/{id}.
    • -
    • Receber notificação via webhook_config.
    • -
    - -

    19.1 Polling

    -
    while True:
    -    res = client.interactions.get(interaction_id)
    -    if res.status == "completed": break
    -    time.sleep(10)
    - -

    19.2 Webhook dinâmico (por requisição)

    -
    interaction = client.interactions.create(
    -    agent="deep-research-preview-04-2026",
    -    input="Research the latest in quantum computing.",
    -    background=True,
    -    webhook_config={
    -        "uris": ["https://my-api.com/gemini-webhook"],
    -        "user_metadata": {"job_id": "abc-123"}
    -    }
    -)
    - -

    19.3 Webhook estático (criar no projeto)

    -
    webhook = client.webhooks.create(
    -    name="MyWebhook",
    -    subscribed_events=["interaction.completed", "interaction.failed",
    -                       "interaction.requires_action", "interaction.cancelled"],
    -    uri="https://my-api.com/gemini-callback",
    -)
    -# webhook.new_signing_secret é retornado APENAS UMA VEZ
    - -

    19.4 Eventos suportados (Interactions)

    -
    - - - - - - - - -
    typeDispara quando
    interaction.completedLRO concluído
    interaction.failedLRO falhou (error_code, error_message em data)
    interaction.requires_actionFunção do cliente pendente
    interaction.cancelledCancelado pelo usuário
    -
    - -

    19.5 Verificação de assinatura (webhooks dinâmicos)

    -
      -
    • Header: Webhook-Signature (JWT, RS256).
    • -
    • Endpoint JWKS público: https://generativelanguage.googleapis.com/.well-known/jwks.json.
    • -
    • Use o kid do header JWT para encontrar a chave pública.
    • -
    - -

    19.6 Boas práticas

    -
      -
    • Responda 2xx em segundos; processe assincronamente.
    • -
    • Retentativas automáticas por 24 horas com backoff exponencial.
    • -
    • Header webhook-timestamp: rejeite se > 5 min de skew (anti-replay).
    • -
    • Header webhook-id para deduplicação (entrega at-least-once).
    • -
    • Rotate signing secret com revocation_behavior: "REVOKE_PREVIOUS_SECRETS_AFTER_H24".
    • -
    - - -
    - -
    -

    20. Flex & Priority Inference

    - -

    20.1 Comparativo de tiers

    -
    - - - - - - - - -
    RecursoPriorityStandardFlexBatch
    Preço+75–100% vs StandardPreço cheio−50%−50%
    LatênciaSegundosSegundos–minutos1–15 min (alvo)Até 24h
    ConfiabilidadeAlta (não descartável)Alta/Média-altaMelhor esforço (descartável)Alta (throughput)
    InterfaceSíncronaSíncronaSíncronaAssíncrona
    -
    - -

    20.2 Habilitar Flex

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Analyze this dataset for trends...",
    -    service_tier='flex'
    -)
    - -

    20.3 Habilitar Priority

    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Triage this critical support ticket immediately.",
    -    service_tier='priority'
    -)
    - -

    20.4 Retry com backoff (Flex)

    -
    import time
    -def call_with_retry(max_retries=3, base_delay=5):
    -    for attempt in range(max_retries):
    -        try:
    -            return client.interactions.create(
    -                model="gemini-3.5-flash", input="...", service_tier="flex")
    -        except Exception as e:
    -            if attempt < max_retries - 1:
    -                time.sleep(base_delay * (2 ** attempt))
    -            else:
    -                return client.interactions.create(
    -                    model="gemini-3.5-flash", input="...")  # fallback
    - -

    20.5 Códigos de erro Flex

    -
      -
    • 503 Service Unavailable — capacidade no limite.
    • -
    • 429 Too Many Requests — limite excedido.
    • -
    - -

    20.6 Soft downgrade (Priority)

    -

    Em picos, Priority faz soft downgrade automático para Standard (cobrado à taxa Standard). Monitore via header x-gemini-service-tier.

    - - -
    - -
    -

    21. Armazenamento & retenção de dados

    - -

    21.1 Padrão server-side

    -
      -
    • Padrão: store=true. Servidor armazena steps por: -
        -
      • Tier pago: 55 dias.
      • -
      • Tier free: 1 dia.
      • -
      -
    • -
    • Use previous_interaction_id para continuar histórico (e habilita cache implícito).
    • -
    - -

    21.2 Modo sem estado (store=false)

    -
      -
    • Servidor não armazena nada.
    • -
    • Você precisa enviar histórico completo (com signature de thought) em cada turno.
    • -
    • Incompatível com background=true.
    • -
    • Impede uso da interação como previous_interaction_id.
    • -
    - -

    21.3 Excluir / cancelar manualmente

    -
    curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/interactions/INT_ID" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY"
    -
    -curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions/INT_ID/cancel" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY"
    -
    - -
    -

    22. Limitações

    - -

    Recursos ainda ausentes ou em desenvolvimento na Interactions API:

    -
      -
    • Batch API assíncrona — siga usando generateContent com :batchGenerateContent.
    • -
    • Cache explícito — disponível apenas via generateContent.
    • -
    • video_metadata (cortes, FPS customizado) — disponível apenas em generateContent.
    • -
    • Chamada automática de função em Python — disponível apenas em generateContent.
    • -
    • MCP remoto com Gemini 3.x — ainda não suportado (em breve, segundo a doc oficial). Quando suportado, apenas servidores Streamable HTTP (não SSE).
    • -
    • Deep Research: function calling personalizado não suportado (use MCP); saída estruturada não suportada.
    • -
    • File Search: sem áudio/vídeo; não disponível na Live API.
    • -
    • Computer Use: suportado em gemini-3-flash-preview (nativo) e no modelo dedicado gemini-2.5-computer-use-preview-10-2025; gemini-3.5-flash não é compatível. Recurso em preview.
    • -
    - -

    22.1 Configurações de segurança

    -

    O filtro de segurança clássico — safety_settings com HarmCategory (ex.: HARM_CATEGORY_HATE_SPEECH) e HarmBlockThreshold (ex.: BLOCK_LOW_AND_ABOVE) — é documentado para o generateContent (via types.GenerateContentConfig) e não consta no schema de request da Interactions API nesta revisão. Para ações agênticas, a Interactions API expõe um mecanismo distinto: o campo safety_decision (ex.: require_confirmation) em ferramentas como Computer Use — implemente HITL conforme a §17.5.

    - -
    - -
    -

    23. Práticas recomendadas

    - -
      -
    • Use previous_interaction_id em vez de reenviar histórico — ativa cache implícito e reduz custo.
    • -
    • Para Deep Research, combine com modelo padrão depois: faça polling até completed e use previous_interaction_id num Gemini Flash para resumir.
    • -
    • Coloque conteúdos grandes (PDF, documento) no início do prompt para maximizar cache hits.
    • -
    • Para multimodal de uma imagem ou PDF curto, posicione o prompt de texto depois da mídia.
    • -
    • Em streaming de function calling, acumule arguments_delta e só faça JSON.parse após step.stop.
    • -
    • Em modo store=false, NUNCA modifique blocos thought ou suas signature — reenvie exatamente como recebido.
    • -
    • Implemente retry com backoff em service_tier: flex; cache de Priority via header x-gemini-service-tier.
    • -
    • Em webhooks, valide webhook-timestamp (≤5 min) e use webhook-id para deduplicação.
    • -
    • Trate eventos SSE desconhecidos com log + skip, não como erro.
    • -
    -
    - -
    -

    Parte B — Referência REST completa

    -

    Schema canônico da Interactions API verificado contra ai.google.dev/api/interactions-api. Todos os nomes de campo, enums e exemplos são preservados literalmente (a API usa snake_case no wire; os SDKs expõem camelCase em JS).

    -
    - -
    -

    B1. Endpoints

    -

    Base: https://generativelanguage.googleapis.com. Versão atual: v1beta (não existe /v1beta2 — todas as páginas oficiais usam /v1beta).

    -
    - - - - - - - - -
    Método & caminhoOperaçãoDescrição
    POST /v1beta/interactionscreateCria uma nova Interaction (modelo ou agente). Aceita stream, store, background.
    GET /v1beta/interactions/{id}getRecupera o estado completo de uma interação armazenada. Aceita stream, last_event_id, include_input.
    DELETE /v1beta/interactions/{id}deleteExclui uma interação armazenada por ID.
    POST /v1beta/interactions/{id}/cancelcancelCancela uma interação background ainda em execução.
    -
    - -
    - -
    -

    B2. Autenticação & Headers

    -
    - - - - - - - -
    HeaderObrigatórioValor
    x-goog-api-keySimSua chave de API ($GEMINI_API_KEY). Alternativa: query ?key=.
    Content-TypeSim (POST)application/json
    Api-RevisionNão (ignorado)Histórico da transição de Maio/2026: 2026-05-20 controlou o opt-in (até 26/05/2026) e 2026-05-07 o rollback (até 08/06/2026). Desde 08/06/2026 o header é ignorado e pode ser omitido.
    -
    -
    - SSE: para respostas em streaming, defina "stream": true no corpo (ou query ?stream=true no GET). O servidor responde text/event-stream com eventos event_type (ver B18). -
    - -
    - -
    -

    B3. POST /v1beta/interactions — criar

    -

    Cria uma nova interação. Exatamente um de model ou agent é obrigatório.

    - -

    Corpo da requisição

    -
    - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoDescrição
    modelModelOptionNome do modelo. Obrigatório se agent ausente. Ver B19.
    agentAgentOptionNome do agente. Obrigatório se model ausente. Ver B20.
    inputContent | array(Content) | array(Step) | string(Obrigatório) Entradas da interação. Aceita string simples, blocos de conteúdo ou steps tipados.
    system_instructionstringInstrução de sistema. Interaction-scoped (reenvie a cada turno).
    toolsarray(Tool)Declarações de ferramentas. Interaction-scoped. Ver B17.
    response_formatResponseFormat | ResponseFormatListFormato de saída (text/JSON, image, audio). Substitui response_mime_type + image_config.
    response_mime_typestringlegado MIME da resposta. No novo schema use mime_type dentro de response_format.
    streambooleanInput only. Streaming SSE.
    storebooleanInput only. Armazenar para recuperação posterior. Default true.
    backgroundbooleanInput only. Executar em background (tarefas longas). Incompatível com store=false.
    generation_configGenerationConfigConfiguração do modelo. Alternativa a agent_config. Só com model. Ver B10.
    agent_configDeepResearchAgentConfig | DynamicAgentConfigConfiguração do agente. Só com agent. Ver B11.
    environmentEnvironmentConfig | stringAmbiente remoto (sources GCS/repo/inline, allowlist de rede) ou ID de ambiente existente.
    previous_interaction_idstringID da interação anterior — ativa estado server-side e cache implícito.
    response_modalitiesarray(ResponseModality)Modalidades desejadas: text, image, audio, video, document.
    service_tierServiceTierflex | standard | priority.
    webhook_configWebhookConfigURIs de webhook + user_metadata para notificações. Ver B12.
    -
    - -

    Exemplo mínimo

    -
    -
    - - - -
    -
    -
    from google import genai
    -
    -client = genai.Client()
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Hello, how are you?",
    -)
    -print(interaction.output_text)
    -
    -
    -
    import {GoogleGenAI} from '@google/genai';
    -
    -const ai = new GoogleGenAI({});
    -const interaction = await ai.interactions.create({
    -    model: 'gemini-3.5-flash',
    -    input: 'Hello, how are you?',
    -});
    -console.log(interaction.output_text);
    -
    -
    -
    curl -X POST https://generativelanguage.googleapis.com/v1beta/interactions \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -H "Api-Revision: 2026-05-20" \
    -  -d '{
    -    "model": "gemini-3.5-flash",
    -    "input": "Hello, how are you?"
    -  }'
    -
    -
    - -
    - Resposta JSON (200) — status: completed -
    -
    {
    -  "created": "2025-11-26T12:25:15Z",
    -  "id": "v1_ChdPU0F4YWFtNkFwS2kxZThQZ05lbXdROBIX...",
    -  "model": "gemini-3.5-flash",
    -  "object": "interaction",
    -  "steps": [
    -    {
    -      "type": "model_output",
    -      "content": [
    -        { "type": "text", "text": "Hello! I'm functioning perfectly..." }
    -      ]
    -    }
    -  ],
    -  "status": "completed",
    -  "updated": "2025-11-26T12:25:15Z",
    -  "usage": {
    -    "input_tokens_by_modality": [ { "modality": "text", "tokens": 7 } ],
    -    "total_cached_tokens": 0,
    -    "total_input_tokens": 7,
    -    "total_output_tokens": 20,
    -    "total_thought_tokens": 22,
    -    "total_tokens": 49,
    -    "total_tool_use_tokens": 0
    -  }
    -}
    -
    -
    -
    - Function calling: quando o modelo decide chamar uma ferramenta, o status retorna requires_action e o último step é function_call (com id, name, arguments). Responda com um step function_result reaproveitando call_id = id. -
    - -
    - -
    -

    B4. GET /v1beta/interactions/{id} — recuperar

    -

    Recupera os detalhes completos de uma interação armazenada (store=true). O recurso retornado pelo GET inclui também o step user_input (a resposta do create retorna apenas steps gerados pelo modelo).

    -
    - - - - - - - - - -
    ParâmetroTipoDescrição
    idstring(Obrigatório) Identificador da interação.
    streambooleanSe true, transmite incrementalmente (SSE). Default false.
    last_event_idstringRetoma o stream a partir do próximo chunk após o evento indicado. Só com stream=true.
    include_inputbooleanInclui o input na resposta. Default false.
    api_versionstringVersão da API a usar.
    -
    -
    -
    - - - -
    -
    -
    interaction = client.interactions.get(id=created.id)
    -print(interaction.status)
    -
    -
    -
    const interaction = await ai.interactions.get(created.id);
    -console.log(interaction.status);
    -
    -
    -
    curl -X GET "https://generativelanguage.googleapis.com/v1beta/interactions/$INTERACTION_ID" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H "Api-Revision: 2026-05-20"
    -
    -
    -
    Polling de background: para background=true, faça get repetido até status sair de in_progress para completed/failed/cancelled.
    - -
    - -
    -

    B5. DELETE /v1beta/interactions/{id} — excluir

    -

    Exclui a interação por ID. Requer apenas id (e api_version opcional). Resposta vazia em caso de sucesso.

    -
    -
    - - - -
    -
    -
    client.interactions.delete(id=created.id)
    -print("Interaction deleted successfully.")
    -
    -
    -
    await ai.interactions.delete(created.id);
    -console.log('Interaction deleted successfully.');
    -
    -
    -
    curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/interactions/$INTERACTION_ID" \
    -  -H "x-goog-api-key: $GEMINI_API_KEY" \
    -  -H "Api-Revision: 2026-05-20"
    -
    -
    -
    - -
    -

    B6. POST /v1beta/interactions/{id}/cancel — cancelar

    -

    Cancela uma interação. Aplica-se apenas a interações background ainda em execução. Retorna o recurso Interaction com status: cancelled.

    -
    -
    - - -
    -
    -
    created = client.interactions.create(
    -    model="gemini-3-flash-preview",
    -    input="Write a long essay about the history of computing.",
    -    tools=[{"type": "computer_use"}],
    -    background=True,
    -)
    -interaction = client.interactions.cancel(id=created.id)
    -print(interaction.status)  # cancelled
    -
    -
    -
    const created = await ai.interactions.create({
    -    model: 'gemini-3-flash-preview',
    -    input: 'Write a long essay about the history of computing.',
    -    tools: [{ type: 'computer_use' }],
    -    background: true,
    -});
    -const interaction = await ai.interactions.cancel(created.id);
    -console.log(interaction.status); // cancelled
    -
    -
    -
    - -
    -

    B7. Recurso Interaction

    -

    Objeto central. Campos Output only são preenchidos pelo servidor.

    -
    - - - - - - - - - - - - - - - - -
    PropriedadeTipoNotas
    idstring(Obrigatório, output) Identificador único.
    objectstringSempre "interaction".
    model / agentenumModelo ou agente usado.
    statusenum(Obrigatório, output) Ver B8.
    stepsarray(Step)(Obrigatório, output) Timeline da interação. Ver B15.
    created / updatedstring(Obrigatório, output) ISO 8601 (YYYY-MM-DDThh:mm:ssZ).
    inputpoliformeEntrada (presente no GET com include_input).
    previous_interaction_idstringEncadeamento server-side.
    rolestringOutput only.
    environment_idstringOutput only. Só se environment foi configurado.
    usageUsageOutput only. Ver B9.
    response_format, response_modalities, service_tier, system_instruction, tools, generation_config, agent_config, webhook_config, environment—Espelham os campos do request.
    -
    -
    - -
    -

    B8. InteractionStatus (enum)

    -
    - - - - - - - - - - - -
    ValorSignificado
    in_progressEm execução (streaming/background).
    requires_actionAguardando ação do cliente — tipicamente um function_result para um function_call.
    completedConcluída com sucesso.
    failedErro durante a geração.
    cancelledCancelada via endpoint de cancel.
    incompleteInterrompida antes de concluir (ex.: limite de tokens).
    budget_exceededOrçamento (ex.: Deep Research) excedido.
    -
    -
    - -
    -

    B9. Usage & modalidades

    -

    Estatísticas de tokens. Os totais são acompanhados por breakdowns por modalidade (ModalityTokens: { modality, tokens }).

    -
    - - - - - - - - - - - - - - - -
    CampoDescrição
    total_input_tokensTokens do prompt (contexto).
    total_output_tokensTokens gerados em todas as respostas.
    total_thought_tokensTokens de raciocínio (modelos thinking).
    total_cached_tokensTokens servidos do cache implícito.
    total_tool_use_tokensTokens de prompts de uso de ferramentas.
    total_tokensTotal (prompt + respostas + internos).
    input_tokens_by_modalityBreakdown de entrada por modalidade.
    output_tokens_by_modalityBreakdown de saída por modalidade.
    cached_tokens_by_modalityBreakdown de cache por modalidade.
    tool_use_tokens_by_modalityBreakdown de uso de ferramentas por modalidade.
    grounding_tool_countarray de { type, count } — type ∈ google_search | google_maps | retrieval.
    -
    -
    - -
    -

    B10. GenerationConfig

    -

    Configuração do modelo (alternativa a agent_config; só com model).

    -
    - - - - - - - - - - - - - - -
    CampoTipoNotas
    thinking_levelenumminimal | low | medium | high. Substitui thinking_budget.
    thinking_summariesenumauto | none.
    max_output_tokensintegerMáximo de tokens na resposta.
    temperaturenumbernão recomendado em Gemini 3.x
    top_pnumbernão recomendado em Gemini 3.x
    seedintegerReprodutibilidade na decodificação.
    stop_sequencesarray(string)Sequências que interrompem a saída.
    tool_choiceToolChoiceConfig | ToolChoiceTypeauto | any | none | validated.
    image_configImageConfigaspect_ratio (1:1…21:9, 1:8, 8:1, 1:4, 4:1) e image_size (0.5K, 1K, 2K, 4K). legado — no novo schema, prefira response_format tipo image.
    speech_configarray(SpeechConfig){ language, speaker, voice } para TTS multi-speaker.
    -
    -
    - -
    -

    B11. AgentConfig & EnvironmentConfig

    -

    Discriminado por type. Só com agent.

    -

    DeepResearchAgentConfig — type: "deep-research"

    -
    - - - - - - - - -
    CampoTipoNotas
    typeconst(Obrigatório) "deep-research".
    collaborative_planningbooleanHuman-in-the-loop: o agente devolve um plano e só prossegue após confirmação no próximo turno.
    thinking_summariesenumauto | none.
    visualizationenumoff | auto — incluir visualizações na resposta.
    -
    -

    DynamicAgentConfig — type: "dynamic"

    -

    Configuração para agentes dinâmicos. Campo obrigatório: type: "dynamic".

    - -

    EnvironmentConfig — ambiente remoto (Computer Use / Antigravity)

    -

    Passado no campo top-level environment (objeto) ou como string com o ID de um ambiente já criado. Discriminador type: "remote".

    -
    - - - - - - - -
    CampoTipoNotas
    typeconst(Obrigatório) "remote".
    networkEnvironmentNetworkEgressAllowlist | enumEgress allowlist de rede: allowlist[].domain + allowlist[].transform (transformação/proxy de credenciais).
    sourcesarray(Source)Arquivos/dados montados no ambiente (campos abaixo).
    -
    -

    Cada Source:

    -
    - - - - - - - - - -
    CampoTipoNotas
    typeenumrepository | gcs | inline (a doc oficial de agents-environments lista esses três tipos).
    sourcestringOrigem (caminho GCS, caminho do GitHub etc.).
    targetstringOnde o conteúdo deve aparecer no ambiente.
    contentstringConteúdo inline (quando type: "inline").
    encodingstringEncoding opcional do inline (ex.: base64).
    -
    -
    - -
    -

    B12. WebhookConfig

    -
    - - - - - - -
    CampoTipoNotas
    urisarray(string)Se definido, usa estes URIs em vez dos webhooks registrados.
    user_metadataobjectMetadados retornados em cada emissão de evento ao webhook.
    -
    -
    Segurança de webhook: valide o header webhook-timestamp (rejeite > 5 min) e use webhook-id para deduplicação. Verifique a assinatura antes de processar o payload.
    -
    - -
    -

    B13. ResponseFormat · ResponseModality / ServiceTier / MediaResolution

    -

    response_format aceita um objeto ResponseFormat ou um array (ResponseFormatList, ex.: [{"type":"text"}, {"type":"image"}] para saída intercalada). Discriminado por type. Substitui o legado response_mime_type + image_config.

    -
    - - - - - - - -
    Variante (type)Campos
    text
    (TextResponseFormat)
    mime_type (application/json | text/plain); schema (JSON Schema — só com application/json).
    image
    (ImageResponseFormat)
    aspect_ratio (1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:8, 8:1, 1:4, 4:1); image_size (512 | 1K | 2K | 4K); delivery (inline | uri); mime_type (image/jpeg).
    audio
    (AudioResponseFormat)
    mime_type (audio/mp3 | audio/ogg_opus | audio/l16 | audio/wav | audio/alaw | audio/mulaw); sample_rate (Hz); bit_rate (bps — só formatos comprimidos); delivery (inline | uri).
    -
    -
    - - - - - - - - - - -
    EnumValores
    ResponseModalitytext · image · audio · video · document
    ServiceTierflex · standard · priority
    MediaResolutionlow · medium · high · ultra_high
    ThinkingLevelminimal · low · medium · high
    ThinkingSummariesauto · none
    ToolChoiceTypeauto · any · none · validated
    -
    -
    - -
    -

    B14. Content blocks (poliforme por type)

    -

    Blocos de conteúdo dentro de content[] de um step. Discriminador: type.

    -
    - - - - - - - - - -
    typeCamposEnums relevantes
    texttext (obrig.), annotations[]—
    imagedata (base64) | uri, mime_type, resolutionimage/png|jpeg|webp|heic|heif|gif|bmp|tiff
    audiodata | uri, mime_type, sample_rate, channelsaudio/wav|mp3|aiff|aac|ogg|flac|mpeg|m4a|l16|opus|alaw|mulaw
    documentdata | uri, mime_typeapplication/pdf
    videodata | uri, mime_type, resolutionvideo/mp4|mpeg|mpg|mov|avi|x-flv|webm|wmv|3gpp · uri aceita YouTube
    -
    -
    Vídeo via URL: { "type": "video", "uri": "https://www.youtube.com/watch?v=..." } dispensa upload.
    -
    - -
    -

    B15. Step types (poliforme por type)

    -

    A timeline steps[] é a substituta de candidates/outputs. Cada step tem um type. Steps de chamada de ferramenta vêm em pares call → result, ligados por id ↔ call_id. Muitos steps trazem signature (hash para validação backend — nunca modifique).

    - -

    Steps de conversa

    -
    - - - - - - - -
    typeCamposDescrição
    user_inputcontent[]Entrada do usuário (presente no GET).
    model_outputcontent[]Saída do modelo (texto/imagem/áudio).
    thoughtsummary[], signatureRaciocínio. summary é array de ThoughtSummaryContent.
    -
    - -

    Steps de chamada de ferramenta (call)

    -
    - - - - - - - - - - - -
    typeCampos-chave
    function_callid, name, arguments (object), signature
    code_execution_callid, arguments.code, arguments.language (python), signature
    url_context_callid, arguments.urls[], signature
    google_search_callid, arguments.queries[], search_type (web_search|image_search|enterprise_web_search), signature
    google_maps_callid, arguments.queries[], signature
    file_search_callid, signature
    mcp_server_tool_callid, name, server_name, arguments, signature
    -
    - -

    Steps de resultado de ferramenta (result)

    -
    - - - - - - - - - - - -
    typeCampos-chave
    function_resultcall_id (obrig.), name, result (string | array de subconteúdo), is_error, signature
    code_execution_resultcall_id, result (string), is_error, signature
    url_context_resultcall_id, result[] com url + status (success|error|paywall|unsafe), is_error
    google_search_resultcall_id, result[], search_suggestions (substitui rendered_content), is_error
    google_maps_resultcall_id, result[].places[] (name, place_id, review_snippets[], url), widget_context_token
    file_search_resultcall_id, signature
    mcp_server_tool_resultcall_id, name, server_name, result
    -
    - -
    - Exemplo: par function_call → function_result -
    -
    // step gerado pelo modelo (status: requires_action)
    -{ "type": "function_call", "id": "call_98231", "name": "get_weather",
    -  "arguments": { "location": "Boston, MA" } }
    -
    -// step que você envia de volta no próximo create
    -{ "type": "function_result", "call_id": "call_98231", "name": "get_weather",
    -  "result": { "temperature": "72F", "conditions": "Partly Cloudy" } }
    -
    -
    - -
    - -
    -

    B16. Annotation (citações)

    -

    Anexadas a blocos text via annotations[]. No novo schema, a citação é tipada como url_citation.

    -
    - - - - - - - - -
    CampoTipoNotas
    typeconst"url_citation" (novo schema).
    urlstringURL da fonte.
    titlestringTítulo da fonte.
    start_index / end_indexintegerIntervalo de caracteres do texto citado.
    -
    -
    Mudança: o schema legado usava { start_index, end_index, source }. O novo usa { type: "url_citation", url, title, start_index, end_index }.
    -
    - -
    -

    B17. Tool schemas (poliforme por type)

    -
    - - - - - - - - - - - - - -
    typeCamposNotas
    functionname, description, parameters (JSON Schema)Função personalizada (client-side).
    google_searchsearch_types[]web_search | image_search | enterprise_web_search.
    google_mapslatitude, longitude, enable_widgetGrounding geográfico + widget token.
    code_execution—Sandbox Python.
    url_context—Busca e lê URLs do prompt.
    computer_useenvironment (browser), excluded_predefined_functions[]Preview. Suportado em gemini-3-flash-preview (nativo) e gemini-2.5-computer-use-preview-10-2025; gemini-3.5-flash não suporta.
    file_searchfile_search_store_names[], metadata_filter, top_kRAG gerenciado.
    mcp_servername, url, headers, allowed_tools ({ mode, tools[] })MCP remoto. mode ∈ auto|any|none|validated.
    retrievalretrieval_types[] (vertex_ai_search), vertex_ai_search_config (datastores[], engine)Vertex AI Search.
    -
    -
    - Exemplo: declaração de function + google_search combinadas -
    -
    "tools": [
    -  { "type": "google_search" },
    -  { "type": "function", "name": "get_weather",
    -    "description": "Get the current weather in a given location",
    -    "parameters": {
    -      "type": "object",
    -      "properties": { "location": { "type": "string" } },
    -      "required": ["location"]
    -    }
    -  }
    -]
    -
    -
    - -
    - -
    -

    B18. InteractionSseEvent (streaming)

    -

    Com stream=true, o servidor emite eventos text/event-stream, discriminados por event_type. Todo evento traz event_id (use com last_event_id para retomar).

    -
    - - - - - - - - - - - - -
    event_typePayloadQuando
    interaction.createdinteraction, event_idInício — interação criada (status: in_progress).
    interaction.in_progressinteraction_id, status, event_idProgresso da interação (schema novo; substitui o legado interaction.status_update).
    interaction.requires_actioninteraction_id, status, event_idAguarda ação do cliente (ex.: function_result pendente).
    step.startindex, step, event_idNovo step inicia (ex.: { "type": "model_output" }).
    step.deltaindex, delta, event_idFragmento incremental — ex.: { "type": "text", "text": "Hello" }.
    step.stopindex, event_idStep finalizado.
    interaction.completedinteraction, event_idFim — interaction com outputs vazios (use os deltas anteriores).
    errorerror (code, message), event_idFalha no stream.
    -
    -
    - Renomeações (schema legado → novo): interaction.start→interaction.created, content.start→step.start, content.delta→step.delta, content.stop→step.stop, interaction.complete→interaction.completed, interaction.status_update→interaction.in_progress/interaction.requires_action (o status_update legado foi removido em 08/06/2026). Acumule arguments_delta de function calls e só faça JSON.parse após step.stop. -
    -
    - Exemplo: sequência de eventos para "Hello" -
    -
    {"event_type":"interaction.created","interaction":{"id":"v1_...","status":"in_progress"},"event_id":"evt_1"}
    -{"event_type":"step.start","index":0,"step":{"type":"model_output"},"event_id":"evt_2"}
    -{"event_type":"step.delta","index":0,"delta":{"type":"text","text":"Hello"},"event_id":"evt_3"}
    -{"event_type":"step.stop","index":0,"event_id":"evt_4"}
    -{"event_type":"interaction.completed","interaction":{"id":"v1_...","status":"completed"},"event_id":"evt_5"}
    -
    -
    - -
    - -
    -

    B19. ModelOption

    -

    Conjunto de modelos atuais recomendados para a Interactions API (verificado em 2026-06-10). A enum aceita outros valores, mas este guia foca exclusivamente nos modelos atuais — para reasoning/multimodal avançado use gemini-3.1-pro-preview.

    -
    - - - - - - - - - - - - -
    Model IDUso
    gemini-3.5-flashTexto/chat, agêntico e código em escala (GA — padrão recomendado).
    gemini-3.1-pro-previewPro — SOTA em raciocínio e multimodal.
    gemini-3.1-flash-liteCusto-eficiente, alto volume, agêntico simples.
    gemini-3.1-flash-imageNano Banana 2 — geração/edição de imagem.
    gemini-3.1-flash-tts-previewTTS (text-to-speech) de baixa latência.
    gemini-3.1-flash-live-previewLive API — diálogo de voz em tempo real (áudio-para-áudio).
    gemini-3-flash-previewComputer Use com suporte nativo (modelo mais recente com CU embutido).
    gemini-2.5-computer-use-preview-10-2025Computer Use — modelo dedicado (única exceção 2.5, pois não há equivalente 3.x).
    -
    -
    STT / transcrição: não há modelo STT dedicado — a transcrição é feita por compreensão de áudio em qualquer modelo multimodal 3.x. Use gemini-3.5-flash (mais capaz) ou gemini-3.1-flash-lite (mais barato; a doc o recomenda explicitamente para transcrição em volume). Para transcrição em tempo real, use a Live API (gemini-3.1-flash-live-preview).
    -
    - -
    -

    B20. AgentOption

    -
    - - - - - - - -
    Agent IDDescrição
    deep-research-preview-04-2026Gemini Deep Research Agent — planeja e executa pesquisa multi-etapa com relatórios citados.
    deep-research-max-preview-04-2026Gemini Deep Research Max Agent — máxima abrangência entre centenas de fontes.
    antigravity-preview-05-2026Antigravity Agent — agente gerenciado de propósito geral (Gemini 3.5 Flash) com sandbox Linux: código, arquivos e web. Ver §18.9.
    -
    -
    Limitações Deep Research: não suporta function calling personalizado (use MCP) nem saída estruturada. Recomenda-se background=true + polling, ou webhook.
    -
    Limitações Antigravity: entrada só text/image; sem saída estruturada, function calling custom ou MCP; background=true não suportado, store=true obrigatório; temperature/top_p/top_k/stop_sequences/max_output_tokens retornam 400.
    -
    - -
    -

    B21. Erros

    -

    Erros seguem o formato { "error": { "code": "...", "message": "..." } }. Em SSE, chegam como evento error. code é um identificador textual (ex.: not_found).

    -
    - - - - - - - - - -
    HTTPCausa comumAção
    400Schema inválido; response_format sem mime_type; mismatch de function_result (id/name/contagem).Corrija o corpo; alinhe call_id/name/contagem.
    401 / 403Chave ausente/ inválida; sem acesso ao modelo/agente.Verifique x-goog-api-key e permissões.
    404 (not_found)previous_interaction_id expirado/excluído; ID inexistente.Recrie a conversa; cheque retenção (55d pago / 1d free).
    429Rate limit / quota.Backoff exponencial; considere service_tier: priority.
    5xxErro do servidor.Retry idempotente com backoff.
    -
    -
    - -
    -

    Parte C — Migração de generateContent → Interactions API

    -

    Cada cenário mostra o código antes (generateContent / models.generate_content) e depois (interactions.create), lado a lado. Use isto como receita de transição. generateContent permanece totalmente suportado — migre por escolha, não por obrigação (exceto onde recursos novos só existem na Interactions API).

    -
    - -
    -

    C1. Visão geral da migração

    -

    A Interactions API é o novo primitivo recomendado para projetos novos e agênticos. Diferenças conceituais centrais:

    -
    - - - - - - - - - - - -
    DimensãogenerateContentInteractions API
    Métodoclient.models.generate_content()client.interactions.create()
    Entradacontents (array de Content com parts)input (string, blocos ou steps tipados)
    Saídacandidates[].content.parts[]steps[] (timeline tipada) + output_text
    EstadoStateless — você reenvia todo o históricoServer-side via previous_interaction_id (ou stateless com store=false)
    Configconfig / generation_configgeneration_config (interaction-scoped)
    Tarefas longasNão nativobackground=true + polling/webhook
    Agentes—Deep Research, Antigravity, managed agents (custom)
    -
    -
    Quando NÃO migrar ainda: se você depende de Batch API, cache explícito, video_metadata ou chamada automática de função (Python), permaneça em generateContent até esses recursos chegarem à Interactions API.
    - -
    - -
    -

    C2. Breaking changes — Maio 2026

    -
    -

    ✅ Status em 2026-06-10 — transição concluída. Desde 08/06/2026 o schema novo (steps + response_format polimórfico) é o único aceito: o schema legado (outputs) foi removido permanentemente, o header Api-Revision passou a ser ignorado e a janela de rollback com Api-Revision: 2026-05-07 fechou em 08/06/2026 — não há mais como voltar. SDKs google-genai/@google/genai 1.x estão quebrados para Interactions; se algo ainda lê outputs ou envia response_mime_type, está falhando em produção — atualize para v2.0.0+ e o schema steps imediatamente. [guia oficial de migração]

    -
    -

    A versão de Maio/2026 do schema da Interactions API (SDK google-genai v2.0.0+; último PyPI 2.10.0, verificado em 2026-06-29) introduziu mudanças incompatíveis. Durante a transição o header Api-Revision controlava o opt-in e depois o rollback; desde 08/06/2026 ele é ignorado e não há rollback (ver status acima).

    - -

    Mudanças de formato

    -
    -
    -
    Antes — schema legado
    -
    {
    -  "outputs": [
    -    { "type": "text", "text": "Hello!" }
    -  ]
    -}
    -
    -
    -
    Depois — novo schema
    -
    {
    -  "steps": [
    -    { "type": "model_output",
    -      "content": [ { "type": "text", "text": "Hello!" } ] }
    -  ]
    -}
    -
    -
    - -
    -
    -
    Antes — response_mime_type + image_config
    -
    {
    -  "response_mime_type": "application/json",
    -  "generation_config": {
    -    "image_config": { "aspect_ratio": "1:1", "image_size": "1K" }
    -  }
    -}
    -
    -
    -
    Depois — response_format unificado
    -
    {
    -  "response_format": [
    -    { "type": "text", "mime_type": "application/json", "schema": { } },
    -    { "type": "image", "mime_type": "image/jpeg",
    -      "aspect_ratio": "1:1", "image_size": "1K" }
    -  ]
    -}
    -
    -
    - -

    Renomeação de eventos SSE

    -
    - - - - - - - - - -
    LegadoNovo
    interaction.startinteraction.created
    content.startstep.start
    content.deltastep.delta
    content.stopstep.stop
    interaction.completeinteraction.completed
    -
    - -

    Outras quebras

    -
      -
    • function_call agora vive dentro de steps[] (não em outputs), com id, name, arguments.
    • -
    • Step thought ganha summary[] + signature.
    • -
    • Grounding: result.rendered_content → result.search_suggestions; google_search_call/google_search_result migram para steps e ganham signature.
    • -
    • Annotations: { start_index, end_index, source } → { type: "url_citation", url, title, start_index, end_index }.
    • -
    • O GET agora prefixa um step user_input na timeline.
    • -
    -
    - SDK 1.x falha desde 08/06/2026: conforme anunciado ("As versões do SDK Python 1.x.x e JS 1.x.x vão falhar nas chamadas da API Interactions"), as chamadas em SDK 1.x agora falham. Atualize para google-genai v2.0.0+ / @google/genai v2.0.0+. -
    - -
    - -
    -

    C3. Texto simples

    -
    -
    -
    Antes — generateContent
    -
    from google import genai
    -
    -client = genai.Client()
    -response = client.models.generate_content(
    -    model="gemini-3.5-flash",
    -    contents="How does AI work?",
    -)
    -print(response.text)
    -
    -
    -
    Depois — Interactions API
    -
    from google import genai
    -
    -client = genai.Client()
    -interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="How does AI work?",
    -)
    -print(interaction.output_text)
    -
    -
    -
      -
    • models.generate_content → interactions.create
    • -
    • contents → input · response.text → interaction.output_text
    • -
    -
    - -
    -

    C4. Chat multi-turno

    -

    A maior mudança: você não reenvia o histórico — encadeia via previous_interaction_id.

    -
    -
    -
    Antes — histórico manual
    -
    history = [
    -    {"role": "user", "parts": [{"text": "Hello!"}]},
    -    {"role": "model", "parts": [{"text": "Hi! How can I help?"}]},
    -    {"role": "user", "parts": [{"text": "Capital of France?"}]},
    -]
    -response = client.models.generate_content(
    -    model="gemini-3.5-flash",
    -    contents=history,
    -)
    -print(response.text)
    -
    -
    -
    Depois — estado server-side
    -
    i1 = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Hello!",
    -)
    -i2 = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Capital of France?",
    -    previous_interaction_id=i1.id,
    -)
    -print(i2.output_text)
    -
    -
    -
    Cache implícito: encadear com previous_interaction_id permite ao servidor reaproveitar o histórico em cache — mais barato e rápido que reenviar tudo.
    -
    Interaction-scoped: tools, system_instruction e generation_config NÃO são herdados pelo previous_interaction_id — reespecifique-os a cada turno.
    -
    - -
    -

    C5. Streaming

    -
    -
    -
    Antes — generate_content_stream
    -
    stream = client.models.generate_content_stream(
    -    model="gemini-3.5-flash",
    -    contents="Write a poem.",
    -)
    -for chunk in stream:
    -    print(chunk.text, end="")
    -
    -
    -
    Depois — stream de steps
    -
    stream = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Write a poem.",
    -    stream=True,
    -)
    -for event in stream:
    -    if event.type == "step.delta" and event.delta.type == "text":
    -        print(event.delta.text, end="")
    -
    -
    -
      -
    • O stream agora emite eventos tipados (interaction.created, step.start/delta/stop, interaction.completed) em vez de chunks de texto homogêneos.
    • -
    • Filtre step.delta com delta.type == "text" para a saída textual; outros deltas carregam thoughts, imagens ou argumentos de função.
    • -
    -
    - -
    -

    C6. Multimodal (imagem / áudio / vídeo / PDF)

    -

    Em vez de types.Part.from_bytes, use blocos de conteúdo tipados no input.

    -
    -
    -
    Antes — Part.from_bytes
    -
    from google.genai import types
    -
    -response = client.models.generate_content(
    -    model="gemini-3.5-flash",
    -    contents=[
    -        types.Part.from_bytes(
    -            data=img_bytes, mime_type="image/png"),
    -        "What is in this picture?",
    -    ],
    -)
    -print(response.text)
    -
    -
    -
    Depois — blocos tipados
    -
    interaction = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -        { "type": "text", "text": "What is in this picture?" },
    -        { "type": "image", "data": base64_img,
    -          "mime_type": "image/png" },
    -    ],
    -)
    -print(interaction.output_text)
    -
    -
    -
      -
    • Tipos de bloco: text, image, audio, document (PDF), video (aceita uri do YouTube).
    • -
    • Posicione mídias grandes (PDF/documento) no início do input para maximizar cache; para uma única imagem/PDF curto, coloque o texto depois da mídia.
    • -
    • ainda só em generateContent video_metadata (cortes, FPS customizado).
    • -
    -
    - -
    -

    C7. Geração de imagem

    -
    -
    -
    Antes — response_modalities + image_config
    -
    response = client.models.generate_content(
    -    model="gemini-3.1-flash-image",
    -    contents="A robot holding a red skateboard",
    -    config=types.GenerateContentConfig(
    -        response_modalities=["IMAGE"],
    -        image_config=types.ImageConfig(aspect_ratio="16:9"),
    -    ),
    -)
    -
    -
    -
    Depois — response_format tipo image
    -
    interaction = client.interactions.create(
    -    model="gemini-3.1-flash-image",
    -    input="A robot holding a red skateboard",
    -    response_format={
    -        "type": "image",
    -        "mime_type": "image/jpeg",
    -        "aspect_ratio": "16:9",
    -        "image_size": "1K",
    -    },
    -)
    -img = interaction.output_image
    -
    -
    -
      -
    • image_config (dentro de generation_config) → entrada image em response_format.
    • -
    • Acesse a imagem por interaction.output_image; para histórias intercaladas texto+imagem, itere steps.
    • -
    • Edição: encadeie com previous_interaction_id e peça a alteração (ex.: trocar idioma do gráfico).
    • -
    -
    - -
    -

    C8. Function calling

    -

    O loop muda de "monte contents com functionResponse" para "envie um step function_result com call_id".

    -
    -
    -
    Antes — functionResponse em contents
    -
    resp = client.models.generate_content(
    -    model="gemini-3.5-flash",
    -    contents=contents,
    -    config=types.GenerateContentConfig(tools=[tool]),
    -)
    -fc = resp.candidates[0].content.parts[0].function_call
    -# ... executa ...
    -contents.append({"role": "user", "parts": [{
    -    "function_response": {
    -        "name": fc.name,
    -        "response": {"result": result},
    -    }}]})
    -final = client.models.generate_content(
    -    model="gemini-3.5-flash", contents=contents,
    -    config=types.GenerateContentConfig(tools=[tool]))
    -
    -
    -
    Depois — step function_result
    -
    i = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Weather in Boston?",
    -    tools=[tool],
    -)
    -fc = i.steps[-1]  # type == "function_call"
    -# ... executa ...
    -final = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    previous_interaction_id=i.id,
    -    tools=[tool],
    -    input=[{
    -        "type": "function_result",
    -        "name": fc.name,
    -        "call_id": fc.id,
    -        "result": [{"type": "text", "text": json.dumps(result)}],
    -    }],
    -)
    -print(final.output_text)
    -
    -
    -
    - Correspondência estrita (Gemini 3.x): todo function_result deve incluir o call_id (= id do call) e o name correspondente, e haver exatamente um resultado por chamada. A Interactions API retorna erro em mismatch (generateContent apenas degrada silenciosamente). -
    -
      -
    • Status intermediário: requires_action enquanto aguarda o function_result.
    • -
    • Respostas multimodais: inclua imagem/áudio dentro do result, não como parte separada.
    • -
    • Instruções extras: anexe ao final do texto do resultado, separadas por duas quebras de linha.
    • -
    • só em generateContent chamada automática de função (Python).
    • -
    -
    - -
    -

    C9. Structured Output (JSON)

    -
    -
    -
    Antes — response_schema
    -
    resp = client.models.generate_content(
    -    model="gemini-3.5-flash",
    -    contents="List 3 cookie recipes",
    -    config=types.GenerateContentConfig(
    -        response_mime_type="application/json",
    -        response_schema=Recipe,
    -    ),
    -)
    -print(resp.text)
    -
    -
    -
    Depois — response_format tipo text
    -
    i = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="List 3 cookie recipes",
    -    response_format={
    -        "type": "text",
    -        "mime_type": "application/json",
    -        "schema": {
    -            "type": "object",
    -            "properties": {
    -                "recipe_name": {"type": "string"},
    -                "ingredients": {
    -                    "type": "array",
    -                    "items": {"type": "string"}},
    -            },
    -            "required": ["recipe_name", "ingredients"],
    -        },
    -    },
    -)
    -print(i.output_text)
    -
    -
    -
      -
    • response_mime_type + response_schema → um único response_format tipo text com mime_type: "application/json" e schema.
    • -
    • Pode combinar JSON com ferramentas (Search, URL context, code execution, function calling) na mesma requisição em Gemini 3.x.
    • -
    -
    - -
    -

    C10. Thinking

    -
    -
    -
    Antes — thinking_budget
    -
    resp = client.models.generate_content(
    -    model="gemini-3.5-flash",
    -    contents="Prove sqrt(2) is irrational.",
    -    config=types.GenerateContentConfig(
    -        thinking_config=types.ThinkingConfig(
    -            thinking_budget=7500,
    -        ),
    -    ),
    -)
    -
    -
    -
    Depois — thinking_level
    -
    i = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Prove sqrt(2) is irrational.",
    -    generation_config={"thinking_level": "high"},
    -)
    -# thoughts aparecem como steps type=="thought"
    -for s in i.steps:
    -    if s.type == "thought":
    -        print(s.summary)
    -
    -
    -
      -
    • thinking_budget (numérico) → thinking_level (minimal|low|medium|high). Default em Gemini 3.5 Flash: medium.
    • -
    • Na Interactions API o raciocínio é exposto como steps thought com summary + signature, em ordem cronológica.
    • -
    • Preservação automática: o contexto de raciocínio é mantido entre turnos automaticamente (em generateContent é implícito, exigindo reenviar o histórico com signatures).
    • -
    -
    Nunca modifique blocos thought nem suas signature. Em modo store=false, reenvie-os exatamente como recebidos.
    -
    - -
    -

    C11. Caching

    -
    -
    -
    Antes — cache explícito
    -
    cache = client.caches.create(
    -    model="gemini-3.5-flash",
    -    config=types.CreateCachedContentConfig(
    -        contents=[big_document],
    -        ttl="3600s",
    -    ),
    -)
    -resp = client.models.generate_content(
    -    model="gemini-3.5-flash",
    -    contents="Summarize it",
    -    config=types.GenerateContentConfig(
    -        cached_content=cache.name),
    -)
    -
    -
    -
    Depois — cache implícito
    -
    # 1º turno com o documento grande no início
    -i1 = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input=[
    -      {"type": "document", "data": pdf_b64,
    -       "mime_type": "application/pdf"},
    -      {"type": "text", "text": "Read this."},
    -    ],
    -)
    -# turnos seguintes reaproveitam o cache automaticamente
    -i2 = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Summarize it",
    -    previous_interaction_id=i1.id,
    -)
    -
    -
    -
      -
    • Cache explícito (caches.create / cached_content) ainda é exclusivo de generateContent.
    • -
    • Na Interactions API, o cache é implícito: encadeie com previous_interaction_id e mantenha conteúdo estável no início do prompt.
    • -
    • Acompanhe o aproveitamento por usage.total_cached_tokens.
    • -
    -
    - - - -
    -

    C13. Streaming + Tools (acúmulo de argumentos)

    -

    Em streaming com function calling, os argumentos chegam fragmentados. Acumule e só faça parse no fim do step.

    -
    buffers = {}  # index -> string de argumentos
    -stream = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    input="Weather in Boston and Paris?",
    -    tools=[weather_tool],
    -    stream=True,
    -)
    -for event in stream:
    -    if event.event_type == "step.start" and event.step.type == "function_call":
    -        buffers[event.index] = ""
    -    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
    -        buffers[event.index] += event.delta.arguments
    -    elif event.event_type == "step.stop" and event.index in buffers:
    -        args = json.loads(buffers[event.index])  # parse só agora
    -        # ... despacha a função ...
    -
    Regra de ouro: nunca faça JSON.parse/json.loads em arguments_delta parcial — espere o step.stop do índice correspondente.
    -
    - -
    -

    C14. Tabela completa de mapeamento

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    generateContentInteractions APIObservação
    client.models.generate_content()client.interactions.create()Método principal.
    generate_content_stream()create(..., stream=True)Streaming.
    contentsinputString, blocos ou steps tipados.
    Content.parts[]content[] (blocos tipados)text/image/audio/document/video.
    role: "user"/"model"step user_input/model_outputPapéis viram tipos de step.
    config / GenerateContentConfiggeneration_configInteraction-scoped.
    system_instructionsystem_instructionReenviar a cada turno.
    response.textinteraction.output_textConveniência.
    imagem em partsinteraction.output_imageConveniência.
    candidates[]steps[]Timeline tipada.
    candidate.content.parts[]step.content[]—
    finish_reasoninteraction.statuscompleted/requires_action/…
    response_mime_type + response_schemaresponse_format (tipo text)mime_type + schema.
    response_modalities + image_configresponse_format (tipo image) ou arrayModalidades unificadas.
    thinking_config.thinking_budgetgeneration_config.thinking_levelEnum em vez de número.
    function_call (part)step function_call (id,name,arguments)—
    function_response (part)step function_result (call_id,name,result)Match estrito.
    tools=[Tool(google_search=...)]tools=[{"type":"google_search"}]Schema textual.
    grounding_metadatasteps *_call/*_result + annotationsurl_citation.
    caches.create + cached_contentprevious_interaction_id (cache implícito)Explícito ainda só em generateContent.
    histórico manual em contentsprevious_interaction_id (store=true)ou stateless com store=false.
    —background=true + cancel + webhooksTarefas longas / Deep Research.
    -
    -
    - -
    -

    C15. Checklist de migração

    -
      -
    • ☐ Atualizar SDK: google-genai >= 2.0.0 (Python) / @google/genai equivalente — obrigatório desde 08/06/2026 (SDKs 1.x falham).
    • -
    • ☐ Trocar models.generate_content → interactions.create.
    • -
    • ☐ contents → input; response.text → output_text.
    • -
    • ☐ Adotar previous_interaction_id para chat (ou manter store=false se gerencia histórico no cliente).
    • -
    • ☐ Migrar leitura de saída: candidates → steps; tratar status == requires_action.
    • -
    • ☐ Function calling: enviar function_result com call_id + name casados (1:1).
    • -
    • ☐ response_mime_type/response_schema/image_config → response_format.
    • -
    • ☐ thinking_budget → thinking_level; remover temperature/top_p/top_k (Gemini 3.x).
    • -
    • ☐ Atualizar nomes de eventos SSE (content.* → step.*, etc.).
    • -
    • ☐ Atualizar annotations para url_citation e grounding para search_suggestions.
    • -
    • ☐ Reduzir tool calls excessivos via thinking_level menor + instrução de orçamento de ferramentas.
    • -
    • ☐ Verificar recursos ausentes (Batch, cache explícito, video_metadata, auto-function-calling) — manter em generateContent se necessário.
    • -
    -
    Automação: agentes de código com skills (ex.: Antigravity) podem instalar a skill Gemini Interactions API e rodar /gemini-interactions-api migrate my app to Gemini 3.5 Flash.
    -
    - -
    -

    C16. Histórico sem estado (store=false)

    -

    Se você prefere gerenciar o histórico no cliente (sem persistência server-side), use store=false e reenvie a timeline completa como input (array de steps).

    -
    i = client.interactions.create(
    -    model="gemini-3.5-flash",
    -    store=False,
    -    input=[
    -        {"type": "user_input",
    -         "content": [{"type": "text", "text": "Hello!"}]},
    -        {"type": "model_output",
    -         "content": [{"type": "text", "text": "Hi! How can I help?"}]},
    -        {"type": "user_input",
    -         "content": [{"type": "text", "text": "Capital of France?"}]},
    -    ],
    -)
    -print(i.output_text)
    -
    Restrições do store=false: incompatível com background=true e impede usar previous_interaction_id nos turnos seguintes. Reenvie blocos thought/signature intactos.
    -
    - -
    -

    C17. Datas críticas & estratégia

    -
    - - - - - - - - -
    DataEventoAção
    30/11/2025Bibliotecas legadas descontinuadas (google-generativeai etc.).Migrar para google-genai / @google/genai.
    07/05/2026Novo schema disponível para opt-in.Envie Api-Revision: 2026-05-20 para testar.
    26/05/2026Novo schema virou padrão.Opt-out temporário era possível com Api-Revision: 2026-05-07 (janela encerrada).
    08/06/2026Schema legado removido (consumado); SDK 1.x falha.Estar em SDK v2.0.0+ e novo schema. Header Api-Revision é ignorado desde então.
    -
    -
    Janela encerrada: a remoção do schema legado foi consumada em 08/06/2026 — não há rollback e o header Api-Revision é ignorado. Chamadas em SDK 1.x ou no schema legado falham; se ainda não migrou, atualize para google-genai/@google/genai v2.0.0+ e o schema steps imediatamente.
    - -
    - -
    -

    Apêndice

    -
    - -
    -

    Ap1. Cookbook (notebooks oficiais)

    -

    Notebooks do repositório google-gemini/cookbook que usam a Interactions API (client.interactions.*), verificados em 2026-05-24.

    -
    - - - - - - - - -
    NotebookO que demonstra
    quickstarts/Get_started_interactions_api.ipynbGuia inicial da Interactions API: interface unificada modelo+agente, estado server-side, orquestração de ferramentas, texto, multi-turn e tool use.
    quickstarts/Get_started_Deep_Research.ipynbAgente Deep Research via Interactions API: criar interação long-running e fazer polling do status até concluir.
    quickstarts/Get_started_managed_agents.ipynbAgentes gerenciados/custom em VMs isoladas; continuação multi-turn via environment_id + previous_interaction_id.
    quickstarts/Webhooks.ipynbWebhooks para notificação de conclusão de operações assíncronas (inclui Interactions), evitando polling.
    -
    -
    - Ainda em generate_content (não migrados): Function_calling.ipynb, Streaming.ipynb, Caching.ipynb, JSON_mode.ipynb, Enum.ipynb e Get_started.ipynb usam a API legada — não os trate como exemplos de Interactions API. O quickstarts/README.md ainda não tem seção dedicada à Interactions API. -
    -
    - -
    -

    Ap2. Glossário

    -
    - - - - - - - - - - - - - - - -
    TermoDefinição
    InteractionRecurso central — uma rodada completa de execução (entradas, raciocínio, tool calls, saída) como timeline de steps.
    stepItem tipado da timeline (user_input, model_output, thought, *_call, *_result). Substitui candidates/outputs.
    previous_interaction_idID encadeado que ativa estado server-side e cache implícito do histórico.
    storePersistência da interação (default true; false = stateless).
    backgroundExecução assíncrona para tarefas longas; combinada com polling ou webhook.
    signatureHash de validação backend anexado a steps (thought, tool calls). Nunca modificar.
    thinking_levelEsforço de raciocínio: minimal|low|medium|high. Substitui thinking_budget.
    response_formatFormato de saída unificado (text/JSON, image, audio). Absorve response_mime_type + image_config.
    Api-RevisionHeader de versionamento do schema durante a transição de Maio/2026. Ignorado desde 08/06/2026 — o schema steps é o único aceito.
    Cache implícitoReaproveitamento automático do histórico quando se usa previous_interaction_id.
    Deep ResearchAgentes (deep-research-*) para pesquisa longa; sem function calling custom (use MCP) nem saída estruturada.
    -
    -
    - -
    -

    Ap3. Histórico deste guia

    -
      -
    • 2026-05-24 — Versão completa: Parte A (23 capítulos de conceitos/guias), Parte B (referência REST: endpoints, recursos, steps, tools, SSE, modelos/agentes, erros) e Parte C (17 cenários de migração antes/depois + breaking changes Maio/2026 + checklist + datas). Apêndice com cookbook verificado e glossário.
    • -
    • 2026-05-24 (revisão de modelos) — Padronização para apenas os modelos atuais: gemini-3.5-flash, gemini-3.1-pro-preview, gemini-3.1-flash-lite, gemini-3.1-flash-image (Nano Banana 2), TTS gemini-3.1-flash-tts-preview e Live gemini-3.1-flash-live-preview. Exceção: Computer Use usa gemini-3-flash-preview (suporte nativo) e gemini-2.5-computer-use-preview-10-2025 (dedicado), pois não há equivalente 3.5/3.1.
    • -
    • 2026-06-10 — Varredura de atualização: remoção do schema legado tratada como fato consumado em 08/06/2026 — steps[] é o único schema, header Api-Revision ignorado, janela de rollback fechada e SDKs google-genai/@google/genai 1.x quebrados para Interactions (mínimo agora: 2.0.0; último PyPI/npm: 2.8.0). Prosa de transição convertida para o passado (Sobre, TL;DR, §1.4, §2.2, §6, B2, B18, C2, C15, C17, glossário). Nuance adicionada: a página oficial migrate-to-interactions agora descreve a Interactions API como "the standard interface for building with Gemini" e a recomenda para todo desenvolvimento novo; a overview mantém Beta + generateContent para produção estável. Datas de verificação re-stampadas para 2026-06-10.
    • -
    • 2026-06-11 — Reorganização da doc oficial absorvida: a Interactions API ganhou seção própria (/docs/interactions/*) com novo quickstart (interactions/quickstart) e overview (interactions/interactions-overview); URLs de ferramentas/guias atualizadas para os caminhos canônicos /interactions/... (google-search, maps-grounding, code-execution, url-context, computer-use, file-search, tool-combination, webhooks, files, file-input-methods, media-resolution). Nova cobertura de agentes gerenciados: Antigravity agent (antigravity-preview-05-2026, §18.9), environments/sandboxes (§18.10), parâmetro environment/environment_id (§3.1) e AgentOption (B20). §18 renomeada para "Agentes: Deep Research & Antigravity". Reconfirmado na página de breaking changes: header Api-Revision ignorado e schema legado removido desde 08/06/2026 (exemplos oficiais ainda incluem o header; é no-op).
    • -
    • 2026-06-19 — Micro-sweep de superfície e versões. Adicionado caveat Developer API (Beta) vs Vertex / Gemini Enterprise Agent Platform (experimental) no topo (§1) e em §17.3: a Interactions API existe nas duas superfícies, mas code_execution dentro de Interactions é documentado/exemplificado só na Developer API; na Vertex a execução de código é documentada via generateContent e, em teste, code_execution via Interactions não funcionou sob auth Vertex (observação, não limitação oficial). Completada a limitação de MCP remoto (apenas Streamable HTTP; SSE não suportado; name sem hífen) em §1.5 e §22. Versões de SDK atualizadas para google-genai/@google/genai 2.9.0 — a 2.9.0 reimplementou a Interactions internamente mantendo a API pública compatível.
    • -
    -

    Fontes primárias: ai.google.dev/gemini-api/docs/interactions/interactions-overview, interactions/quickstart, ai.google.dev/api/interactions-api, interactions-breaking-changes-may-2026, migrate-to-interactions, docs/agents/antigravity-agent/agent-environment e github.com/google-gemini/cookbook; superfície Vertex em docs.cloud.google.com/gemini-enterprise-agent-platform/reference/models/interactions-api e .../models/tools/code-execution. Verificado em 2026-06-19 — para fatos perecíveis (modelos, datas, limites), consulte sempre a fonte oficial.

    -
    - - -
    -
    - - - - - - + + + + + +Guia Gemini Interactions API — Referência completa + Migração de generateContent + + + + + + + + +
    +
    +
    Guia Gemini Interactions API PT-BR · Referência completa + Migração
    +
    + Verificado em 2026-07-12 + google-genai + GA + +
    +
    +
    + +
    + + +
    + +
    +

    Guia Gemini Interactions API — Referência completa + Migração

    +

    + Documentação técnica exaustiva da Gemini Interactions API + (GA desde junho/2026 — a interface recomendada por padrão para novos projetos), + sucessora do método generateContent. + Cobre a anatomia da Interaction (timeline de steps), + texto, streaming SSE, multimodal (imagem/áudio/vídeo/PDF), + function calling, structured output, thinking, caching, Deep Research, + ferramentas server-side (Google Search, Maps, Code Execution, URL Context, + File Search, Computer Use, MCP), background tasks, webhooks + e a referência REST completa, além de uma seção dedicada com mapeamento + antes/depois e breaking changes de Maio 2026. +

    +

    + ⭐ Destaque: a Interactions API é agora GA (junho/2026) e o caminho + SOTA recomendado pela Google para todo projeto novo. Modelos recomendados: + gemini-3.5-flash (Flash estável, padrão) e gemini-3.1-pro-preview + (reasoning/multimodal avançado). SDK google-genai ≥ 2.0.0 (último 2.11.0). +

    +
    + google-genai · Python ≥ 2.0.0 (último 2.11.0) + @google/genai · JS ≥ 2.0.0 (último 2.11.0) + GA · jun/2026 + SOTA · 2026-06-29 + Schema steps · Api-Revision ignorado +
    +
    + +
    +

    Sobre este guia

    +

    + Este é um guia técnico exaustivo, em português brasileiro, da nova + Google Gemini Interactions API — a interface padrão recomendada + pela Google para novos projetos agênticos, conversas multiturno com estado + no servidor e fluxos com ferramentas. O método generateContent + continua suportado, mas a migração é incentivada e várias capacidades novas + (Deep Research, novos modelos da família Gemini 3.x) chegam apenas via Interactions. +

    +

    O guia é organizado em três partes e um apêndice:

    +
      +
    • Parte A — Conceitos & Guias: explica cada capacidade da API + com exemplos em Python, JavaScript e REST, no formato encontrado na documentação oficial.
    • +
    • Parte B — Referência REST: enumera todos os endpoints, schemas, + enums, tipos de step, tipos de content, tipos de tool e eventos SSE.
    • +
    • Parte C — Migração: par-a-par de antes (generateContent) + e depois (Interactions), tabela completa de mapeamento, + checklist e as breaking changes oficiais de Maio 2026.
    • +
    • Apêndice: notebooks do cookbook, glossário e histórico do guia.
    • +
    +
    + Como ler: cada capítulo expõe Python, JS e REST em paralelo, + preservando exatamente os exemplos oficiais. Se um detalhe divergir do + publicado em ai.google.dev, a documentação oficial é a fonte autoritativa. +
    +
    + Status: GA (junho/2026). A Interactions API é agora + generally available e a interface recomendada por padrão para + todo desenvolvimento novo — a própria landing page da Gemini API + recomenda interactions.create para novos projetos. Importante: o + endpoint permanece em /v1beta/interactions — o rótulo GA não + promoveu o caminho para /v1/. O conjunto de breaking changes de + Maio 2026 (ver seção dedicada) + já foi consumado em 08/06/2026: a matriz outputs foi + substituída por steps, os eventos SSE foram renomeados, + response_format absorveu response_mime_type e + image_config, o schema legado foi removido permanentemente, o header + Api-Revision passou a ser ignorado (a janela de rollback + com Api-Revision: 2026-05-07 fechou nessa data) e os SDKs 1.x falham nas + chamadas de Interactions. O método generateContent continua suportado, + mas várias capacidades novas (Deep Research, agentes gerenciados) chegam só via Interactions. +
    +
    + Superfície: Developer API (GA) vs Vertex / Gemini Enterprise Agent Platform (experimental). + Toda a documentação desta página e os exemplos REST abaixo usam a + Gemini Developer API (AI Studio): endpoint + generativelanguage.googleapis.com/v1beta/interactions e header + x-goog-api-key com chave do + AI Studio. + A Interactions API também existe na Vertex AI / Gemini Enterprise Agent Platform + (endpoint aiplatform.googleapis.com/v1beta1/projects/{project}/locations/global/interactions, + auth OAuth/ADC), porém rotulada como experimental — status diferente do + GA da Developer API. Nem toda ferramenta tem paridade documentada entre as duas: + code_execution dentro de Interactions é documentado/exemplificado só na Developer API; + na Vertex a execução de código é documentada via generateContent (ver + §17.3 e o guia de code tools). + Em produção na Vertex, valide a disponibilidade de cada recurso antes de migrar de + generateContent para Interactions. + Verificado em 2026-06-29, fontes oficiais Google. +
    +
    + +
    +

    Fontes oficiais

    + +

    + Última verificação contra estas fontes: 2026-06-19. + Sempre que houver divergência entre este guia e a documentação oficial em + produção, a documentação oficial é a fonte autoritativa. Capturas literais + de exemplos e tabelas preservam a acentuação PT-BR original. +

    +
    + +
    +

    TL;DR · Migração rápida

    +

    Se você já usa generateContent e precisa migrar, decore estes pontos:

    +
    + + + + + + + + + + + + + + + + + + + +
    AspectogenerateContent (legado)Interactions API (novo)
    EndpointPOST /v1beta/models/{model}:generateContentPOST /v1beta/interactions
    Streaming:streamGenerateContentmesmo endpoint + "stream": true
    Históricocliente reenvia array contentsservidor mantém via previous_interaction_id
    Resposta textoresponse.candidates[0].content.parts[0].textinteraction.output_text
    Estrutura da respostacandidates[].content.parts[]steps[] tipados
    Schema estruturadogenerationConfig.responseFormatresponse_format (top-level)
    Image configgeneration_config.image_configresponse_format: {type:"image", ...}
    Toolstools=[{google_search:{}}]tools=[{"type":"google_search"}]
    Function declaration{name, description, parameters} aninhado em function_declarations{"type":"function", name, description, parameters} direto em tools
    Function call IDnão garantidostep.id obrigatório (Gemini 3)
    CitaçõesgroundingMetadata.groundingSupports com índicesannotations[] inline em content[].annotations
    Tasks longasnão suportadasbackground=true + webhook_config
    Retençãon/a (stateless)55 dias pago / 1 dia free (padrão store=true)
    SDK Python mínimoqualquer google-genai≥ 2.0.0 (obrigatório desde 08/06/2026; SDKs 1.x falham nas chamadas de Interactions)
    SDK JS mínimoqualquer @google/genai≥ 2.0.0 (obrigatório desde 08/06/2026; SDKs 1.x falham nas chamadas de Interactions)
    +
    +
    + Datas críticas (Breaking changes Maio 2026): +
      +
    • 07/05/2026 — SDKs Python 2.0.0 e JS 2.0.0 publicados. Opt-in via cabeçalho Api-Revision: 2026-05-20.
    • +
    • 26/05/2026 — Novo schema virou padrão; rollback temporário possível via Api-Revision: 2026-05-07 (janela já encerrada).
    • +
    • 08/06/2026 — Schema legado removido permanentemente (consumado). Headers de rollback ignorados; SDKs 1.x falham.
    • +
    +
    +

    Detalhes completos em Parte C — Migração.

    +
    + + + + + + +
    +

    Parte A — Conceitos & Guias

    +

    Capítulos 1–23 cobrindo todos os conceitos públicos da Gemini Interactions API, em ordem de leitura recomendada da documentação oficial. Exemplos em Python (google-genai), JavaScript (@google/genai) e REST/cURL.

    +
    + +
    +

    1. Visão geral da Interactions API

    + +

    A API Interactions é a nova interface padrão do Gemini para fluxos agênticos, conversas multiturno com estado server-side e operações longas. Está em Beta e seus esquemas estão sujeitos a mudanças incompatíveis (ver breaking changes de Maio 2026). O método generateContent continua funcional e suportado, mas novos recursos (Deep Research, novos modelos da família Gemini 3.x exclusivos) chegam apenas via Interactions.

    + +

    1.1 Por que usar a Interactions API

    +
      +
    • Gerenciamento de histórico server-side: conversa multiturno via previous_interaction_id. O servidor ativa estado por padrão (store=true); para modo stateless, defina store=false.
    • +
    • Etapas de execução observáveis: a resposta é uma timeline tipada de steps (thought, function_call, function_result, model_output, google_search_call, etc.), facilitando depuração e renderização de UI para eventos intermediários.
    • +
    • Criado para fluxos agênticos: orquestração nativa multi-turno com ferramentas.
    • +
    • Tarefas longas em background: background=true habilita operações assíncronas (Deep Think, Deep Research) com integração a webhooks.
    • +
    • Acesso exclusivo a novos modelos: agentes Deep Research e outros lançamentos saem direto na Interactions.
    • +
    + +

    1.2 Quando usar cada API

    +
    + + + + + + + + +
    SituaçãoAPI recomendada
    Novo projeto ou aplicação agênticaInteractions API
    Integração existente em produção estávelgenerateContent
    Recursos ainda não disponíveis em Interactions (Batch, cache explícito)generateContent
    Deep Research, agentes nativos, background tasksInteractions API
    +
    +
    + Atualização (2026-06-10): a página oficial de migração + (migrate-to-interactions) + agora descreve a Interactions API como "the standard interface for building with Gemini" + e a recomenda para todo desenvolvimento novo. A página de visão geral mantém + o aviso de Beta e generateContent como caminho estável para produção — a tabela + acima reflete as duas fontes. +
    + +

    1.3 Propriedades de conveniência do SDK

    +
    + + + + + + + +
    PropriedadeTipoDescrição
    interaction.output_textstringÚltimos blocos TextContent consecutivos unidos automaticamente. Não captura texto separado por pensamentos, imagens, áudio ou tool calls.
    interaction.output_imageImageContent ou NoneÚltimo bloco de imagem gerado pelo modelo.
    interaction.output_audioAudioContent ou NoneÚltimo bloco de áudio gerado pelo modelo.
    +
    +
    + Quando iterar manualmente: para inspecionar pensamentos, function calls ou conteúdo intercalado (texto + imagem + áudio), itere interaction.steps. +
    + +

    1.4 SDKs & versões mínimas

    +
    + + + + + + + + + +
    LinguagemPacoteVersão mínimaInstalação
    Python (≥ 3.9)google-genai2.0.0 (SDKs 1.x falham desde 08/06/2026; último PyPI: 2.11.0)pip install -U google-genai
    JavaScript / TypeScript (Node ≥ 18)@google/genai2.0.0 (SDKs 1.x falham desde 08/06/2026; último npm: 2.11.0)npm install @google/genai
    Gogoogle.golang.org/genai—go get google.golang.org/genai
    Javacom.google.genai:google-genai1.0.0Maven artifact
    C#Google.GenAI—dotnet add package Google.GenAI
    +
    +

    Nota (2026-07-12): o último google-genai / @google/genai é 2.11.0 (ambos; 2026-07-09). A 2.9.0 reimplementou a Interactions internamente mantendo a API pública compatível e a 2.10.0/2.11.0 seguem compatíveis, então os exemplos deste guia seguem válidos; mantenha o piso prático ≥ 2.0.0 (1.x falha desde 08/06/2026).

    +
    + Bibliotecas legadas descontinuadas em 30/11/2025: + google-generativeai (Python), @google/generativeai (JS), google.golang.org/generative-ai (Go), + google_generative_ai (Dart), generative-ai-swift, generative-ai-android. + Para Dart/Flutter e mobile (Swift/Android), a recomendação oficial passa a ser Firebase AI Logic, + e não o SDK google-genai. +
    + +

    1.5 Limitações conhecidas (vs. generateContent)

    +

    Recursos ainda ausentes em Interactions API (presentes em generateContent):

    +
      +
    • Metadados de vídeo (video_metadata: intervalos de corte, FPS customizado).
    • +
    • Batch API assíncrona em lote.
    • +
    • Chamada automática de função (Python apenas).
    • +
    • Cache explícito — porém cache implícito via previous_interaction_id está disponível.
    • +
    • MCP Remoto com Gemini 3 — "Gemini 3 não é compatível com MCP remoto, mas isso vai mudar em breve" (doc oficial). Além disso, apenas servidores Streamable HTTP são suportados — servidores baseados em SSE não são (e o name do servidor não pode conter -, use snake_case).
    • +
    + + +
    + +
    +

    2. Quickstart & SDKs

    + +

    2.1 Chave de API

    +

    Obtenha uma chave em aistudio.google.com/app/apikey. Em ambientes Python/JS o SDK lê automaticamente a variável GEMINI_API_KEY:

    +
    # macOS / Linux
    +export GEMINI_API_KEY="sk-..."
    +
    +# Windows PowerShell
    +$env:GEMINI_API_KEY = "sk-..."
    +
    +# Windows CMD
    +set "GEMINI_API_KEY=sk-..."
    + +

    2.2 Instalação

    +
    # Mínimo para usar a Interactions API hoje (schema steps, único desde 08/06/2026):
    +pip install -U "google-genai>=2.0.0"             # Python (último PyPI: 2.11.0)
    +npm install "@google/genai@>=2.0.0"              # Node / TypeScript (último npm: 2.11.0)
    +
    +# SDKs 1.x (google-genai < 2.0.0 / @google/genai < 2.0.0) falham nas
    +# chamadas de Interactions desde 08/06/2026 — schema legado removido.
    + +

    2.3 Primeira interação (Hello world)

    +

    Python

    +
    from google import genai
    +
    +client = genai.Client()
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="How does AI work?"
    +)
    +print(interaction.output_text)
    + +

    JavaScript

    +
    import { GoogleGenAI } from "@google/genai";
    +
    +const ai = new GoogleGenAI({});
    +
    +const interaction = await ai.interactions.create({
    +  model: "gemini-3.5-flash",
    +  input: "How does AI work?",
    +});
    +console.log(interaction.output_text);
    + +

    REST

    +
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H 'Content-Type: application/json' \
    +  -H "Api-Revision: 2026-05-20" \
    +  -d '{
    +    "model": "gemini-3.5-flash",
    +    "input": "How does AI work?"
    +  }'
    + +
    + Header Api-Revision (histórico): entre 07/05/2026 e 26/05/2026 ele controlou o opt-in no novo schema (2026-05-20) e, até 08/06/2026, o rollback temporário (2026-05-07). Desde 08/06/2026 o header é ignorado e pode ser omitido das chamadas — o schema steps é o único aceito. Os exemplos REST da doc oficial (incl. o novo quickstart) ainda o incluem; enviá-lo é inofensivo (no-op). +
    + + +
    + +
    +

    3. Anatomia de uma Interaction

    + +

    O recurso central da API é o objeto Interaction. Ele encapsula uma rodada completa de execução: as entradas do usuário, qualquer raciocínio (thoughts), chamadas de ferramentas, resultados e a resposta final do modelo — tudo organizado em uma timeline ordenada chamada steps.

    + +

    3.1 Campos principais

    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoDescrição
    idstringIdentificador único (v1_...) usado em previous_interaction_id.
    objectstringSempre "interaction".
    modelModelOptionID do modelo (ex.: gemini-3.5-flash). Obrigatório se agent não for fornecido.
    agentAgentOptionID do agente (ex.: deep-research-preview-04-2026, antigravity-preview-05-2026). Obrigatório se model não for fornecido.
    environment / environment_idstring | EnvironmentConfigSandbox de agente gerenciado: "remote" (novo), "env_..." (reuso) ou config completa. A resposta traz environment_id. Usado com agent (ver §18.9–18.10).
    statusInteractionStatusUm de in_progress, requires_action, completed, failed, cancelled, incomplete, budget_exceeded.
    created / updatedstring ISO 8601Timestamps.
    stepsStep[]Timeline ordenada de etapas (ver §3.2).
    inputContent / Content[] / Step[] / stringEntrada (texto livre, lista de blocks ou lista de steps em modo stateless).
    toolsTool[]Lista de ferramentas disponíveis para esta interação.
    response_formatResponseFormat / listConfigura saída estruturada e modalidades de resposta.
    system_instructionstringInstrução de sistema (precisa ser reespecificada por turno).
    generation_configGenerationConfigParâmetros de inferência (temperature, thinking_level, tool_choice, etc.).
    previous_interaction_idstringID da interação anterior para continuar o histórico.
    storebooleanArmazenamento server-side. Padrão true.
    backgroundbooleanExecuta em segundo plano (incompatível com store=false).
    webhook_configWebhookConfigURIs para notificação assíncrona.
    service_tierServiceTierflex | standard | priority.
    usageUsageContagem de tokens (entrada, saída, cache, thinking, ferramentas) por modalidade.
    +
    + +

    3.2 Tipos de step

    +

    Cada elemento de steps tem um campo type que discrimina seu papel. Veja a referência completa em Parte B — Step types. Os tipos mais comuns:

    +
    + + + + + + + + + + + + + + + +
    typeQuando apareceCampos principais
    user_inputApenas em GET /interactions/{id} com include_input=truecontent[]
    model_outputResposta final do modelocontent[] (text, image, audio, ...)
    thoughtRaciocínio interno (Gemini 3.x)signature, summary
    function_callModelo solicita execução de função do clienteid, name, arguments, signature
    function_resultCliente devolve resultadocall_id, name, result, is_error
    google_search_call / google_search_resultGrounding com Pesquisa Googlearguments.queries, result.search_suggestions
    code_execution_call / code_execution_resultExecução server-side de Pythonarguments.code, result, is_error
    url_context_call / url_context_resultLeitura de URLsarguments.urls, result.status
    google_maps_call / google_maps_resultGrounding com Google Mapsarguments.queries, result.places, widget_context_token
    file_search_call / file_search_resultRAG sobre File Search Storesid, call_id
    mcp_server_tool_call / mcp_server_tool_resultTool externa via MCP HTTP Streamingserver_name, name, arguments, result
    +
    + +

    3.3 Blocos de conteúdo (Content)

    +

    Dentro de step.content[] (e dentro de input multimodal) cada bloco tem type:

    +
    { "type": "text",     "text": "..." , "annotations": [ ... ] }
    +{ "type": "image",    "data": "<base64>",     "mime_type": "image/jpeg" }
    +{ "type": "image",    "uri":  "files/abc...",  "mime_type": "image/png"  }
    +{ "type": "audio",    "data": "<base64>",     "mime_type": "audio/mp3", "sample_rate": 16000, "channels": 1 }
    +{ "type": "document", "uri":  "files/abc...",  "mime_type": "application/pdf" }
    +{ "type": "video",    "uri":  "https://www.youtube.com/watch?v=..." }
    +{ "type": "video",    "uri":  "files/abc...",  "mime_type": "video/mp4", "resolution": "low" }
    + +

    3.4 Exemplo de resposta completa

    +
    {
    +  "id": "v1_ChdPU0F4YWFtNkFwS2kxZThQZ05lbXdROBIXT1NBeGFhbTZBcEtpMWU4UGdOZW13UTg",
    +  "object": "interaction",
    +  "model": "gemini-3.5-flash",
    +  "status": "completed",
    +  "created": "2025-11-26T12:25:15Z",
    +  "updated": "2025-11-26T12:25:15Z",
    +  "steps": [
    +    { "type": "thought",      "signature": "abc123..." },
    +    { "type": "model_output", "content": [
    +        { "type": "text", "text": "Hello! I'm functioning perfectly and ready to assist you.\n\nHow are you doing today?" }
    +    ]}
    +  ],
    +  "usage": {
    +    "input_tokens_by_modality": [{ "modality": "text", "tokens": 7 }],
    +    "total_input_tokens": 7,
    +    "total_output_tokens": 20,
    +    "total_thought_tokens": 22,
    +    "total_tokens": 49,
    +    "total_tool_use_tokens": 0,
    +    "total_cached_tokens": 0
    +  }
    +}
    + + +
    + +
    +

    4. Geração de texto

    + +

    A operação mais básica da Interactions API: enviar uma string ou lista de blocos como input e receber uma Interaction com a resposta nos steps.

    + +

    4.1 Exemplo mínimo

    +

    Python

    +
    from google import genai
    +
    +client = genai.Client()
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="How does AI work?"
    +)
    +print(interaction.output_text)
    + +

    JavaScript

    +
    import { GoogleGenAI } from "@google/genai";
    +
    +const ai = new GoogleGenAI({});
    +
    +const interaction = await ai.interactions.create({
    +  model: "gemini-3.5-flash",
    +  input: "How does AI work?",
    +});
    +console.log(interaction.output_text);
    + +

    REST

    +
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H 'Content-Type: application/json' \
    +  -H "Api-Revision: 2026-05-20" \
    +  -d '{
    +    "model": "gemini-3.5-flash",
    +    "input": "How does AI work?"
    +  }'
    + +

    4.2 System instruction

    +

    Use system_instruction para definir persona, política ou contexto. Lembre-se: instruções de sistema têm escopo por interação — você precisa reespecificá-las em cada turno (mesmo com previous_interaction_id) se quiser mantê-las.

    + +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    system_instruction="You are a cat. Your name is Neko.",
    +    input="Hello there"
    +)
    +print(interaction.output_text)
    + +

    4.3 Configuração de geração

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Explain how AI works",
    +    generation_config={
    +        "temperature": 1.0,
    +        "top_p": 0.95,
    +        "max_output_tokens": 1024,
    +        "stop_sequences": ["END"],
    +        "seed": 42
    +    }
    +)
    + +

    4.4 Pensando com o Gemini (thinking_level)

    +

    Nos modelos Gemini 3.x é possível ajustar o esforço de raciocínio. Veja a seção Thinking para a tabela completa de valores aceitos por modelo.

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="How does AI work?",
    +    generation_config={"thinking_level": "low"}
    +)
    +print(interaction.output_text)
    + +

    4.5 Entrada multimodal (imagem + texto)

    +
    from google import genai
    +client = genai.Client()
    +
    +uploaded_file = client.files.upload(file="path/to/organ.jpg")
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "text", "text": "Tell me about this instrument"},
    +        {"type": "image", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
    +    ]
    +)
    +print(interaction.output_text)
    + +

    4.6 Parâmetros principais

    +
    + + + + + + + + + + + + + + + +
    ParâmetroTipoDescrição
    modelstringModelo Gemini (ver ModelOption).
    inputstring · Content[] · Step[]Texto livre ou blocos multimodais.
    system_instructionstringInstrução de sistema.
    generation_configobjecttemperature, top_p, seed, thinking_level, max_output_tokens, stop_sequences...
    toolsTool[]Função, Google Search, Code Execution, etc.
    response_formatobject · arrayEstrutura de saída e modalidades.
    streambooleanSSE incremental.
    previous_interaction_idstringContinua histórico server-side.
    storebooleanPadrão true (servidor mantém estado).
    backgroundbooleanExecução assíncrona (Deep Research, Deep Think).
    service_tierstringflex · standard · priority.
    +
    + + +
    + +
    +

    5. Conversas multiturno

    + +

    A Interactions API gerencia o histórico no servidor por padrão. Para continuar uma conversa, basta passar o id da interação anterior em previous_interaction_id. Não é mais necessário reenviar o array contents inteiro como no generateContent.

    + +

    5.1 Padrão server-side (recomendado)

    +

    Python

    +
    from google import genai
    +
    +client = genai.Client()
    +
    +interaction1 = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="I have 2 dogs in my house.",
    +)
    +print(interaction1.output_text)
    +
    +interaction2 = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="How many paws are in my house?",
    +    previous_interaction_id=interaction1.id,
    +)
    +print(interaction2.output_text)
    + +

    JavaScript

    +
    const interaction1 = await ai.interactions.create({
    +  model: "gemini-3.5-flash",
    +  input: "I have 2 dogs in my house.",
    +});
    +
    +const interaction2 = await ai.interactions.create({
    +  model: "gemini-3.5-flash",
    +  input: "How many paws are in my house?",
    +  previous_interaction_id: interaction1.id,
    +});
    +console.log(interaction2.output_text);
    + +

    REST

    +
    RESPONSE1=$(curl -s -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H 'Content-Type: application/json' \
    +  -H "Api-Revision: 2026-05-20" \
    +  -d '{ "model": "gemini-3.5-flash", "input": "I have 2 dogs in my house." }')
    +
    +INTERACTION_ID=$(echo "$RESPONSE1" | jq -r '.id')
    +
    +curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H 'Content-Type: application/json' \
    +  -H "Api-Revision: 2026-05-20" \
    +  -d '{
    +    "model": "gemini-3.5-flash",
    +    "input": "How many paws are in my house?",
    +    "previous_interaction_id": "'$INTERACTION_ID'"
    +  }'
    + +
    + Parâmetros com escopo por interação: ao usar previous_interaction_id, alguns parâmetros precisam ser reespecificados a cada turno se ainda forem desejados — tools, system_instruction e generation_config (inclui thinking_level, temperature). +
    + +

    5.2 Modo sem estado (store=false)

    +

    Para conformidade ou casos onde você não quer armazenamento server-side, defina store=false. Nesse modo você é responsável por reenviar TODOS os steps gerados (incluindo thought com signature) em cada turno — caso contrário a continuidade de raciocínio quebra.

    +
    history = [
    +    {"type": "user_input", "content": [{"type": "text", "text": "I have 2 dogs."}]}
    +]
    +
    +interaction1 = client.interactions.create(
    +    model="gemini-3.5-flash", store=False, input=history
    +)
    +
    +for step in interaction1.steps:
    +    history.append(step.model_dump())
    +
    +history.append({
    +    "type": "user_input",
    +    "content": [{"type": "text", "text": "How many paws are in my house?"}]
    +})
    +
    +interaction2 = client.interactions.create(
    +    model="gemini-3.5-flash", store=False, input=history
    +)
    +print(interaction2.steps[-1].content[0].text)
    + +
    + Restrições de store=false: +
      +
    • Incompatível com background=true (Deep Research exige store=true).
    • +
    • Impede usar a interação como previous_interaction_id em chamadas subsequentes.
    • +
    • Você precisa preservar e reenviar todas as etapas geradas pelo modelo — incluindo assinaturas de thought.
    • +
    +
    + + +
    + +
    +

    6. Streaming (SSE)

    + +

    O streaming usa o mesmo endpoint POST /v1beta/interactions, apenas adicionando "stream": true no body. A resposta é um fluxo Server-Sent Events com eventos tipados por step. Não há mais o endpoint dedicado :streamGenerateContent.

    + +
    Transporte: a Interactions API é HTTP request-response (com estado no servidor via previous_interaction_id) e o streaming é SSE sobre HTTP — não há WebSocket nesse caminho. Interação bidirecional em tempo real (voz/vídeo, áudio-para-áudio) é a Live API sobre WebSocket (WSS, BidiGenerateContent, modelos como gemini-3.1-flash-live-preview) — uma superfície separada da Interactions API.
    + +

    6.1 Streaming básico

    +

    Python

    +
    stream = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Count from 1 to 25.",
    +    stream=True,
    +)
    +for event in stream:
    +    if event.event_type == "step.delta":
    +        if event.delta.type == "text":
    +            print(event.delta.text, end="", flush=True)
    + +

    JavaScript

    +
    const stream = await client.interactions.create({
    +  model: "gemini-3.5-flash",
    +  input: "Count from 1 to 25.",
    +  stream: true,
    +});
    +for await (const event of stream) {
    +  if (event.event_type === "step.delta" && event.delta.type === "text") {
    +    process.stdout.write(event.delta.text);
    +  }
    +}
    + +

    REST (SSE)

    +
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions?alt=sse" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -H "Api-Revision: 2026-05-20" \
    +  --no-buffer \
    +  -d '{
    +    "model": "gemini-3.5-flash",
    +    "input": "Count from 1 to 25.",
    +    "stream": true
    +  }'
    + +

    6.2 Tipos de evento SSE

    +
    + + + + + + + + + + + +
    event_typeCarga principalQuando
    interaction.createdinteraction (id, status, model)Início do stream.
    interaction.status_updateinteraction_id, statusMudança de status. O campo status carrega o enum in_progress/requires_action/completed/failed/cancelled/incomplete/budget_exceeded (ver B8). Não existem eventos interaction.in_progress ou interaction.requires_action separados — essas são apenas valores de status.
    step.startindex, stepInicia um step (tipo: thought, model_output, function_call, etc.).
    step.deltaindex, deltaTrecho incremental do step atual.
    step.stopindexStep finalizado.
    interaction.completedinteraction com usageFinal do stream com contagem de tokens.
    errorerror.code, error.messageErro em tempo de execução.
    +
    +
    + Conjunto canônico de eventos SSE — schema novo (default desde 26/05/2026): interaction.created, interaction.in_progress, + interaction.requires_action, interaction.completed, step.start, step.delta, step.stop (mais error). No schema vigente, + interaction.in_progress e interaction.requires_action são eventos SSE distintos (cada um com seu event_type). O evento legado + interaction.status_update — que carregava o status num único evento — foi substituído por eles e foi removido junto do schema legado em 08/06/2026. + Verificado 2026-06-03 contra interactions-breaking-changes-may-2026#streaming (corrige a leitura anterior, baseada no schema legado). Os eventos de webhook (§19) são um namespace à parte e incluem + interaction.requires_action/cancelled. +
    + +

    6.3 Tipos de delta em step.delta

    +
    + + + + + + + + + + + + + +
    delta.typeCamposOnde aparece
    texttextmodel_output
    imagedata, uri, mime_type, resolutionmodel_output
    audiodata, uri, mime_type, sample_rate, channelsmodel_output
    documentdata, uri, mime_typemodel_output
    videodata, uri, mime_type, resolutionmodel_output
    thought_summarycontent (texto/imagem)thought
    thought_signaturesignaturethought (último delta)
    arguments_deltaarguments (string JSON parcial)function_call — exige acumulação até step.stop
    text_annotation_deltaannotations[]model_output (citações inline)
    +
    + +

    6.4 Exemplo de fluxo SSE completo

    +
    event: interaction.created
    +data: {"interaction":{"id":"v1_...","status":"in_progress","object":"interaction","model":"gemini-3.5-flash"},"event_type":"interaction.created"}
    +
    +event: interaction.in_progress
    +data: {"interaction_id":"v1_...","status":"in_progress","event_type":"interaction.in_progress"}
    +
    +event: step.start
    +data: {"index":0,"step":{"type":"thought"},"event_type":"step.start"}
    +
    +event: step.delta
    +data: {"index":0,"delta":{"signature":"...","type":"thought_signature"},"event_type":"step.delta"}
    +
    +event: step.stop
    +data: {"index":0,"event_type":"step.stop"}
    +
    +event: step.start
    +data: {"index":1,"step":{"type":"model_output"},"event_type":"step.start"}
    +
    +event: step.delta
    +data: {"index":1,"delta":{"text":"1, 2, 3, 4, 5, 6, ","type":"text"},"event_type":"step.delta"}
    +
    +event: step.delta
    +data: {"index":1,"delta":{"text":"7, 8, 9, 10","type":"text"},"event_type":"step.delta"}
    +
    +event: step.stop
    +data: {"index":1,"event_type":"step.stop"}
    +
    +event: interaction.completed
    +data: {"interaction":{"id":"v1_...","status":"completed","usage":{"total_tokens":346,"total_input_tokens":11,"total_output_tokens":90,"total_thought_tokens":245}},"event_type":"interaction.completed"}
    +
    +event: done
    +data: [DONE]
    + +

    6.5 Streaming com function calling

    +

    Diferente do generateContent, function calls em streaming chegam em partes: step.start entrega name e id, e cada step.delta com delta.type == "arguments_delta" traz um fragmento em delta.arguments (string JSON) que você precisa acumular até o step.stop.

    + +
    stream = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="What is the weather in Paris?",
    +    tools=[weather_tool],
    +    stream=True
    +)
    +
    +current_calls = {}
    +for event in stream:
    +    if event.event_type == "step.start" and event.step.type == "function_call":
    +        current_calls[event.index] = {
    +            "id": event.step.id,
    +            "name": event.step.name,
    +            "arguments": ""
    +        }
    +    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
    +        if event.index in current_calls:
    +            current_calls[event.index]["arguments"] += event.delta.arguments
    +
    +# Após interaction.completed, parse final
    +import json
    +for index, call in current_calls.items():
    +    call["arguments"] = json.loads(call["arguments"]) if call["arguments"] else {}
    +print(current_calls)
    + +

    6.6 Streaming com thinking summaries

    +
    stream = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="What is the greatest common divisor of 1071 and 462?",
    +    generation_config={"thinking_summaries": "auto"},
    +    stream=True,
    +)
    +for event in stream:
    +    if event.event_type == "step.delta":
    +        if event.delta.type == "thought_summary":
    +            if event.delta.content.type == "text":
    +                print(f"[Thought] {event.delta.content.text}", end="")
    +        elif event.delta.type == "text":
    +            print(event.delta.text, end="")
    + +

    6.7 Streaming de geração de imagem

    +
    stream = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="Search the history of the Colosseum and write a short illustrated story.",
    +    tools=[{"type": "google_search", "search_types": ["web_search", "image_search"]}],
    +    response_format=[{"type": "text"}, {"type": "image"}],
    +    stream=True,
    +)
    +for event in stream:
    +    if event.event_type == "step.delta":
    +        if event.delta.type == "text":
    +            print(event.delta.text, end="")
    +        elif event.delta.type == "image":
    +            print(f"[Image chunk: {len(event.delta.data)} bytes]")
    + +
    + Eventos desconhecidos: a política de versionamento da API admite novos tipos de eventos ao longo do tempo. Seu cliente deve registrar e pular tipos desconhecidos em vez de gerar erros. +
    + + +
    + +
    +

    7. Geração de imagens

    + +

    Modelos da família Nano Banana geram imagens nativamente como parte do fluxo Interactions. A imagem retorna como bloco image dentro de steps[].content[] e pode ser acessada via interaction.output_image.

    + +

    7.1 Modelos disponíveis

    +
    + + + + + + +
    Nome comercialModel IDFoco
    Nano Banana 2gemini-3.1-flash-imageGA desde 28/05/2026 (saiu de preview; o ID -preview é desligado em 25/06/2026). Geração/edição de imagem de alta eficiência e alto volume; suporta thinking_level e saída intercalada texto+imagem
    Nano Banana Progemini-3-pro-imageGA desde 28/05/2026. Qualidade máxima (estúdio): tipografia/texto precisos, composições complexas, até 4K; aceita mais imagens de referência por prompt
    +
    +

    Todas as imagens geradas incluem marca d'água SynthID.

    + +

    7.2 Limites técnicos

    +
      +
    • Aspect ratios: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9. Apenas gemini-3.1-flash-image: 1:4, 4:1, 1:8, 8:1.
    • +
    • Resoluções: 0.5K (apenas Flash 3.1), 1K (padrão), 2K, 4K. O image_size exige K maiúsculo (ex.: "2K") — inclusive o menor valor é "0.5K", não 512.
    • +
    • Imagens de referência: Flash 3.1 aceita até 10 objetos / 4 personagens; Pro 3 aceita até 6 objetos / 5 personagens.
    • +
    • MIME types: image/png, image/jpeg.
    • +
    + +

    7.3 Text-to-image

    +

    Python

    +
    from google import genai
    +import base64
    +
    +client = genai.Client()
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme",
    +)
    +
    +with open("generated_image.png", "wb") as f:
    +    f.write(base64.b64decode(interaction.output_image.data))
    + +

    JavaScript

    +
    import { GoogleGenAI } from "@google/genai";
    +import * as fs from "node:fs";
    +
    +const ai = new GoogleGenAI({});
    +
    +const interaction = await ai.interactions.create({
    +  model: "gemini-3.1-flash-image",
    +  input: "Create a picture of a nano banana dish in a fancy restaurant with a Gemini theme",
    +});
    +if (interaction.output_image) {
    +  fs.writeFileSync("gemini-native-image.png",
    +    Buffer.from(interaction.output_image.data, "base64"));
    +}
    + +

    REST

    +
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -H "Api-Revision: 2026-05-20" \
    +  -d '{
    +    "model": "gemini-3.1-flash-image",
    +    "input": [{"type": "text", "text": "Create a picture of a nano banana dish..."}]
    +  }'
    + +

    7.4 Controle de proporção e resolução

    +
    interaction = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="Da Vinci style anatomical sketch of a dissected Monarch butterfly",
    +    response_format={
    +        "type": "image",
    +        "mime_type": "image/jpeg",
    +        "aspect_ratio": "1:1",
    +        "image_size": "1K"
    +    },
    +)
    + +

    7.5 Edição (text+image-to-image)

    +
    import base64
    +with open("/path/to/cat_image.png", "rb") as f:
    +    image_bytes = f.read()
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input=[
    +        {"type": "text", "text": "Replace the cat with a corgi wearing sunglasses."},
    +        {"type": "image", "data": base64.b64encode(image_bytes).decode('utf-8'),
    +         "mime_type": "image/png"}
    +    ],
    +)
    + +

    7.6 Edição multi-turn (conversacional)

    +
    interaction = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="Create a vibrant infographic that explains photosynthesis.",
    +    tools=[{"type": "google_search"}],
    +)
    +
    +interaction_2 = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="Update this infographic to be in Spanish. Do not change other elements.",
    +    previous_interaction_id=interaction.id,
    +    response_format={
    +        "type": "image",
    +        "mime_type": "image/jpeg",
    +        "aspect_ratio": "16:9",
    +        "image_size": "2K"
    +    },
    +)
    + +

    7.7 Saída intercalada (texto + imagens)

    +

    Modelos como gemini-3.1-flash-image podem gerar conteúdo intercalado. Você precisa iterar steps[].content[] em vez de usar output_image:

    +
    interaction = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="Write the story of the lifecycle of a monarch butterfly, interleave illustrations",
    +)
    +
    +image_counter = 1
    +for step in interaction.steps:
    +    if step.type == "model_output":
    +        for block in step.content:
    +            if block.type == "text":
    +                print(block.text)
    +            elif block.type == "image":
    +                with open(f"butterfly_lifecycle_{image_counter}.png", "wb") as f:
    +                    f.write(base64.b64decode(block.data))
    +                image_counter += 1
    + +

    7.8 Thinking durante geração de imagem

    +

    Thinking é ativado por padrão em modelos de imagem; não pode ser desativado. O modelo gera até dois "thought images" intermediários antes da imagem final. Tokens de thinking são cobrados normalmente.

    +
    interaction = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="A futuristic city built inside a giant glass bottle floating in space",
    +    generation_config={"thinking_level": "high"},
    +)
    +
    +# Inspecionar thought images intermediárias
    +for step in interaction.steps:
    +    if step.type == "thought":
    +        for content_block in step.summary or []:
    +            if content_block.type == "image":
    +                # base64 de thought image
    +                ...
    + +

    7.9 Grounding com Google Search (web + image search)

    +
    interaction = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="A detailed painting of a Timareta butterfly resting on a flower",
    +    tools=[{
    +      "type": "google_search",
    +      "search_types": ["web_search", "image_search"]
    +    }],
    +    response_format={"type": "image", "mime_type": "image/jpeg", "aspect_ratio": "16:9"}
    +)
    +
    + Ao usar Image Search é obrigatório exibir search_suggestions do step google_search_result na UI. +
    + + +
    + +
    +

    8. Compreensão de imagens

    + +

    8.1 Métodos de envio

    +
      +
    • Files API (recomendado para reuso e arquivos > 20 MB).
    • +
    • Inline Base64 (limite 20 MB no total do payload).
    • +
    • URI público / URL externo.
    • +
    + +

    8.2 Formatos suportados

    +
      +
    • image/png, image/jpeg, image/webp, image/heic, image/heif, image/gif, image/bmp, image/tiff.
    • +
    + +

    8.3 Limites e tokenização

    +
      +
    • Máximo: 3.600 imagens por requisição.
    • +
    • Tokens: imagens com ambas dimensões ≤ 384 px = 258 tokens; maiores são divididas em blocos de 768×768 px com 258 tokens cada.
    • +
    • tile_size = floor(min(width, height) / 1.5); blocos = ceil(width/tile_size) × ceil(height/tile_size).
    • +
    • Resolução: parâmetro media_resolution controla detalhe (custos mais altos).
    • +
    + +

    8.4 Exemplo — upload via Files API

    +
    from google import genai
    +client = genai.Client()
    +
    +my_file = client.files.upload(file="path/to/sample.jpg")
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "text", "text": "Caption this image."},
    +        {"type": "image", "uri": my_file.uri, "mime_type": my_file.mime_type}
    +    ]
    +)
    +print(interaction.output_text)
    + +

    8.5 Exemplo — inline Base64

    +
    import base64
    +with open('small.jpg', 'rb') as f:
    +    image_bytes = f.read()
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "text", "text": "Caption this image."},
    +        {"type": "image", "data": base64.b64encode(image_bytes).decode('utf-8'),
    +         "mime_type": "image/jpeg"}
    +    ]
    +)
    + +

    8.6 Múltiplas imagens

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "text", "text": "What is different between these two images?"},
    +        {"type": "image", "uri": "https://example.com/image1.jpg", "mime_type": "image/jpeg"},
    +        {"type": "image", "uri": "https://example.com/image2.jpg", "mime_type": "image/jpeg"}
    +    ]
    +)
    + +

    8.7 Detecção de objetos (bounding boxes)

    +

    Coordenadas no formato [ymin, xmin, ymax, xmax], normalizadas 0–1000. Redimensione para o tamanho real da imagem.

    +
    from pydantic import BaseModel, Field
    +from typing import List
    +
    +class BoundingBox(BaseModel):
    +    box_2d: List[int] = Field(description="[ymin, xmin, ymax, xmax] normalized 0-1000.")
    +    mask: List[List[int]] = Field(description="Segmentation mask as polygon of [x,y].")
    +    label: str
    +
    +class BoundingBoxes(BaseModel):
    +    boxes: List[BoundingBox]
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "text", "text": "Detect all prominent items. box_2d normalized 0-1000."},
    +        {"type": "image", "uri": "https://example.com/image.png", "mime_type": "image/png"}
    +    ],
    +    response_format={
    +        "type": "text",
    +        "mime_type": "application/json",
    +        "schema": BoundingBoxes.model_json_schema()
    +    }
    +)
    +detected = BoundingBoxes.model_validate_json(interaction.output_text)
    + +

    8.8 Segmentação

    +

    A máscara é um PNG codificado em base64 com valores 0–255. Recomenda-se thinking_level: "minimal" para melhores resultados.

    +
    Exceção de modelo: a segmentação de imagem não é suportada na família Gemini 3.x via Interactions API. Para esse workload, use o modelo dedicado gemini-robotics-er-1.6-preview (embodied reasoning).
    + + +
    + +
    +

    9. Áudio — compreensão & geração (TTS)

    + +

    9.1 Capacidades

    +

    Descrição, resumo, transcrição, tradução voz-texto, diarização de locutor, detecção de emoções, análise por timestamp (formato MM:SS).

    + +
    Qual modelo usar: não há modelo STT dedicado — a transcrição é compreensão de áudio em qualquer modelo multimodal 3.x. Use gemini-3.5-flash para qualidade máxima, ou gemini-3.1-flash-lite (multimodal, aceita áudio) como opção mais barata e rápida para transcrição em volume — a doc oficial o recomenda explicitamente. Não existe um modelo gemini-3.1-flash "puro". Para transcrição em tempo real, use a Live API (gemini-3.1-flash-live-preview) ou o Google Cloud Speech-to-Text.
    + +

    9.2 Especificações técnicas

    +
    + + + + + + + + + + +
    ParâmetroValor
    Tokens por segundo32 tokens/s
    1 minuto de áudio1.920 tokens
    Duração máxima9,5 horas
    Resolução16 Kbps
    CanaisMulticanal combinado em mono
    Tamanho máximo inline20 MB (total)
    +
    + +

    9.3 Formatos suportados

    +
      +
    • audio/wav, audio/mp3, audio/aiff, audio/aac, audio/ogg, audio/flac, audio/mpeg, audio/m4a, audio/l16, audio/opus, audio/alaw, audio/mulaw.
    • +
    + +

    9.4 Upload via Files API

    +
    from google import genai
    +client = genai.Client()
    +
    +uploaded_file = client.files.upload(file="path/to/sample.mp3")
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "text", "text": "Describe this audio clip"},
    +        {"type": "audio", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
    +    ]
    +)
    +print(interaction.output_text)
    + +

    9.5 Transcrição com diarização e emoção

    +
    response_schema = {
    +    "type": "object",
    +    "properties": {
    +        "summary": {"type": "string"},
    +        "segments": {
    +            "type": "array",
    +            "items": {
    +                "type": "object",
    +                "properties": {
    +                    "speaker": {"type": "string"},
    +                    "timestamp": {"type": "string"},
    +                    "content": {"type": "string"},
    +                    "language": {"type": "string"},
    +                    "emotion": {"type": "string",
    +                                "enum": ["happy", "sad", "angry", "neutral"]}
    +                },
    +                "required": ["speaker", "timestamp", "content", "emotion"]
    +            }
    +        }
    +    }
    +}
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "audio", "uri": uploaded_file.uri, "mime_type": "audio/mp3"},
    +        {"type": "text", "text": "Transcribe with diarization, language, emotion."}
    +    ],
    +    response_format={"type": "text", "mime_type": "application/json",
    +                     "schema": response_schema},
    +)
    +print(interaction.output_text)
    + +

    9.6 Consulta por timestamps

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "text", "text": "Provide a transcript from 02:30 to 03:29."},
    +        {"type": "audio", "uri": uploaded_file.uri, "mime_type": uploaded_file.mime_type}
    +    ]
    +)
    + + + +

    9.7 Geração de áudio (TTS)

    +

    A Interactions API também gera áudio a partir de texto. Defina response_modalities=["audio"] e passe generation_config.speech_config; o modelo TTS atual é gemini-3.1-flash-tts-preview (Preview). Estilo, sotaque, ritmo e tom são controláveis por linguagem natural no próprio prompt. O áudio sai em interaction.output_audio.data (base64; PCM 24 kHz, 16-bit, mono).

    +

    Single-speaker — Python

    +
    from google import genai
    +import base64, wave
    +
    +client = genai.Client()
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.1-flash-tts-preview",
    +    input="Say cheerfully: Have a wonderful day!",
    +    response_modalities=["audio"],
    +    generation_config={"speech_config": [{"voice": "Kore"}]},
    +)
    +
    +pcm = base64.b64decode(interaction.output_audio.data)
    +with wave.open("out.wav", "wb") as wf:
    +    wf.setnchannels(1); wf.setsampwidth(2); wf.setframerate(24000)
    +    wf.writeframes(pcm)
    +

    REST

    +
    curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -H "Api-Revision: 2026-05-20" \
    +  -d '{
    +    "model": "gemini-3.1-flash-tts-preview",
    +    "input": "Say cheerfully: Have a wonderful day!",
    +    "response_modalities": ["audio"],
    +    "generation_config": {"speech_config": [{"voice": "Kore"}]}
    +  }'
    + +

    9.8 Multi-speaker (até 2 locutores)

    +

    Para diálogos, configure um item de speech_config por locutor (máximo 2), cada um com speaker (o nome usado no prompt) e voice.

    +
    prompt = """TTS the following conversation between Joe and Jane:
    +         Joe: How's it going today Jane?
    +         Jane: Not too bad, how about you?"""
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.1-flash-tts-preview",
    +    input=prompt,
    +    response_modalities=["audio"],
    +    generation_config={"speech_config": [
    +        {"speaker": "Joe", "voice": "Kore"},
    +        {"speaker": "Jane", "voice": "Puck"},
    +    ]},
    +)
    +pcm = base64.b64decode(interaction.output_audio.data)
    + +

    9.9 Vozes, idiomas & limites

    +
      +
    • 30 vozes pré-construídas no campo voice — ex.: Zephyr (bright), Puck (upbeat), Charon (informative), Kore (firm), Fenrir (excitable), Leda (youthful), Aoede (breezy), Achird (friendly), Sulafat (warm)… (lista completa na doc oficial).
    • +
    • Idioma automático: o modelo detecta o idioma da entrada; ~70 idiomas suportados (en, pt, es, fr, de, it, hi, ja, ko, ar, cmn…).
    • +
    • Saída: PCM 24 kHz, 16-bit, mono — recuperada via interaction.output_audio.data (base64).
    • +
    +
    Limitações do TTS: entrada somente texto, saída somente áudio; janela de contexto de 32k tokens; não suporta streaming; ocasionalmente o modelo retorna tokens de texto e o servidor falha com 500 (implemente retry automático); prompts vagos podem ser rejeitados (PROHIBITED_CONTENT) — adicione um preâmbulo claro instruindo a sintetizar fala e marque onde começa o texto a ser falado. A qualidade pode degradar após alguns minutos — divida transcrições longas.
    + +
    + +
    +

    10. Compreensão de vídeo

    + +

    10.1 Métodos de entrada

    +
    + + + + + + + + +
    MétodoTamanho máx.Uso
    Files API20 GB (pago) / 2 GB (free)Vídeos > 100 MB, longos (>10 min), reutilizáveis
    Cloud Storage2 GB / arquivo, sem limite totalGrandes, persistentes
    Inline (Base64)< 100 MBCurtos, uso único
    URLs YouTube—Vídeos públicos
    +
    + +

    10.2 Formatos suportados

    +

    video/mp4, video/mpeg, video/mov, video/avi, video/x-flv, video/mpg, video/webm, video/wmv, video/3gpp.

    + +

    10.3 Especificações técnicas

    +
    + + + + + + + + + + +
    AspectoValor
    Janela 1M tokens1 h (resolução padrão) ou 3 h (resolução baixa)
    Amostragem visual1 FPS
    Áudio (Files API)1 Kbps, mono
    Tokens — padrão~300 tokens/s (258 frame + 32 áudio + metadados)
    Tokens — baixa~100 tokens/s (66 frame + 32 áudio + metadados)
    Formato timestampMM:SS
    +
    + +

    10.4 Upload & espera por ACTIVE

    +
    from google import genai
    +import time, base64
    +client = genai.Client()
    +
    +myfile = client.files.upload(file="path/to/sample.mp4")
    +while not myfile.state or myfile.state.name != "ACTIVE":
    +    print("Processing video...")
    +    time.sleep(5)
    +    myfile = client.files.get(name=myfile.name)
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "video", "uri": myfile.uri, "mime_type": myfile.mime_type},
    +        {"type": "text", "text": "Summarize this video. Then create a quiz with key."}
    +    ]
    +)
    +print(interaction.steps[-1].content[0].text)
    + +

    10.5 YouTube URL

    +
    interaction = client.interactions.create(
    +    model='gemini-3.5-flash',
    +    input=[
    +        {"type": "text", "text": "Summarize the video in 3 sentences."},
    +        {"type": "video", "uri": "https://www.youtube.com/watch?v=9hE5-98ZeCg"}
    +    ]
    +)
    +
      +
    • Gratuito: até 8 h/dia.
    • +
    • Pago: sem limite.
    • +
    • Os modelos Gemini 3.x aceitam até 10 vídeos por requisição.
    • +
    • Apenas vídeos públicos.
    • +
    + +

    10.6 Inline (vídeos pequenos)

    +
    video_bytes = open("video.mp4", 'rb').read()
    +interaction = client.interactions.create(
    +    model='gemini-3.5-flash',
    +    input=[
    +        {"type": "text", "text": "Please summarize the video in 3 sentences."},
    +        {"type": "video", "data": base64.b64encode(video_bytes).decode('utf-8'),
    +         "mime_type": "video/mp4"}
    +    ]
    +)
    + +

    10.7 Timestamps e descrição multimodal

    +
    prompt = "Describe key events with audio and visual details. Include timestamps."
    +# ou: "What are the examples given at 00:05 and 00:10 supposed to show us?"
    + +
    + Limitação na Interactions API: o campo video_metadata (intervalos de corte, FPS customizado) presente em generateContent ainda não está disponível em Interactions. +
    + + +
    + +
    +

    11. Processamento de documentos (PDF)

    + +

    11.1 Capacidades

    +

    PDFs são processados com visão nativa: leitura de texto, imagens, diagramas, gráficos, tabelas, preservação de layout. Outros formatos (HTML, Markdown, CSV, etc.) são tratados como texto puro.

    + +

    11.2 Limites técnicos

    +
    + + + + + + + + + + +
    ParâmetroValor
    Tamanho máximo50 MB (inline)
    Páginas máximas1.000
    Tokens por página258
    Resolução máx.3072 × 3072 px
    Resolução mín.768 × 768 px
    Files API retention48 horas
    +
    + +

    11.3 Inline Base64

    +
    import base64
    +with open('path/to/document.pdf', 'rb') as f:
    +    pdf_bytes = f.read()
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "document",
    +         "data": base64.b64encode(pdf_bytes).decode('utf-8'),
    +         "mime_type": "application/pdf"},
    +        {"type": "text", "text": "Summarize this document"}
    +    ]
    +)
    +print(interaction.output_text)
    + +

    11.4 Files API (PDFs grandes)

    +
    import httpx, io
    +doc_io = io.BytesIO(httpx.get("https://arxiv.org/pdf/2312.11805").content)
    +sample_doc = client.files.upload(file=doc_io, config={'mime_type': 'application/pdf'})
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "document", "uri": sample_doc.uri, "mime_type": sample_doc.mime_type},
    +        {"type": "text", "text": "Summarize this document"}
    +    ]
    +)
    + +

    11.5 Múltiplos PDFs

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "document", "uri": sample_pdf_1.uri, "mime_type": "application/pdf"},
    +        {"type": "document", "uri": sample_pdf_2.uri, "mime_type": "application/pdf"},
    +        {"type": "text", "text": "Compare main benchmarks between these papers. Output as table."}
    +    ]
    +)
    + +

    11.6 Gemini 3 — media_resolution & texto nativo

    +
      +
    • media_resolution: unspecified (default), low, medium, high, ultra_high (só por item de conteúdo).
    • +
    • Texto nativo do PDF: agora extraído diretamente e fornecido ao modelo.
    • +
    • Faturamento: tokens de texto nativo não são cobrados; páginas processadas como imagem entram na modalidade IMAGE.
    • +
    • Por item de conteúdo (só Gemini 3): defina resolution dentro de cada bloco image/video/document para misturar resoluções no mesmo request.
    • +
    + +

    Tokens por valor de media_resolution (modelos Gemini 3) — fonte: ai.google.dev/gemini-api/docs/interactions/media-resolution:

    +
    + + + + + + + + + +
    MediaResolutionImagemVídeoPDF
    unspecified (default)112070560
    low28070280 + texto nativo
    medium56070560 + texto nativo
    high11202801120 + texto nativo
    ultra_high2240N/AN/A
    +
    +

    Recomendado: imagens high (1120); PDFs medium (560 — a qualidade satura aí para documentos comuns); vídeo geral low/medium (70/frame, tratados igual); vídeo com texto denso high (280/frame). ultra_high existe só por item de conteúdo e é voltado a Computer Use.

    + + +
    + +
    +

    12. Files API & métodos de entrada

    + +

    12.1 Quando usar cada método

    +
    + + + + + + + + +
    MétodoTamanho máx.PersistênciaIdeal para
    Inline (Base64)100 MB / 50 MB PDFsNenhumaTestes, arquivos pequenos, tempo real
    Files API2 GB / arquivo, 20 GB / projeto48 horasArquivos grandes, reuso
    GCS URI (gs://)2 GB / arquivo, sem limite totalRegistro: acesso por até 30 dias (não armazena; buscado por requisição)Já no Cloud Storage
    URLs externas100 MB / payloadBuscado por requisiçãoDados públicos, S3 pré-assinado, SAS Azure
    +
    + +

    12.2 Upload & uso

    +
    myfile = client.files.upload(file="path/to/sample.mp3")
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        {"type": "audio", "uri": myfile.uri, "mime_type": myfile.mime_type},
    +        {"type": "text", "text": "Describe this audio clip"}
    +    ]
    +)
    + +

    12.3 Listar / obter / excluir

    +
    for f in client.files.list(): print(f.name)
    +client.files.get(name=file_name)
    +client.files.delete(name=file_name)
    + +

    12.4 Registrar arquivos do GCS

    +
    from google.oauth2.service_account import Credentials
    +GCS_READ_SCOPES = [
    +  'https://www.googleapis.com/auth/devstorage.read_only',
    +  'https://www.googleapis.com/auth/cloud-platform'
    +]
    +credentials = Credentials.from_service_account_file('service-account.json',
    +                                                   scopes=GCS_READ_SCOPES)
    +
    +registered = client.files.register_files(
    +    uris=["gs://my_bucket/some_object.pdf"],
    +    auth=credentials
    +)
    +for f in registered.files:
    +    response = client.interactions.create(
    +        model="gemini-3.5-flash",
    +        input=[
    +            {"type": "document", "uri": f.uri, "mime_type": f.mime_type},
    +            {"type": "text", "text": "Summarize this file."}
    +        ]
    +    )
    + +
    + A Interactions API não aceita URLs externas (S3/SAS) como fonte de mídia — use upload inline ou a Files API. Arquivos na Files API expiram em 48 h. PDFs inline têm limite separado de 50 MB. +
    + + +
    + +
    +

    13. Function calling

    + +

    Function calling conecta o modelo a ferramentas/APIs externas. Em vez de produzir só texto, o modelo decide quando emitir uma step function_call com id, name e arguments. Seu app executa a função e devolve o resultado num step function_result.

    + +

    13.1 Esquema da declaração de função

    +
    + + + + + + + + + +
    CampoTipoObrigatórioDescrição
    typestringSimSempre "function" (no nível superior de tools).
    namestringSimsnake_case ou camelCase.
    descriptionstringSimExplicação clara da finalidade.
    parametersobjectSimJSON Schema (subset OpenAPI).
    parameters.requiredstring[]NãoLista de parâmetros obrigatórios.
    +
    + +

    13.2 Fluxo completo (4 etapas)

    +
      +
    1. Definir a declaração
    2. +
    3. Chamar o modelo com tools=[...]
    4. +
    5. Executar a função no cliente (lendo step.name e step.arguments)
    6. +
    7. Enviar function_result referenciando call_id
    8. +
    + +

    13.3 Exemplo — set_light_values

    +

    Python

    +
    set_light_values_declaration = {
    +    "type": "function",
    +    "name": "set_light_values",
    +    "description": "Sets the brightness and color temperature of a light.",
    +    "parameters": {
    +        "type": "object",
    +        "properties": {
    +            "brightness": {"type": "integer", "description": "0–100"},
    +            "color_temp": {"type": "string",
    +                           "enum": ["daylight", "cool", "warm"]},
    +        },
    +        "required": ["brightness", "color_temp"],
    +    },
    +}
    +
    +def set_light_values(brightness, color_temp):
    +    return {"brightness": brightness, "colorTemperature": color_temp}
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Turn the lights down to a romantic level",
    +    tools=[set_light_values_declaration],
    +)
    +
    +fc_step = next(s for s in interaction.steps if s.type == "function_call")
    +result = set_light_values(**fc_step.arguments)
    +
    +final = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[{
    +        "type": "function_result",
    +        "name": fc_step.name,
    +        "call_id": fc_step.id,
    +        "result": [{"type": "text", "text": str(result)}],
    +    }],
    +    tools=[set_light_values_declaration],
    +    previous_interaction_id=interaction.id,
    +)
    +print(final.output_text)
    + +

    JavaScript

    +
    const setLightValuesTool = {
    +  type: 'function',
    +  name: 'set_light_values',
    +  description: 'Sets the brightness and color temperature of a light.',
    +  parameters: {
    +    type: 'object',
    +    properties: {
    +      brightness: { type: 'number' },
    +      color_temp: { type: 'string', enum: ['daylight', 'cool', 'warm'] },
    +    },
    +    required: ['brightness', 'color_temp'],
    +  },
    +};
    +
    +const interaction = await client.interactions.create({
    +  model: 'gemini-3.5-flash',
    +  input: 'Turn the lights down to a romantic level',
    +  tools: [setLightValuesTool],
    +});
    +
    +const fcStep = interaction.steps.find(s => s.type === 'function_call');
    +const result = setLightValues(fcStep.arguments.brightness,
    +                              fcStep.arguments.color_temp);
    +
    +const final = await client.interactions.create({
    +  model: 'gemini-3.5-flash',
    +  input: [{
    +    type: 'function_result',
    +    name: fcStep.name,
    +    call_id: fcStep.id,
    +    result: [{ type: 'text', text: JSON.stringify(result) }]
    +  }],
    +  tools: [setLightValuesTool],
    +  previous_interaction_id: interaction.id,
    +});
    +console.log(final.output_text);
    + +

    13.4 Modos de tool_choice

    +
    + + + + + + + + +
    ModoComportamento
    auto (padrão)Modelo decide se chama função ou responde direto.
    anyModelo é forçado a chamar alguma função.
    noneModelo não pode chamar funções.
    validated (preview)Garante aderência ao schema.
    +
    +
    generation_config = {
    +    "tool_choice": {
    +        "allowed_tools": {
    +            "mode": "any",
    +            "tools": ["get_current_temperature"]
    +        }
    +    }
    +}
    + +

    13.5 Chamadas paralelas

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Turn this place into a party!",
    +    tools=[power_disco_ball, start_music, dim_lights],
    +    generation_config={"tool_choice": "any"},
    +)
    +for step in interaction.steps:
    +    if step.type == "function_call":
    +        print(f"{step.name}({step.arguments})")
    + +

    13.6 Chamadas composicionais

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="If it's warmer than 20°C in London, set the thermostat to 20°C, otherwise 18°C.",
    +    tools=[get_weather_forecast_declaration,
    +           set_thermostat_temperature_declaration],
    +)
    + +

    13.7 Function result multimodal (Gemini 3)

    +
    base64_image_data = base64.b64encode(image_bytes).decode("utf-8")
    +final = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    previous_interaction_id=interaction.id,
    +    input=[{
    +        "type": "function_result",
    +        "name": tool_call.name,
    +        "call_id": tool_call.id,
    +        "result": [
    +            {"type": "text",  "text": "instrument.jpg"},
    +            {"type": "image", "mime_type": "image/jpeg", "data": base64_image_data},
    +        ],
    +    }],
    +)
    + +

    13.8 MCP Server tools (HTTP Streaming)

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Check the status of my last server deployment.",
    +    tools=[{
    +        "type": "mcp_server",
    +        "name": "deployment_tracker",
    +        "url": "https://mcp.example.com/mcp",
    +        "headers": {"Authorization": "Bearer my-token"},
    +    }]
    +)
    +
    + Restrições do MCP remoto: apenas HTTP streaming (não SSE). Gemini 3 ainda não suporta MCP remoto. Nomes de servidor não podem conter - (use snake_case). +
    + +

    13.9 Streaming de function calling — acumular arguments_delta

    +
    stream = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="What is the weather in Paris?",
    +    tools=[weather_tool],
    +    stream=True
    +)
    +current_calls = {}
    +for event in stream:
    +    if event.event_type == "step.start" and event.step.type == "function_call":
    +        current_calls[event.index] = {"id": event.step.id, "name": event.step.name, "arguments": ""}
    +    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
    +        current_calls[event.index]["arguments"] += event.delta.arguments
    + +

    13.10 Limitações

    +
      +
    • Apenas subset OpenAPI suportado para parameters.
    • +
    • Em modo any, esquemas muito grandes podem ser rejeitados.
    • +
    • Recomendação: manter ≤ 10–20 ferramentas ativas.
    • +
    • Gemini 3 ainda não suporta MCP remoto.
    • +
    + + +
    + +
    +

    14. Saída estruturada

    + +

    Configure response_format com type: "text", mime_type: "application/json" e um schema (JSON Schema, Pydantic ou Zod) para forçar resposta estruturada.

    + +

    14.1 Exemplo — extrator de receitas

    +

    Python (Pydantic)

    +
    from pydantic import BaseModel, Field
    +from typing import List, Optional
    +
    +class Ingredient(BaseModel):
    +    name: str = Field(description="Name of the ingredient.")
    +    quantity: str = Field(description="Quantity with units.")
    +
    +class Recipe(BaseModel):
    +    recipe_name: str
    +    prep_time_minutes: Optional[int]
    +    ingredients: List[Ingredient]
    +    instructions: List[str]
    +
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Extract this recipe: ...",
    +    response_format={
    +        "type": "text",
    +        "mime_type": "application/json",
    +        "schema": Recipe.model_json_schema()
    +    },
    +)
    +recipe = Recipe.model_validate_json(interaction.output_text)
    + +

    JavaScript (Zod)

    +
    import * as z from "zod";
    +
    +const recipeJsonSchema = {
    +  type: "object",
    +  properties: {
    +    recipe_name: { type: "string" },
    +    ingredients: {
    +      type: "array",
    +      items: { type: "object", properties: {
    +        name: { type: "string" },
    +        quantity: { type: "string" }
    +      }, required: ["name", "quantity"] }
    +    },
    +    instructions: { type: "array", items: { type: "string" } }
    +  },
    +  required: ["recipe_name", "ingredients", "instructions"]
    +};
    +
    +const interaction = await ai.interactions.create({
    +  model: "gemini-3.5-flash",
    +  input: "Extract this recipe: ...",
    +  response_format: {
    +    type: 'text',
    +    mime_type: 'application/json',
    +    schema: recipeJsonSchema
    +  },
    +});
    +const recipeSchema = z.fromJSONSchema(recipeJsonSchema);
    +const recipe = recipeSchema.parse(JSON.parse(interaction.output_text));
    + +

    14.2 Streaming de saída estruturada

    +
    stream = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="The new UI is intuitive. Long summary please!",
    +    response_format={"type": "text", "mime_type": "application/json",
    +                     "schema": Feedback.model_json_schema()},
    +    stream=True
    +)
    +for event in stream:
    +    if event.event_type == "step.delta" and event.delta.text:
    +        print(event.delta.text, end="")
    + +

    14.3 Saída estruturada + ferramentas (Preview · Gemini 3)

    +
    interaction = client.interactions.create(
    +    model="gemini-3.1-pro-preview",
    +    input="Search for all details for the latest Euro.",
    +    tools=[{"type": "google_search"}, {"type": "url_context"}],
    +    response_format={
    +        "type": "text",
    +        "mime_type": "application/json",
    +        "schema": MatchResult.model_json_schema()
    +    },
    +)
    +

    Ferramentas compatíveis: google_search, url_context, code_execution, file_search e function calling. Apenas modelos Gemini 3.

    + +

    14.4 Tipos JSON Schema aceitos

    +
      +
    • string, number, integer, boolean, object, array.
    • +
    • Nullable: {"type": ["string", "null"]}.
    • +
    • enum, format (date-time, date, time) em strings.
    • +
    • minimum, maximum em números.
    • +
    • items, prefixItems, minItems, maxItems em arrays.
    • +
    • properties, required, additionalProperties em objetos.
    • +
    + + +
    + +
    +

    15. Thinking & assinaturas de pensamento

    + +

    Os modelos Gemini 3.x usam raciocínio em múltiplas etapas, expostos como steps thought em interaction.steps. Cada step contém signature (representação criptografada do estado interno) e opcionalmente summary (resumo em texto/imagem).

    + +

    15.1 Modelos & níveis de thinking

    +
    + + + + + + + + +
    ModeloThinking padrãoNíveis
    gemini-3.1-pro-previewAtivado (alto)low, medium, high
    gemini-3-flash-previewAtivado (alto)low, medium, high
    gemini-3.5-flashAtivado (médio, padrão)minimal, low, medium, high
    gemini-3.1-flash-liteminimal (padrão)minimal, low, medium, high
    +
    +

    O minimal não garante que o thinking esteja desligado; gemini-3.5-flash e gemini-3.1-flash-lite não suportam thinking-off completo (verificado 2026-06-03 na doc de thinking).

    + +

    15.2 Controlar nível

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Provide a list of 3 famous physicists and their key contributions",
    +    generation_config={"thinking_level": "low"}
    +)
    + +

    15.3 Resumos de pensamento (thinking_summaries)

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="What is the sum of the first 50 prime numbers?",
    +    generation_config={"thinking_summaries": "auto"}
    +)
    +for step in interaction.steps:
    +    if step.type == "thought":
    +        for block in step.summary or []:
    +            if block.type == "text":
    +                print("Thought:", block.text)
    +    elif step.type == "model_output":
    +        for block in step.content:
    +            if block.type == "text":
    +                print("Answer:", block.text)
    + +

    15.4 Streaming com raciocínio (dois tipos de delta)

    +
    + + + + + + +
    delta.typeCargaQuando
    thought_summarycontent (texto/imagem)Resumos incrementais.
    thought_signaturesignatureÚltimo delta antes de step.stop.
    +
    +
    stream = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Alice, Bob, Carol live in red/green/blue houses. ...",
    +    generation_config={"thinking_summaries": "auto"},
    +    stream=True
    +)
    +for event in stream:
    +    if event.event_type == "step.delta":
    +        if event.delta.type == "thought_summary":
    +            print(f"[Thought] {event.delta.content.text}", end="")
    +        elif event.delta.type == "text":
    +            print(event.delta.text, end="")
    + +

    15.5 Assinaturas de pensamento (signature)

    +

    São representações criptografadas do estado de raciocínio interno. Regra: se você receber uma assinatura em uma resposta, transmita-a exatamente como recebida ao enviar o histórico na próxima chamada. Em Gemini 3 isso é obrigatório em chamadas de função — omissão gera erro 400.

    + +
    + + + + + + +
    ModoComportamento
    store=true (server-side)SDK e servidor gerenciam assinaturas automaticamente. Nenhuma ação manual.
    store=false (stateless)Você precisa reenviar todos os blocos thought com signature exatamente como recebidos. Mudar ou pular = erro 400 em FC.
    +
    + +

    15.6 Preço & tokens de raciocínio

    +

    Custo = tokens de saída + tokens de raciocínio. O campo interaction.usage.total_thought_tokens expõe o total gerado. Apenas o resumo é exposto ao desenvolvedor — o conteúdo completo de raciocínio fica interno.

    + +

    15.7 Recomendações de nível

    +
    + + + + + + + +
    CenárioNível
    Fatos diretos, classificação trivialminimal
    Comparações, raciocínio criativoPadrão (medium)
    Programação avançada, matemática difícil, AIMEhigh
    +
    + + +
    + +
    +

    16. Caching (implícito)

    + +

    A Interactions API suporta apenas cache implícito. Cache explícito (criação manual de objetos de cache) não está disponível na Interactions; para isso continue usando generateContent com client.caches.create(...).

    + +

    16.1 Como funciona

    +
      +
    • Ativado por padrão nos modelos Gemini 3.x.
    • +
    • Economia de custo aplicada automaticamente em cache hits.
    • +
    • Reutilização via previous_interaction_id dispara o cache.
    • +
    + +

    16.2 Limites mínimos por modelo

    +
    + + + + + + + + + +
    ModeloTokens mínimos para cache
    Gemini 3.5 Flash4096
    Gemini 3.1 Pro Preview4096
    Gemini 2.5 Flash2048
    Gemini 2.5 Pro2048
    Gemini 3.1 Flash-Litenão publicado
    +

    Fonte oficial (caching, verificado 2026-07-12): a tabela publicada agora lista Gemini 3.5 Flash = 4096, Gemini 3.1 Pro Preview = 4096, Gemini 2.5 Flash = 2048 e Gemini 2.5 Pro = 2048 (os valores mudaram desde o snapshot antigo de 2026-06-03, que trazia Flash=1024). O gemini-3.1-flash-lite não tem linha própria na tabela oficial — seu mínimo permanece [UNVERIFIED], por isso não atribuímos um valor.

    +
    + +

    16.3 Maximizar cache hits

    +
      +
    • Coloque grandes conteúdos comuns no início do prompt.
    • +
    • Envie requisições com prefixos semelhantes em curto intervalo.
    • +
    • Use previous_interaction_id para reutilizar histórico.
    • +
    + +

    16.4 Verificar tokens em cache

    +

    Disponível em interaction.usage.total_cached_tokens (na Interactions API o objeto é usage; usage_metadata/usageMetadata é a nomenclatura do generateContent).

    + + +
    + +
    +

    17. Ferramentas server-side

    + +

    Além de function calling (cliente), a Interactions API integra diversas ferramentas executadas pelo servidor do Google. Habilite com tools=[{"type": "<tool_name>"}] e elas aparecem como steps na timeline.

    + +

    17.1 Catálogo de ferramentas server-side

    +
    + + + + + + + + + + + +
    TooltypeCasos de uso
    Google Searchgoogle_searchEventos atuais, verificação de fatos, citações
    Google Mapsgoogle_mapsAssistentes com localização, itinerários, lugares
    Code Executioncode_executionCálculos precisos em Python sandbox
    URL Contexturl_contextLeitura/comparação de páginas/PDFs/JSON
    Computer Use (preview)computer_useAgentes que veem tela e clicam
    File Searchfile_searchRAG sobre file_search_stores
    MCP Servermcp_serverFerramentas externas via HTTP streaming
    +
    +
    + + + +
    +

    17.2 Google Maps (grounding)

    + +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="What are the best Italian restaurants within a 15-minute walk from here?",
    +    tools=[{
    +        "type": "google_maps",
    +        "enable_widget": True,
    +        "latitude": 34.050481,
    +        "longitude": -118.248526
    +    }]
    +)
    +for step in interaction.steps:
    +    if step.type == "google_maps_result":
    +        for place in step.result.places:
    +            print(f"- {place.name} ({place.url})")
    +        if step.result.widget_context_token:
    +            print(f"<gmp-place-contextual context-token='{step.result.widget_context_token}'></gmp-place-contextual>")
    + +

    Preços & cota

    +
      +
    • Preço: US$ 25 / 1.000 prompts fundamentados.
    • +
    • Nível gratuito: 500 requisições/dia.
    • +
    • Cobrado apenas quando retorna ≥ 1 lugar.
    • +
    + + +
    + +
    +

    17.3 Code Execution

    + +

    O modelo gera e executa Python em sandbox seguro. Steps code_execution_call trazem o código, e code_execution_result traz a saída.

    + +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="What is the sum of the first 50 prime numbers? Generate and run code.",
    +    tools=[{"type": "code_execution"}],
    +)
    +for step in interaction.steps:
    +    if step.type == "code_execution_call":
    +        print("CODE:\n", step.arguments.code)
    +    elif step.type == "code_execution_result":
    +        print("OUTPUT:", step.result)
    + +

    Limites

    +
      +
    • Tempo máximo de execução: 30 s.
    • +
    • Entrada máxima: ~1 M tokens (~2 MB texto).
    • +
    • Até 5 retentativas em erro.
    • +
    • Sandbox apenas com bibliotecas pré-instaladas; não é possível instalar próprias.
    • +
    • Apenas gráficos gerados com matplotlib são renderizados como imagem inline no resultado.
    • +
    + +

    Bibliotecas disponíveis (extrato)

    +

    matplotlib, numpy, pandas, scipy, scikit-learn, tensorflow, sympy, pillow, opencv-python, geopandas, pyPDF2, python-docx, python-pptx, openpyxl, xlrd, reportlab, fpdf, pylatex, jinja2, seaborn, chess, imageio, tabulate, jsonschema, ...

    + +
    Superfície (Developer API vs Vertex): como toda a Interactions API, este code_execution é documentado e exemplificado na Developer API. Na Vertex / Gemini Enterprise Agent Platform o CodeExecution consta apenas no schema (sem exemplo prático) e a execução de código é documentada via generateContent; em teste, code_execution via Interactions não funcionou sob auth Vertex. Em Vertex, use generateContent + code_execution. Detalhes no guia de code tools. (2026-06-19)
    + + +
    + +
    +

    17.4 URL Context

    + +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Compare ingredients of these recipes: https://... and https://...",
    +    tools=[{"type": "url_context"}]
    +)
    +for step in interaction.steps:
    +    if step.type == "url_context_result":
    +        print(step.result.url, "→", step.result.status)
    + +

    Limites & aceitação

    +
      +
    • Até 20 URLs por requisição.
    • +
    • Até 34 MB por URL.
    • +
    • Aceita PDF, HTML, JSON, CSS, JS, CSV, RTF, PNG/JPEG/BMP/WebP.
    • +
    • Não aceita: paywalls, vídeos do YouTube, Google Workspace, áudio/vídeo, localhost/redes privadas/ngrok/pinggy.
    • +
    + +

    Status (url_retrieval_status)

    +

    URL_RETRIEVAL_STATUS_SUCCESS, URL_RETRIEVAL_STATUS_UNSAFE.

    + + +
    + +
    +

    17.5 Computer Use (preview)

    + +

    Agentes que "veem" tela via screenshots e "agem" via ações de UI (cliques, digitação, scroll). Modelos suportados (usar outro modelo gera erro):

    +
      +
    • gemini-3-flash-preview — suporte nativo a Computer Use (não precisa de modelo separado para acessar a ferramenta).
    • +
    • gemini-2.5-computer-use-preview-10-2025 — modelo dedicado de Computer Use.
    • +
    +
    gemini-3.5-flash ainda não suporta Computer Use; use gemini-3-flash-preview (mais recente com suporte nativo).
    + +

    Ações disponíveis (resumo)

    +

    open_web_browser, navigate(url), click_at(x,y), type_text_at(x,y,text,press_enter), hover_at, scroll_at, scroll_document(direction), drag_and_drop, key_combination(keys), go_back, go_forward, wait_5_seconds, search.

    +
    + Coordenadas em escala 0–999; converta para pixels reais antes de executar. +
    + +

    Habilitar (Interactions API)

    +
    interaction = client.interactions.create(
    +    model="gemini-3-flash-preview",  # suporte nativo a Computer Use
    +    input="Find a flight to Tokyo",
    +    tools=[{
    +        "type": "computer_use",
    +        "environment": "browser",
    +        "excluded_predefined_functions": ["drag_and_drop"],
    +    }],
    +)
    + +

    Segurança

    +
      +
    • Algumas respostas trazem safety_decision: require_confirmation — implemente HITL.
    • +
    • Use sandbox (VM/Docker), allowlist de URLs e logs detalhados.
    • +
    • Não use para decisões críticas sem supervisão humana.
    • +
    + + +
    + + + +
    +

    17.7 MCP Server tools

    + +

    Conecte agentes a servidores MCP externos via HTTP streaming.

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Check status of latest deploy",
    +    tools=[{
    +        "type": "mcp_server",
    +        "name": "deployment_tracker",
    +        "url": "https://mcp.example.com/mcp",
    +        "headers": {"Authorization": "Bearer token"},
    +        "allowed_tools": {"mode": "auto", "tools": ["check_deploy"]}
    +    }]
    +)
    +
    + Restrições: apenas HTTP streaming (não SSE). Gemini 3 ainda não suporta MCP remoto. Nomes não podem conter -. +
    +
    + +
    +

    17.8 Combinando ferramentas (Preview · Gemini 3)

    + +
    +

    ✅ Sim: Gemini 3.x combina built-in tools + function calling no mesmo turno. Não é workaround — é uma feature Preview oficial da série Gemini 3, baseada em tool context circulation. O modelo pode, por exemplo, se ancorar em dados frescos da web (Google Search) antes de chamar a sua lógica de negócio (custom function) em uma única geração. Funciona tanto em client.models.generate_content(...) quanto aqui na Interactions API. [doc]

    +
    + +

    Como ligar: declare os built-in tools junto com as custom functions e ligue o flag include_server_side_tool_invocations=true. A cada turno, devolva todos os parts retornados (id, tool_type, thought_signature) exatamente como recebidos — omitir o thought_signature faz o modelo dar erro. O combo opera em modo VALIDATED (o AUTO não é suportado com o flag ligado).

    + +
    # Forma generate_content (clássica) — built-in (google_search) + custom (getWeather) no mesmo turno
    +from google import genai
    +from google.genai import types
    +
    +client = genai.Client()
    +getWeather = {
    +    "name": "getWeather",
    +    "description": "Gets the weather for a requested city.",
    +    "parameters": {"type": "object",
    +                   "properties": {"city": {"type": "string"}},
    +                   "required": ["city"]},
    +}
    +response = client.models.generate_content(
    +    model="gemini-3-flash-preview",
    +    contents="Qual a cidade mais ao norte dos EUA? Como está o tempo lá hoje?",
    +    config=types.GenerateContentConfig(
    +        tools=[types.Tool(
    +            google_search=types.ToolGoogleSearch(),   # built-in (server-side)
    +            function_declarations=[getWeather],        # custom (client-side)
    +        )],
    +        include_server_side_tool_invocations=True,     # liga a circulação de contexto
    +    ),
    +)
    +# A resposta traz toolCall/toolResponse (built-in) + functionCall (custom) para você executar.
    +# No próximo turno reenvie TODOS os parts (com thought_signature) + o functionResponse com o mesmo id.
    + +
    Na Interactions API: declare as tools como dicts ({"type":"google_search"}, {"type":"code_execution"}, …) ao lado das suas function tools; a circulação de contexto e o thought_signature são carregados automaticamente entre turnos quando você encadeia via previous_interaction_id. Para o caso vision-grounded (Code Execution + imagem), veja 17.9 Agentic Vision. Endpoint dedicado para bash + custom tools: gemini-3.1-pro-preview-customtools.
    + +

    Matriz de compatibilidade

    +
    + + + + + + + + + + + +
    FerramentaLadoSuporte à circulação de contexto
    Google SearchServidorSim
    Google MapsServidorSim
    URL ContextServidorSim
    File SearchServidorSim
    Code ExecutionServidorSim (executableCode+codeExecutionResult)
    Computer UseClienteSim (functionCall/functionResponse)
    Funções personalizadasClienteSim
    +
    + + +
    + +
    +

    17.9 Agentic Vision com gemini-3.5-flash (Code Execution + imagem)

    + +
    +

    ✅ Oficialmente suportado em Gemini 3 Flash. O modelo escreve e executa Python sobre a própria imagem (crop, zoom, threshold, edge detection, contagem, anotação) em vez de "chutar olhando o thumbnail". A doc oficial chama isso de Code Execution with images e lista três usos: zoom & inspect (detecta detalhe pequeno e re-examina em alta resolução), visual math (cálculo multi-passo por código) e image annotation (desenha setas/caixas para responder). Ativa-se habilitando Code Execution + Thinking. [doc]

    +

    ✅ Já funciona com gemini-3.5-flash — e pela Interactions API. Validamos este contrato em produção: agentic vision (Code Execution sobre a própria imagem) roda com gemini-3.5-flash via client.interactions.create — testado e funcionando, multi-turn inclusive. A doc oficial demonstra o recurso pelo generate_content; aqui é a mesma capacidade exposta pela Interactions API.

    +
    + +
    +

    ⚠️ Escopo do recurso — família Flash. (A capacidade já está confirmada com gemini-3.5-flash pela Interactions API, acima; aqui é só a delimitação de escopo.)

    +
      +
    • É um recurso da família Flash — não dos modelos Pro. A doc oficial documenta Code Execution with images apenas na linha Gemini 3 Flash; os exemplos oficiais usam o ID gemini-3-flash-preview.
    • +
    • Este guia usa gemini-3.5-flash — escolha validada por teste, não inferência. Rodamos o contrato com code_execution + thinking_level (testado até high) em benchmark de produção (n=198 derma 128 px; ~$0,005/caso em medium; p50 ~6 s) e funcionou. O gemini-3-flash-preview é apenas o ID dos exemplos da doc; o gemini-3.5-flash é o Flash estável atual da mesma família.
    • +
    +

    Reverificado na fonte oficial em 2026-06-04.

    +
    + +

    Diferenças entre as APIs (este guia × exemplo oficial)

    +
    +

    Atenção ao copiar código. A doc oficial demonstra Code Execution with images via client.models.generate_content; este guia usa a Interactions API (client.interactions.create), que tem nomes de campo e envelope diferentes. O recurso e o comportamento são os mesmos — muda só o formato da requisição/resposta.

    +
    +
    + + + + + + + + + + + + +
    Aspectogenerate_content (doc oficial)interactions.create (este guia)
    Modelo dos exemplosgemini-3-flash-previewgemini-3.5-flash (validado por teste)
    Imagem na entradacontents=[Part.from_bytes(data, mime_type), "prompt"]input=[{"type":"image","data":b64,"mime_type":…}, …]
    Resolução da imagemmedia_resolution = enum MEDIA_RESOLUTION_* (per-part é v1alpha/experimental)campo resolution no bloco de imagem (standard/high/ultra_high)
    Ativar Code Executionconfig.tools=[Tool(code_execution=ToolCodeExecution)]tools=[{"type":"code_execution"}]
    Thinkinghabilitar Thinking no configgeneration_config={"thinking_level":"minimal|low|medium|high"}
    Saída estruturada (JSON)response_mime_type="application/json" + response_schemaresponse_format={"type":"text","mime_type":"application/json","schema":…}
    Multi-turn / estadoclient.chats (history) ou reenviar id+thought_signature manualmente (REST)previous_interaction_id (o SDK reidrata a signature)
    Imagem anotada (saída)part.as_image().image_bytes nos partsresp.output_image.data
    Trace do códigopart.executable_code / part.code_execution_resultresp.steps (ModelOutputStep / code_execution_call)
    + +

    Esta seção descreve o contrato de agentic vision usado para delegar uma investigação visual a gemini-3.5-flash via client.interactions.create. A ideia central: Code Execution é o instrumento de medição do modelo, e a Interactions API dá memória multi-turn (raciocínio + traços de tool + thought_signature) através de previous_interaction_id.

    + +

    O loop, em uma figura

    +
    Orquestrador                                   gemini-3.5-flash
    +   │  turn 1: payload + imagem + prompt            │
    +   ├───────────────────────────────────────────────►│ THINK  (planeja a hipótese e a região)
    +   │                                                 │ ACT    ──► code_execution (crop/zoom/threshold/medir)
    +   │                                                 │ OBSERVE ◄── lê o crop transformado; itera se preciso
    +   │                                                 │ FINAL: plt.show(imagem anotada)
    +   │  {analysis, findings, measurements, boxes[]}    │
    +   │  + annotated_png (emitido pelo modelo)          │
    +   │  + interaction_id (para o próximo turno)        │
    +   │◄───────────────────────────────────────────────┤
    +   │  turn 2 (opcional): MESMOS bytes (audita SHA256!)│
    +   │            + previous_interaction_id + nova pergunta
    +   ├───────────────────────────────────────────────►│ retoma com thinking_signature + contexto de code_execution
    + +

    Invariantes obrigatórias (todo turno, sem exceção)

    +
      +
    1. A imagem vai em TODO turno. previous_interaction_id carrega raciocínio + assinatura + traços de tool, não os bytes da imagem. Reenvie os bytes e audite por sha256(png)[:16].
    2. +
    3. Assinatura de pensamento preservada verbatim. Ela é opaca e vive dentro dos step/content blocks da interaction — não há acessor top-level resp.thinking_signature no SDK google-genai atual. O SDK reidrata sozinho quando você define previous_interaction_id = resp.id; nunca reconstrua nem injete a assinatura à mão.
    4. +
    5. Schema fixo = AGENTIC_SCHEMA (abaixo), com additionalProperties: false e os quatro campos sempre exigidos.
    6. +
    7. Tool list = exatamente [{"type":"code_execution"}] no turno de vision. Quer multi-tool? Embrulhe o flash dentro de um agente maior que roda seu próprio loop e delega só a visão.
    8. +
    9. Trust framing no system prompt (o modelo é a fonte de verdade; o código é o instrumento). Autonomy framing ("decida se usa a tool") degradou calibração ~8,9 pp nos experimentos.
    10. +
    + +

    System prompt (trust framing — núcleo)

    +
    Você é o especialista de AGENTIC-VISION. Você É a fonte de verdade sobre esta
    +imagem — o orquestrador confia na sua leitura. O code execution é o SEU
    +INSTRUMENTO para fundamentar essa leitura; use-o liberalmente em vez de chutar
    +a partir de um thumbnail.
    +
    +Opere em um loop explícito THINK → ACT → OBSERVE:
    +  • THINK   — em 1–3 frases, planeje qual região e qual medida resolvem a questão.
    +  • ACT     — carregue a imagem e rode código: crop/zoom; realce de contraste
    +              (CLAHE/equalização); threshold (HSV costuma ser mais estável que RGB);
    +              edge detection (Canny/Sobel) ou blob analysis. DESCARREGUE qualquer
    +              contagem/área/distância para o Python. NÃO meça "no olho".
    +  • OBSERVE — leia o crop transformado; se não for decisivo, itere outro passo.
    +
    +PASSO FINAL — OBRIGATÓRIO: como última chamada de código, DESENHE sua(s) caixa(s)
    +e rótulo(s) sobre a imagem (cv2.rectangle / patches.Rectangle) e exiba com
    +plt.imshow(...); plt.show() para capturar a imagem anotada — é a sua trilha de auditoria.
    +
    +DISCIPLINA DE SAÍDA: preencha apenas analysis, findings_summary, measurements e
    +boxes (coordenadas em pixels da imagem ORIGINAL). Não emita diagnóstico final fora
    +do schema — o diagnóstico é responsabilidade do agente principal.
    + +

    Chamada (Interactions API)

    +
    import hashlib, base64, json
    +from google import genai
    +client = genai.Client()
    +
    +def sha16(b): return hashlib.sha256(b).hexdigest()[:16]
    +
    +def consult_flash(*, png_bytes, expected_hash, prompt, prior_id=None,
    +                  thinking_level="medium"):
    +    assert sha16(png_bytes) == expected_hash, "image drift antes do envio"
    +    payload = dict(
    +        model="gemini-3.5-flash",
    +        generation_config={"thinking_level": thinking_level},  # minimal|low|medium|high
    +        input=[
    +            {"type": "text",  "text": "Fonte da modalidade / caption"},
    +            {"type": "image", "data": base64.b64encode(png_bytes).decode(),
    +                              "mime_type": "image/png",
    +                              "resolution": "ultra_high"},     # crítico p/ lesão pequena
    +            {"type": "text",  "text": prompt},
    +        ],
    +        tools=[{"type": "code_execution"}],                    # SÓ isto no turno de vision
    +        response_format={"type": "text", "mime_type": "application/json",
    +                         "schema": AGENTIC_SCHEMA},
    +    )
    +    if prior_id:
    +        payload["previous_interaction_id"] = prior_id          # única diferença no multi-turn
    +    resp = client.interactions.create(**payload)
    +    parsed  = json.loads(resp.output_text) if resp.output_text else {}
    +    steps   = [type(s).__name__ for s in (resp.steps or [])]
    +    code_n  = sum(1 for s in steps if "CodeExecutionCall" in s)
    +    out_img = getattr(getattr(resp, "output_image", None), "data", None)
    +    return {
    +        "interaction_id": resp.id,
    +        "analysis": parsed.get("analysis", ""),
    +        "findings_summary": parsed.get("findings_summary", ""),
    +        "measurements": parsed.get("measurements", "none"),
    +        "boxes": parsed.get("boxes", []),
    +        "n_code_calls": code_n,
    +        "used_agentic": code_n > 0,        # 0 chamadas = modelo "fugiu" da tool
    +        "annotated_b64": out_img,          # PNG anotado emitido pelo próprio modelo
    +        "image_hash": expected_hash,
    +    }
    + +

    Schema autoritativo

    +
    AGENTIC_SCHEMA = {
    +    "type": "object",
    +    "properties": {
    +        "analysis":         {"type": "string"},
    +        "findings_summary": {"type": "string"},
    +        "measurements":     {"type": "string"},   # números concretos ou "none"
    +        "boxes": {
    +            "type": "array",
    +            "items": {
    +                "type": "object",
    +                "properties": {
    +                    "x0": {"type": "integer"}, "y0": {"type": "integer"},
    +                    "x1": {"type": "integer"}, "y1": {"type": "integer"},
    +                    "label": {"type": "string"},
    +                },
    +                "required": ["x0", "y0", "x1", "y1", "label"],
    +                "additionalProperties": False,
    +            },
    +        },
    +    },
    +    "required": ["analysis", "findings_summary", "measurements", "boxes"],
    +    "additionalProperties": False,
    +}
    +

    boxes em pixels da imagem original (nunca normalizados). measurements é string (conjunto aberto: área px², razão de assimetria, diâmetro mm…). additionalProperties: false em todo lugar — sem isso o flash inventa campos que o orquestrador descarta em silêncio.

    + +

    Multi-turn: o que você NÃO faz numa continuação

    +
      +
    1. Não remova a imagem do novo turno — mesmo com previous_interaction_id, os bytes precisam estar no payload.
    2. +
    3. Não reconstrua o system prompt inteiro num mega-prompt; envie só a instrução incremental — o contexto anterior vem pelo id.
    4. +
    5. Não levante/re-injete a "thinking signature" manualmente; setar previous_interaction_id = resp.id é o mecanismo suportado.
    6. +
    +

    Encadeie (previous_interaction_id) para aprofundar na MESMA imagem; comece do zero para outra imagem ou quando a pergunta muda de eixo (continuação serve para deepening, não para redirecionar). Se sha256 diverge entre turnos, aborte — é bug de drift de ground-truth.

    + +

    Tuning

    +
    + + + + + + +
    thinking_levelQuando
    minimal / lowTriagem em volume, passes de sanidade, consultas de rotina.
    mediumDefault para vision diagnóstico. medium → high não deu ganho de acurácia detectável no benchmark, mas ~80% mais caro.
    highCasos difíceis (lesão pequena, camadas OCT ambíguas); raramente necessário.
    +

    resolution: "ultra_high" é não-negociável para imagens diagnósticas ≤ 512 px (dermoscopia etc.); o default subamostra e perde o gradiente que dirige a decisão. Distribuição empírica: mediana de 3 passos de código por caso; se o flash emite < 2 chamadas de rotina, suba o thinking_level ou torne o THINK obrigatório no prompt.

    +

    Campo na Interactions API: a resolução vai no próprio bloco de imagem do input, no campo resolution (string). Valores validados em produção:

    +
    + + + + + + +
    resolutionQuando usar
    standardImagens macroscópicas grandes (ex.: raio-X de tórax).
    highOCT, ultrassom.
    ultra_highDermoscopia e qualquer imagem ≤ 512 px (preserva o gradiente de pigmentação que o default subamostra).
    +

    Equivalência no generate_content: o parâmetro é media_resolution com o enum MEDIA_RESOLUTION_{LOW,MEDIUM,HIGH,ULTRA_HIGH}. O ULTRA_HIGH é per-part, experimental (v1alpha), ~2240 tokens/imagem; a doc oficial recomenda HIGH para a maioria dos casos e ULTRA_HIGH só quando o teste mostra ganho claro sobre HIGH (ex.: computer use ou detalhe diagnóstico minúsculo). [doc]

    + +

    Anti-padrões (não faça)

    +
      +
    • Adicionar google_search ao turno de vision. Misturar busca introduz confound (regressão de ~10 pp medida em gemini-3.5-flash em derma). Mantenha o turno de visão só visão; busca é outra tool, orquestrada à parte.
    • +
    • Re-renderizar as boxes quando output_image existe — o PNG anotado pelo próprio modelo é melhor que o render por coordenadas (ele "viu" as medidas do código).
    • +
    • Pedir veredito diagnóstico final ao flash. Ele é instrumento de visão; o diagnóstico é do agente principal. Misturar os papéis infla a confiança dele nas próprias caixas.
    • +
    • Usar gemini-3.1-flash-image para isto — essa variante é de geração de imagem, não de raciocínio vision-grounded. Use o gemini-3.5-flash normal.
    • +
    • Reaproveitar previous_interaction_id entre imagens diferentes "para economizar tokens" — o flash conflaciona os casos. Imagem nova = interaction nova.
    • +
    + +
    +

    Leitura honesta do ganho. No benchmark de referência (n=198, derma 128px), o ganho marginal de agentic vision em cima do trust framing é quase-zero: a melhora observada vem do framing, não da tool. Trate agentic vision como instrumento de explicabilidade/auditoria (caixas + medidas que mostram por que o modelo decidiu), não como alavanca de acurácia por si só. Detecte "tool-dodge": n_code_calls == 0 + boxes == [] + measurements == "none" ⇒ rebaixe a contribuição do flash, não trate como negativo confiante.

    +
    + + +
    + +
    +

    18. Agentes: Deep Research & Antigravity

    + +

    A Interactions API expõe agentes gerenciados via parâmetro agent (no lugar de model): os agentes Deep Research (§18.1–18.8), o agente de propósito geral Antigravity (§18.9) e agentes custom construídos sobre ele — todos executando server-side. Deep Research é um agente assíncrono que pesquisa, planeja, lê, sintetiza e produz relatórios longos. Disponível apenas via Interactions API.

    + +

    18.1 Agentes Deep Research

    +
    + + + + + + +
    IdentificadorDescrição
    deep-research-preview-04-2026Deep Research — planeja e executa pesquisa multi-etapa com relatórios citados
    deep-research-max-preview-04-2026Deep Research Max — máxima abrangência de coleta e síntese entre centenas de fontes
    +
    + +

    18.2 Como invocar

    +
    import time
    +interaction = client.interactions.create(
    +    input="Research the history of Google TPUs.",
    +    agent="deep-research-preview-04-2026",
    +    background=True,
    +)
    +
    +while True:
    +    interaction = client.interactions.get(interaction.id)
    +    if interaction.status == "completed":
    +        print(interaction.output_text); break
    +    elif interaction.status == "failed":
    +        print("Failed:", interaction.error); break
    +    time.sleep(10)
    + +

    18.3 agent_config

    +
    + + + + + + + + +
    CampoTipoPadrãoDescrição
    typestringobrigatórioSempre "deep-research"
    thinking_summariesstring"none""auto" habilita raciocínio intermediário no stream
    visualizationstring"auto""auto" gera tabelas/gráficos; "off" desativa
    collaborative_planningbooleanfalseAtiva revisão do plano antes de executar
    +
    + +

    18.4 Planejamento colaborativo (3 etapas)

    +
      +
    1. Solicitar plano (collaborative_planning: true).
    2. +
    3. Refinar plano (mesmo collaborative_planning: true, com previous_interaction_id).
    4. +
    5. Aprovar e executar (collaborative_planning: false).
    6. +
    + +

    18.5 Ferramentas suportadas

    +

    Ativadas por padrão: google_search, url_context, code_execution. Opcionalmente: mcp_server, file_search.

    + +

    18.6 Reconexão de stream

    +
    # Salve last_event_id e reconecte com:
    +stream = client.interactions.get(
    +    id=interaction_id, stream=True, last_event_id=last_event_id
    +)
    + +

    18.7 Custos & limites

    +
    Estimativas de preview (sujeitas a mudança): custos e nº de consultas abaixo são aproximados (~) e baseados em preview rates — a doc oficial avisa que podem mudar. Tempo máximo de pesquisa: 60 min (maioria das tarefas em ~20 min).
    +
    + + + + + + +
    VersãoConsultasTokens entradaTokens saídaCusto estimado
    deep-research-preview-04-2026~80~250k (50–70% cache)~60kUS$ 1,00–3,00 / tarefa
    deep-research-max-preview-04-2026~160~900k (50–70% cache)~80kUS$ 3,00–7,00 / tarefa
    +
    +
      +
    • Tempo máximo: 60 minutos por tarefa (maioria conclui em ~20 min).
    • +
    • background=true exige store=true.
    • +
    • Function calling personalizado não é suportado (use MCP).
    • +
    • Saída estruturada não é suportada atualmente.
    • +
    + +

    18.8 Follow-up sobre relatório

    +
    followup = client.interactions.create(
    +    input="Can you elaborate on the second point?",
    +    model="gemini-3.1-pro-preview",
    +    previous_interaction_id="COMPLETED_INTERACTION_ID"
    +)
    + +

    18.9 Antigravity agent (preview) — agente gerenciado de propósito geral

    +

    O Antigravity (antigravity-preview-05-2026) é um agente gerenciado de propósito geral movido por gemini-3.5-flash: uma única chamada dispara um loop autônomo de raciocínio, execução de código, gestão de arquivos e navegação web dentro de um sandbox Linux hospedado (ver §18.10). Disponível via Interactions API e Google AI Studio.

    +
    interaction = client.interactions.create(
    +    agent="antigravity-preview-05-2026",
    +    input="Analyze this CSV and produce a summary report.",
    +    environment="remote",   # sandbox novo com defaults
    +)
    +print(interaction.output_text)
    +print(interaction.environment_id)  # reutilize para continuar com os mesmos arquivos/estado
    +

    O parâmetro environment aceita três formas:

    +
    + + + + + + + +
    FormaComportamento
    "remote"Cria um sandbox novo com configurações padrão.
    "env_abc123"Reutiliza um environment existente pelo ID — arquivos e estado preservados.
    {...} (EnvironmentConfig)Configuração completa: fontes Git/GCS/inline e regras de rede (allowlist).
    +
    +

    Capacidades: execução de código (Bash, Python, Node.js — instala pacotes, roda testes), gestão de arquivos persistente entre interações, acesso web (Google Search + URL Context) e compactação automática de contexto (disparada em ~135k tokens). Ferramentas tipadas suportadas: code_execution, google_search e url_context (todas ativas por padrão — restrinja passando só o necessário em tools); o filesystem é habilitado automaticamente pelo environment.

    +

    Customização: passe um AGENTS.md com instruções, monte skills em .agents/skills/ no sandbox ou configure inline na interação; o resultado pode ser salvo como agente gerenciado (custom agent).

    +
    Limitações (preview): entrada apenas text e image (base64 inline) — sem áudio, vídeo ou documentos; os parâmetros temperature, top_p, top_k, stop_sequences e max_output_tokens retornam 400; sem saída estruturada; sem file_search, computer_use, google_maps, function calling custom ou MCP; background=true não é suportado e store=true é obrigatório. Schemas podem mudar.
    +
    Custos (estimativas de preview, pay-as-you-go): tarefas típicas usam 100k–500k tokens de entrada (50–70% em cache) e 10k–50k de saída — US$ 0,25–1,30 por tarefa; processamento de dados pode chegar a 300k–3M de entrada (US$ 0,70–3,25) e workflows complexos a 3–5M tokens (~US$ 5/interação). A computação do sandbox não é cobrada durante o preview.
    + +

    18.10 Environments (sandboxes de agente)

    +

    Cada agente gerenciado roda em uma VM Linux isolada (Ubuntu, Python 3.12, Node.js 22) onde raciocina, executa código, gerencia arquivos e navega na web. Rede de saída liberada por padrão (configurável via allowlist). A VM hiberna por inatividade e restaura o estado na próxima requisição (cold start); é deletada permanentemente após 7 dias de inatividade. Limite: 1.000 agentes gerenciados. Agentes custom são construídos sobre a base do Antigravity — ver custom-agents e o quickstart de managed agents nas fontes abaixo.

    + + +
    + +
    +

    19. Background & webhooks

    + +

    Para operações longas (Deep Research, Deep Think), defina background=true. A interação fica em estado in_progress até concluir, e você pode:

    +
      +
    • Fazer polling via GET /interactions/{id}.
    • +
    • Receber notificação via webhook_config.
    • +
    + +

    19.1 Polling

    +
    while True:
    +    res = client.interactions.get(interaction_id)
    +    if res.status == "completed": break
    +    time.sleep(10)
    + +

    19.2 Webhook dinâmico (por requisição)

    +
    interaction = client.interactions.create(
    +    agent="deep-research-preview-04-2026",
    +    input="Research the latest in quantum computing.",
    +    background=True,
    +    webhook_config={
    +        "uris": ["https://my-api.com/gemini-webhook"],
    +        "user_metadata": {"job_id": "abc-123"}
    +    }
    +)
    + +

    19.3 Webhook estático (criar no projeto)

    +
    webhook = client.webhooks.create(
    +    name="MyWebhook",
    +    subscribed_events=["interaction.completed", "interaction.failed",
    +                       "interaction.requires_action", "interaction.cancelled"],
    +    uri="https://my-api.com/gemini-callback",
    +)
    +# webhook.new_signing_secret é retornado APENAS UMA VEZ
    + +

    19.4 Eventos suportados (Interactions)

    +
    + + + + + + + + +
    typeDispara quando
    interaction.completedLRO concluído
    interaction.failedLRO falhou (error_code, error_message em data)
    interaction.requires_actionFunção do cliente pendente
    interaction.cancelledCancelado pelo usuário
    +
    + +

    19.5 Verificação de assinatura (webhooks dinâmicos)

    +
      +
    • Header: Webhook-Signature (JWT, RS256).
    • +
    • Endpoint JWKS público: https://generativelanguage.googleapis.com/.well-known/jwks.json.
    • +
    • Use o kid do header JWT para encontrar a chave pública.
    • +
    + +

    19.6 Boas práticas

    +
      +
    • Responda 2xx em segundos; processe assincronamente.
    • +
    • Retentativas automáticas por 24 horas com backoff exponencial.
    • +
    • Header webhook-timestamp: rejeite se > 5 min de skew (anti-replay).
    • +
    • Header webhook-id para deduplicação (entrega at-least-once).
    • +
    • Rotate signing secret com revocation_behavior: "REVOKE_PREVIOUS_SECRETS_AFTER_H24".
    • +
    + + +
    + +
    +

    20. Flex & Priority Inference

    + +

    20.1 Comparativo de tiers

    +
    + + + + + + + + +
    RecursoPriorityStandardFlexBatch
    Preço+75–100% vs StandardPreço cheio−50%−50%
    LatênciaSegundosSegundos–minutos1–15 min (alvo)Até 24h
    ConfiabilidadeAlta (não descartável)Alta/Média-altaMelhor esforço (descartável)Alta (throughput)
    InterfaceSíncronaSíncronaSíncronaAssíncrona
    +
    + +

    20.2 Habilitar Flex

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Analyze this dataset for trends...",
    +    service_tier='flex'
    +)
    + +

    20.3 Habilitar Priority

    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Triage this critical support ticket immediately.",
    +    service_tier='priority'
    +)
    + +

    20.4 Retry com backoff (Flex)

    +
    import time
    +def call_with_retry(max_retries=3, base_delay=5):
    +    for attempt in range(max_retries):
    +        try:
    +            return client.interactions.create(
    +                model="gemini-3.5-flash", input="...", service_tier="flex")
    +        except Exception as e:
    +            if attempt < max_retries - 1:
    +                time.sleep(base_delay * (2 ** attempt))
    +            else:
    +                return client.interactions.create(
    +                    model="gemini-3.5-flash", input="...")  # fallback
    + +

    20.5 Códigos de erro Flex

    +
      +
    • 503 Service Unavailable — capacidade no limite.
    • +
    • 429 Too Many Requests — limite excedido.
    • +
    + +

    20.6 Soft downgrade (Priority)

    +

    Em picos, Priority faz soft downgrade automático para Standard (cobrado à taxa Standard). Monitore via header x-gemini-service-tier.

    + + +
    + +
    +

    21. Armazenamento & retenção de dados

    + +

    21.1 Padrão server-side

    +
      +
    • Padrão: store=true. Servidor armazena steps por: +
        +
      • Tier pago: 55 dias.
      • +
      • Tier free: 1 dia.
      • +
      +
    • +
    • Use previous_interaction_id para continuar histórico (e habilita cache implícito).
    • +
    + +

    21.2 Modo sem estado (store=false)

    +
      +
    • Servidor não armazena nada.
    • +
    • Você precisa enviar histórico completo (com signature de thought) em cada turno.
    • +
    • Incompatível com background=true.
    • +
    • Impede uso da interação como previous_interaction_id.
    • +
    + +

    21.3 Excluir / cancelar manualmente

    +
    curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/interactions/INT_ID" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY"
    +
    +curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions/INT_ID/cancel" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY"
    +
    + +
    +

    22. Limitações

    + +

    Recursos ainda ausentes ou em desenvolvimento na Interactions API:

    +
      +
    • Batch API assíncrona — siga usando generateContent com :batchGenerateContent.
    • +
    • Cache explícito — disponível apenas via generateContent.
    • +
    • video_metadata (cortes, FPS customizado) — disponível apenas em generateContent.
    • +
    • Chamada automática de função em Python — disponível apenas em generateContent.
    • +
    • MCP remoto com Gemini 3.x — ainda não suportado (em breve, segundo a doc oficial). Quando suportado, apenas servidores Streamable HTTP (não SSE).
    • +
    • Deep Research: function calling personalizado não suportado (use MCP); saída estruturada não suportada.
    • +
    • File Search: sem áudio/vídeo; não disponível na Live API.
    • +
    • Computer Use: suportado em gemini-3-flash-preview (nativo) e no modelo dedicado gemini-2.5-computer-use-preview-10-2025; gemini-3.5-flash não é compatível. Recurso em preview.
    • +
    + +

    22.1 Configurações de segurança

    +

    O filtro de segurança clássico — safety_settings com HarmCategory (ex.: HARM_CATEGORY_HATE_SPEECH) e HarmBlockThreshold (ex.: BLOCK_LOW_AND_ABOVE) — é documentado para o generateContent (via types.GenerateContentConfig) e não consta no schema de request da Interactions API nesta revisão. Para ações agênticas, a Interactions API expõe um mecanismo distinto: o campo safety_decision (ex.: require_confirmation) em ferramentas como Computer Use — implemente HITL conforme a §17.5.

    + +
    + +
    +

    23. Práticas recomendadas

    + +
      +
    • Use previous_interaction_id em vez de reenviar histórico — ativa cache implícito e reduz custo.
    • +
    • Para Deep Research, combine com modelo padrão depois: faça polling até completed e use previous_interaction_id num Gemini Flash para resumir.
    • +
    • Coloque conteúdos grandes (PDF, documento) no início do prompt para maximizar cache hits.
    • +
    • Para multimodal de uma imagem ou PDF curto, posicione o prompt de texto depois da mídia.
    • +
    • Em streaming de function calling, acumule arguments_delta e só faça JSON.parse após step.stop.
    • +
    • Em modo store=false, NUNCA modifique blocos thought ou suas signature — reenvie exatamente como recebido.
    • +
    • Implemente retry com backoff em service_tier: flex; cache de Priority via header x-gemini-service-tier.
    • +
    • Em webhooks, valide webhook-timestamp (≤5 min) e use webhook-id para deduplicação.
    • +
    • Trate eventos SSE desconhecidos com log + skip, não como erro.
    • +
    +
    + +
    +

    Parte B — Referência REST completa

    +

    Schema canônico da Interactions API verificado contra ai.google.dev/api/interactions-api. Todos os nomes de campo, enums e exemplos são preservados literalmente (a API usa snake_case no wire; os SDKs expõem camelCase em JS).

    +
    + +
    +

    B1. Endpoints

    +

    Base: https://generativelanguage.googleapis.com. Versão atual: v1beta (não existe /v1beta2 — todas as páginas oficiais usam /v1beta).

    +
    + + + + + + + + +
    Método & caminhoOperaçãoDescrição
    POST /v1beta/interactionscreateCria uma nova Interaction (modelo ou agente). Aceita stream, store, background.
    GET /v1beta/interactions/{id}getRecupera o estado completo de uma interação armazenada. Aceita stream, last_event_id, include_input.
    DELETE /v1beta/interactions/{id}deleteExclui uma interação armazenada por ID.
    POST /v1beta/interactions/{id}/cancelcancelCancela uma interação background ainda em execução.
    +
    + +
    + +
    +

    B2. Autenticação & Headers

    +
    + + + + + + + +
    HeaderObrigatórioValor
    x-goog-api-keySimSua chave de API ($GEMINI_API_KEY). Alternativa: query ?key=.
    Content-TypeSim (POST)application/json
    Api-RevisionNão (ignorado)Histórico da transição de Maio/2026: 2026-05-20 controlou o opt-in (até 26/05/2026) e 2026-05-07 o rollback (até 08/06/2026). Desde 08/06/2026 o header é ignorado e pode ser omitido.
    +
    +
    + SSE: para respostas em streaming, defina "stream": true no corpo (ou query ?stream=true no GET). O servidor responde text/event-stream com eventos event_type (ver B18). +
    + +
    + +
    +

    B3. POST /v1beta/interactions — criar

    +

    Cria uma nova interação. Exatamente um de model ou agent é obrigatório.

    + +

    Corpo da requisição

    +
    + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoDescrição
    modelModelOptionNome do modelo. Obrigatório se agent ausente. Ver B19.
    agentAgentOptionNome do agente. Obrigatório se model ausente. Ver B20.
    inputContent | array(Content) | array(Step) | string(Obrigatório) Entradas da interação. Aceita string simples, blocos de conteúdo ou steps tipados.
    system_instructionstringInstrução de sistema. Interaction-scoped (reenvie a cada turno).
    toolsarray(Tool)Declarações de ferramentas. Interaction-scoped. Ver B17.
    response_formatResponseFormat | ResponseFormatListFormato de saída (text/JSON, image, audio). Substitui response_mime_type + image_config.
    response_mime_typestringlegado MIME da resposta. No novo schema use mime_type dentro de response_format.
    streambooleanInput only. Streaming SSE.
    storebooleanInput only. Armazenar para recuperação posterior. Default true.
    backgroundbooleanInput only. Executar em background (tarefas longas). Incompatível com store=false.
    generation_configGenerationConfigConfiguração do modelo. Alternativa a agent_config. Só com model. Ver B10.
    agent_configDeepResearchAgentConfig | DynamicAgentConfigConfiguração do agente. Só com agent. Ver B11.
    environmentEnvironmentConfig | stringAmbiente remoto (sources GCS/repo/inline, allowlist de rede) ou ID de ambiente existente.
    previous_interaction_idstringID da interação anterior — ativa estado server-side e cache implícito.
    response_modalitiesarray(ResponseModality)Modalidades desejadas: text, image, audio, video, document.
    service_tierServiceTierflex | standard | priority.
    webhook_configWebhookConfigURIs de webhook + user_metadata para notificações. Ver B12.
    +
    + +

    Exemplo mínimo

    +
    +
    + + + +
    +
    +
    from google import genai
    +
    +client = genai.Client()
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Hello, how are you?",
    +)
    +print(interaction.output_text)
    +
    +
    +
    import {GoogleGenAI} from '@google/genai';
    +
    +const ai = new GoogleGenAI({});
    +const interaction = await ai.interactions.create({
    +    model: 'gemini-3.5-flash',
    +    input: 'Hello, how are you?',
    +});
    +console.log(interaction.output_text);
    +
    +
    +
    curl -X POST https://generativelanguage.googleapis.com/v1beta/interactions \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -H "Api-Revision: 2026-05-20" \
    +  -d '{
    +    "model": "gemini-3.5-flash",
    +    "input": "Hello, how are you?"
    +  }'
    +
    +
    + +
    + Resposta JSON (200) — status: completed +
    +
    {
    +  "created": "2025-11-26T12:25:15Z",
    +  "id": "v1_ChdPU0F4YWFtNkFwS2kxZThQZ05lbXdROBIX...",
    +  "model": "gemini-3.5-flash",
    +  "object": "interaction",
    +  "steps": [
    +    {
    +      "type": "model_output",
    +      "content": [
    +        { "type": "text", "text": "Hello! I'm functioning perfectly..." }
    +      ]
    +    }
    +  ],
    +  "status": "completed",
    +  "updated": "2025-11-26T12:25:15Z",
    +  "usage": {
    +    "input_tokens_by_modality": [ { "modality": "text", "tokens": 7 } ],
    +    "total_cached_tokens": 0,
    +    "total_input_tokens": 7,
    +    "total_output_tokens": 20,
    +    "total_thought_tokens": 22,
    +    "total_tokens": 49,
    +    "total_tool_use_tokens": 0
    +  }
    +}
    +
    +
    +
    + Function calling: quando o modelo decide chamar uma ferramenta, o status retorna requires_action e o último step é function_call (com id, name, arguments). Responda com um step function_result reaproveitando call_id = id. +
    + +
    + +
    +

    B4. GET /v1beta/interactions/{id} — recuperar

    +

    Recupera os detalhes completos de uma interação armazenada (store=true). O recurso retornado pelo GET inclui também o step user_input (a resposta do create retorna apenas steps gerados pelo modelo).

    +
    + + + + + + + + + +
    ParâmetroTipoDescrição
    idstring(Obrigatório) Identificador da interação.
    streambooleanSe true, transmite incrementalmente (SSE). Default false.
    last_event_idstringRetoma o stream a partir do próximo chunk após o evento indicado. Só com stream=true.
    include_inputbooleanInclui o input na resposta. Default false.
    api_versionstringVersão da API a usar.
    +
    +
    +
    + + + +
    +
    +
    interaction = client.interactions.get(id=created.id)
    +print(interaction.status)
    +
    +
    +
    const interaction = await ai.interactions.get(created.id);
    +console.log(interaction.status);
    +
    +
    +
    curl -X GET "https://generativelanguage.googleapis.com/v1beta/interactions/$INTERACTION_ID" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H "Api-Revision: 2026-05-20"
    +
    +
    +
    Polling de background: para background=true, faça get repetido até status sair de in_progress para completed/failed/cancelled.
    + +
    + +
    +

    B5. DELETE /v1beta/interactions/{id} — excluir

    +

    Exclui a interação por ID. Requer apenas id (e api_version opcional). Resposta vazia em caso de sucesso.

    +
    +
    + + + +
    +
    +
    client.interactions.delete(id=created.id)
    +print("Interaction deleted successfully.")
    +
    +
    +
    await ai.interactions.delete(created.id);
    +console.log('Interaction deleted successfully.');
    +
    +
    +
    curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/interactions/$INTERACTION_ID" \
    +  -H "x-goog-api-key: $GEMINI_API_KEY" \
    +  -H "Api-Revision: 2026-05-20"
    +
    +
    +
    + +
    +

    B6. POST /v1beta/interactions/{id}/cancel — cancelar

    +

    Cancela uma interação. Aplica-se apenas a interações background ainda em execução. Retorna o recurso Interaction com status: cancelled.

    +
    +
    + + +
    +
    +
    created = client.interactions.create(
    +    model="gemini-3-flash-preview",
    +    input="Write a long essay about the history of computing.",
    +    tools=[{"type": "computer_use"}],
    +    background=True,
    +)
    +interaction = client.interactions.cancel(id=created.id)
    +print(interaction.status)  # cancelled
    +
    +
    +
    const created = await ai.interactions.create({
    +    model: 'gemini-3-flash-preview',
    +    input: 'Write a long essay about the history of computing.',
    +    tools: [{ type: 'computer_use' }],
    +    background: true,
    +});
    +const interaction = await ai.interactions.cancel(created.id);
    +console.log(interaction.status); // cancelled
    +
    +
    +
    + +
    +

    B7. Recurso Interaction

    +

    Objeto central. Campos Output only são preenchidos pelo servidor.

    +
    + + + + + + + + + + + + + + + + +
    PropriedadeTipoNotas
    idstring(Obrigatório, output) Identificador único.
    objectstringSempre "interaction".
    model / agentenumModelo ou agente usado.
    statusenum(Obrigatório, output) Ver B8.
    stepsarray(Step)(Obrigatório, output) Timeline da interação. Ver B15.
    created / updatedstring(Obrigatório, output) ISO 8601 (YYYY-MM-DDThh:mm:ssZ).
    inputpoliformeEntrada (presente no GET com include_input).
    previous_interaction_idstringEncadeamento server-side.
    rolestringOutput only.
    environment_idstringOutput only. Só se environment foi configurado.
    usageUsageOutput only. Ver B9.
    response_format, response_modalities, service_tier, system_instruction, tools, generation_config, agent_config, webhook_config, environment—Espelham os campos do request.
    +
    +
    + +
    +

    B8. InteractionStatus (enum)

    +
    + + + + + + + + + + + +
    ValorSignificado
    in_progressEm execução (streaming/background).
    requires_actionAguardando ação do cliente — tipicamente um function_result para um function_call.
    completedConcluída com sucesso.
    failedErro durante a geração.
    cancelledCancelada via endpoint de cancel.
    incompleteInterrompida antes de concluir (ex.: limite de tokens).
    budget_exceededOrçamento (ex.: Deep Research) excedido.
    +
    +
    + +
    +

    B9. Usage & modalidades

    +

    Estatísticas de tokens. Os totais são acompanhados por breakdowns por modalidade (ModalityTokens: { modality, tokens }).

    +
    + + + + + + + + + + + + + + + +
    CampoDescrição
    total_input_tokensTokens do prompt (contexto).
    total_output_tokensTokens gerados em todas as respostas.
    total_thought_tokensTokens de raciocínio (modelos thinking).
    total_cached_tokensTokens servidos do cache implícito.
    total_tool_use_tokensTokens de prompts de uso de ferramentas.
    total_tokensTotal (prompt + respostas + internos).
    input_tokens_by_modalityBreakdown de entrada por modalidade.
    output_tokens_by_modalityBreakdown de saída por modalidade.
    cached_tokens_by_modalityBreakdown de cache por modalidade.
    tool_use_tokens_by_modalityBreakdown de uso de ferramentas por modalidade.
    grounding_tool_countarray de { type, count } — type ∈ google_search | google_maps | retrieval.
    +
    +
    + +
    +

    B10. GenerationConfig

    +

    Configuração do modelo (alternativa a agent_config; só com model).

    +
    + + + + + + + + + + + + + + +
    CampoTipoNotas
    thinking_levelenumminimal | low | medium | high. Substitui thinking_budget.
    thinking_summariesenumauto | none.
    max_output_tokensintegerMáximo de tokens na resposta.
    temperaturenumbernão recomendado em Gemini 3.x
    top_pnumbernão recomendado em Gemini 3.x
    seedintegerReprodutibilidade na decodificação.
    stop_sequencesarray(string)Sequências que interrompem a saída.
    tool_choiceToolChoiceConfig | ToolChoiceTypeauto | any | none | validated.
    image_configImageConfigaspect_ratio (1:1…21:9, 1:8, 8:1, 1:4, 4:1) e image_size (0.5K, 1K, 2K, 4K). legado — no novo schema, prefira response_format tipo image.
    speech_configarray(SpeechConfig){ language, speaker, voice } para TTS multi-speaker.
    +
    +
    + +
    +

    B11. AgentConfig & EnvironmentConfig

    +

    Discriminado por type. Só com agent.

    +

    DeepResearchAgentConfig — type: "deep-research"

    +
    + + + + + + + + +
    CampoTipoNotas
    typeconst(Obrigatório) "deep-research".
    collaborative_planningbooleanHuman-in-the-loop: o agente devolve um plano e só prossegue após confirmação no próximo turno.
    thinking_summariesenumauto | none.
    visualizationenumoff | auto — incluir visualizações na resposta.
    +
    +

    DynamicAgentConfig — type: "dynamic"

    +

    Configuração para agentes dinâmicos. Campo obrigatório: type: "dynamic".

    + +

    EnvironmentConfig — ambiente remoto (Computer Use / Antigravity)

    +

    Passado no campo top-level environment (objeto) ou como string com o ID de um ambiente já criado. Discriminador type: "remote".

    +
    + + + + + + + +
    CampoTipoNotas
    typeconst(Obrigatório) "remote".
    networkEnvironmentNetworkEgressAllowlist | enumEgress allowlist de rede: allowlist[].domain + allowlist[].transform (transformação/proxy de credenciais).
    sourcesarray(Source)Arquivos/dados montados no ambiente (campos abaixo).
    +
    +

    Cada Source:

    +
    + + + + + + + + + +
    CampoTipoNotas
    typeenumrepository | gcs | inline (a doc oficial de agents-environments lista esses três tipos).
    sourcestringOrigem (caminho GCS, caminho do GitHub etc.).
    targetstringOnde o conteúdo deve aparecer no ambiente.
    contentstringConteúdo inline (quando type: "inline").
    encodingstringEncoding opcional do inline (ex.: base64).
    +
    +
    + +
    +

    B12. WebhookConfig

    +
    + + + + + + +
    CampoTipoNotas
    urisarray(string)Se definido, usa estes URIs em vez dos webhooks registrados.
    user_metadataobjectMetadados retornados em cada emissão de evento ao webhook.
    +
    +
    Segurança de webhook: valide o header webhook-timestamp (rejeite > 5 min) e use webhook-id para deduplicação. Verifique a assinatura antes de processar o payload.
    +
    + +
    +

    B13. ResponseFormat · ResponseModality / ServiceTier / MediaResolution

    +

    response_format aceita um objeto ResponseFormat ou um array (ResponseFormatList, ex.: [{"type":"text"}, {"type":"image"}] para saída intercalada). Discriminado por type. Substitui o legado response_mime_type + image_config.

    +
    + + + + + + + +
    Variante (type)Campos
    text
    (TextResponseFormat)
    mime_type (application/json | text/plain); schema (JSON Schema — só com application/json).
    image
    (ImageResponseFormat)
    aspect_ratio (1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:8, 8:1, 1:4, 4:1); image_size (512 | 1K | 2K | 4K); delivery (inline | uri); mime_type (image/jpeg).
    audio
    (AudioResponseFormat)
    mime_type (audio/mp3 | audio/ogg_opus | audio/l16 | audio/wav | audio/alaw | audio/mulaw); sample_rate (Hz); bit_rate (bps — só formatos comprimidos); delivery (inline | uri).
    +
    +
    + + + + + + + + + + +
    EnumValores
    ResponseModalitytext · image · audio · video · document
    ServiceTierflex · standard · priority
    MediaResolutionlow · medium · high · ultra_high
    ThinkingLevelminimal · low · medium · high
    ThinkingSummariesauto · none
    ToolChoiceTypeauto · any · none · validated
    +
    +
    + +
    +

    B14. Content blocks (poliforme por type)

    +

    Blocos de conteúdo dentro de content[] de um step. Discriminador: type.

    +
    + + + + + + + + + +
    typeCamposEnums relevantes
    texttext (obrig.), annotations[]—
    imagedata (base64) | uri, mime_type, resolutionimage/png|jpeg|webp|heic|heif|gif|bmp|tiff
    audiodata | uri, mime_type, sample_rate, channelsaudio/wav|mp3|aiff|aac|ogg|flac|mpeg|m4a|l16|opus|alaw|mulaw
    documentdata | uri, mime_typeapplication/pdf
    videodata | uri, mime_type, resolutionvideo/mp4|mpeg|mpg|mov|avi|x-flv|webm|wmv|3gpp · uri aceita YouTube
    +
    +
    Vídeo via URL: { "type": "video", "uri": "https://www.youtube.com/watch?v=..." } dispensa upload.
    +
    + +
    +

    B15. Step types (poliforme por type)

    +

    A timeline steps[] é a substituta de candidates/outputs. Cada step tem um type. Steps de chamada de ferramenta vêm em pares call → result, ligados por id ↔ call_id. Muitos steps trazem signature (hash para validação backend — nunca modifique).

    + +

    Steps de conversa

    +
    + + + + + + + +
    typeCamposDescrição
    user_inputcontent[]Entrada do usuário (presente no GET).
    model_outputcontent[]Saída do modelo (texto/imagem/áudio).
    thoughtsummary[], signatureRaciocínio. summary é array de ThoughtSummaryContent.
    +
    + +

    Steps de chamada de ferramenta (call)

    +
    + + + + + + + + + + + +
    typeCampos-chave
    function_callid, name, arguments (object), signature
    code_execution_callid, arguments.code, arguments.language (python), signature
    url_context_callid, arguments.urls[], signature
    google_search_callid, arguments.queries[], search_type (web_search|image_search|enterprise_web_search), signature
    google_maps_callid, arguments.queries[], signature
    file_search_callid, signature
    mcp_server_tool_callid, name, server_name, arguments, signature
    +
    + +

    Steps de resultado de ferramenta (result)

    +
    + + + + + + + + + + + +
    typeCampos-chave
    function_resultcall_id (obrig.), name, result (string | array de subconteúdo), is_error, signature
    code_execution_resultcall_id, result (string), is_error, signature
    url_context_resultcall_id, result[] com url + status (success|error|paywall|unsafe), is_error
    google_search_resultcall_id, result[], search_suggestions (substitui rendered_content), is_error
    google_maps_resultcall_id, result[].places[] (name, place_id, review_snippets[], url), widget_context_token
    file_search_resultcall_id, signature
    mcp_server_tool_resultcall_id, name, server_name, result
    +
    + +
    + Exemplo: par function_call → function_result +
    +
    // step gerado pelo modelo (status: requires_action)
    +{ "type": "function_call", "id": "call_98231", "name": "get_weather",
    +  "arguments": { "location": "Boston, MA" } }
    +
    +// step que você envia de volta no próximo create
    +{ "type": "function_result", "call_id": "call_98231", "name": "get_weather",
    +  "result": { "temperature": "72F", "conditions": "Partly Cloudy" } }
    +
    +
    + +
    + +
    +

    B16. Annotation (citações)

    +

    Anexadas a blocos text via annotations[]. No novo schema, a citação é tipada como url_citation.

    +
    + + + + + + + + +
    CampoTipoNotas
    typeconst"url_citation" (novo schema).
    urlstringURL da fonte.
    titlestringTítulo da fonte.
    start_index / end_indexintegerIntervalo de caracteres do texto citado.
    +
    +
    Mudança: o schema legado usava { start_index, end_index, source }. O novo usa { type: "url_citation", url, title, start_index, end_index }.
    +
    + +
    +

    B17. Tool schemas (poliforme por type)

    +
    + + + + + + + + + + + + + +
    typeCamposNotas
    functionname, description, parameters (JSON Schema)Função personalizada (client-side).
    google_searchsearch_types[]web_search | image_search | enterprise_web_search.
    google_mapslatitude, longitude, enable_widgetGrounding geográfico + widget token.
    code_execution—Sandbox Python.
    url_context—Busca e lê URLs do prompt.
    computer_useenvironment (browser), excluded_predefined_functions[]Preview. Suportado em gemini-3-flash-preview (nativo) e gemini-2.5-computer-use-preview-10-2025; gemini-3.5-flash não suporta.
    file_searchfile_search_store_names[], metadata_filter, top_kRAG gerenciado.
    mcp_servername, url, headers, allowed_tools ({ mode, tools[] })MCP remoto. mode ∈ auto|any|none|validated.
    retrievalretrieval_types[] (vertex_ai_search), vertex_ai_search_config (datastores[], engine)Vertex AI Search.
    +
    +
    + Exemplo: declaração de function + google_search combinadas +
    +
    "tools": [
    +  { "type": "google_search" },
    +  { "type": "function", "name": "get_weather",
    +    "description": "Get the current weather in a given location",
    +    "parameters": {
    +      "type": "object",
    +      "properties": { "location": { "type": "string" } },
    +      "required": ["location"]
    +    }
    +  }
    +]
    +
    +
    + +
    + +
    +

    B18. InteractionSseEvent (streaming)

    +

    Com stream=true, o servidor emite eventos text/event-stream, discriminados por event_type. Todo evento traz event_id (use com last_event_id para retomar).

    +
    + + + + + + + + + + + + +
    event_typePayloadQuando
    interaction.createdinteraction, event_idInício — interação criada (status: in_progress).
    interaction.in_progressinteraction_id, status, event_idProgresso da interação (schema novo; substitui o legado interaction.status_update).
    interaction.requires_actioninteraction_id, status, event_idAguarda ação do cliente (ex.: function_result pendente).
    step.startindex, step, event_idNovo step inicia (ex.: { "type": "model_output" }).
    step.deltaindex, delta, event_idFragmento incremental — ex.: { "type": "text", "text": "Hello" }.
    step.stopindex, event_idStep finalizado.
    interaction.completedinteraction, event_idFim — interaction com outputs vazios (use os deltas anteriores).
    errorerror (code, message), event_idFalha no stream.
    +
    +
    + Renomeações (schema legado → novo): interaction.start→interaction.created, content.start→step.start, content.delta→step.delta, content.stop→step.stop, interaction.complete→interaction.completed, interaction.status_update→interaction.in_progress/interaction.requires_action (o status_update legado foi removido em 08/06/2026). Acumule arguments_delta de function calls e só faça JSON.parse após step.stop. +
    +
    + Exemplo: sequência de eventos para "Hello" +
    +
    {"event_type":"interaction.created","interaction":{"id":"v1_...","status":"in_progress"},"event_id":"evt_1"}
    +{"event_type":"step.start","index":0,"step":{"type":"model_output"},"event_id":"evt_2"}
    +{"event_type":"step.delta","index":0,"delta":{"type":"text","text":"Hello"},"event_id":"evt_3"}
    +{"event_type":"step.stop","index":0,"event_id":"evt_4"}
    +{"event_type":"interaction.completed","interaction":{"id":"v1_...","status":"completed"},"event_id":"evt_5"}
    +
    +
    + +
    + +
    +

    B19. ModelOption

    +

    Conjunto de modelos atuais recomendados para a Interactions API (verificado em 2026-06-10). A enum aceita outros valores, mas este guia foca exclusivamente nos modelos atuais — para reasoning/multimodal avançado use gemini-3.1-pro-preview.

    +
    + + + + + + + + + + + + +
    Model IDUso
    gemini-3.5-flashTexto/chat, agêntico e código em escala (GA — padrão recomendado).
    gemini-3.1-pro-previewPro — SOTA em raciocínio e multimodal.
    gemini-3.1-flash-liteCusto-eficiente, alto volume, agêntico simples.
    gemini-3.1-flash-imageNano Banana 2 — geração/edição de imagem.
    gemini-3.1-flash-tts-previewTTS (text-to-speech) de baixa latência.
    gemini-3.1-flash-live-previewLive API — diálogo de voz em tempo real (áudio-para-áudio).
    gemini-3-flash-previewComputer Use com suporte nativo (modelo mais recente com CU embutido).
    gemini-2.5-computer-use-preview-10-2025Computer Use — modelo dedicado (única exceção 2.5, pois não há equivalente 3.x).
    +
    +
    STT / transcrição: não há modelo STT dedicado — a transcrição é feita por compreensão de áudio em qualquer modelo multimodal 3.x. Use gemini-3.5-flash (mais capaz) ou gemini-3.1-flash-lite (mais barato; a doc o recomenda explicitamente para transcrição em volume). Para transcrição em tempo real, use a Live API (gemini-3.1-flash-live-preview).
    +
    + +
    +

    B20. AgentOption

    +
    + + + + + + + +
    Agent IDDescrição
    deep-research-preview-04-2026Gemini Deep Research Agent — planeja e executa pesquisa multi-etapa com relatórios citados.
    deep-research-max-preview-04-2026Gemini Deep Research Max Agent — máxima abrangência entre centenas de fontes.
    antigravity-preview-05-2026Antigravity Agent — agente gerenciado de propósito geral (Gemini 3.5 Flash) com sandbox Linux: código, arquivos e web. Ver §18.9.
    +
    +
    Limitações Deep Research: não suporta function calling personalizado (use MCP) nem saída estruturada. Recomenda-se background=true + polling, ou webhook.
    +
    Limitações Antigravity: entrada só text/image; sem saída estruturada, function calling custom ou MCP; background=true não suportado, store=true obrigatório; temperature/top_p/top_k/stop_sequences/max_output_tokens retornam 400.
    +
    + +
    +

    B21. Erros

    +

    Erros seguem o formato { "error": { "code": "...", "message": "..." } }. Em SSE, chegam como evento error. code é um identificador textual (ex.: not_found).

    +
    + + + + + + + + + +
    HTTPCausa comumAção
    400Schema inválido; response_format sem mime_type; mismatch de function_result (id/name/contagem).Corrija o corpo; alinhe call_id/name/contagem.
    401 / 403Chave ausente/ inválida; sem acesso ao modelo/agente.Verifique x-goog-api-key e permissões.
    404 (not_found)previous_interaction_id expirado/excluído; ID inexistente.Recrie a conversa; cheque retenção (55d pago / 1d free).
    429Rate limit / quota.Backoff exponencial; considere service_tier: priority.
    5xxErro do servidor.Retry idempotente com backoff.
    +
    +
    + +
    +

    Parte C — Migração de generateContent → Interactions API

    +

    Cada cenário mostra o código antes (generateContent / models.generate_content) e depois (interactions.create), lado a lado. Use isto como receita de transição. generateContent permanece totalmente suportado — migre por escolha, não por obrigação (exceto onde recursos novos só existem na Interactions API).

    +
    + +
    +

    C1. Visão geral da migração

    +

    A Interactions API é o novo primitivo recomendado para projetos novos e agênticos. Diferenças conceituais centrais:

    +
    + + + + + + + + + + + +
    DimensãogenerateContentInteractions API
    Métodoclient.models.generate_content()client.interactions.create()
    Entradacontents (array de Content com parts)input (string, blocos ou steps tipados)
    Saídacandidates[].content.parts[]steps[] (timeline tipada) + output_text
    EstadoStateless — você reenvia todo o históricoServer-side via previous_interaction_id (ou stateless com store=false)
    Configconfig / generation_configgeneration_config (interaction-scoped)
    Tarefas longasNão nativobackground=true + polling/webhook
    Agentes—Deep Research, Antigravity, managed agents (custom)
    +
    +
    Quando NÃO migrar ainda: se você depende de Batch API, cache explícito, video_metadata ou chamada automática de função (Python), permaneça em generateContent até esses recursos chegarem à Interactions API.
    + +
    + +
    +

    C2. Breaking changes — Maio 2026

    +
    +

    ✅ Status em 2026-06-10 — transição concluída. Desde 08/06/2026 o schema novo (steps + response_format polimórfico) é o único aceito: o schema legado (outputs) foi removido permanentemente, o header Api-Revision passou a ser ignorado e a janela de rollback com Api-Revision: 2026-05-07 fechou em 08/06/2026 — não há mais como voltar. SDKs google-genai/@google/genai 1.x estão quebrados para Interactions; se algo ainda lê outputs ou envia response_mime_type, está falhando em produção — atualize para v2.0.0+ e o schema steps imediatamente. [guia oficial de migração]

    +
    +

    A versão de Maio/2026 do schema da Interactions API (SDK google-genai v2.0.0+; último PyPI 2.11.0, verificado em 2026-07-12) introduziu mudanças incompatíveis. Durante a transição o header Api-Revision controlava o opt-in e depois o rollback; desde 08/06/2026 ele é ignorado e não há rollback (ver status acima).

    + +

    Mudanças de formato

    +
    +
    +
    Antes — schema legado
    +
    {
    +  "outputs": [
    +    { "type": "text", "text": "Hello!" }
    +  ]
    +}
    +
    +
    +
    Depois — novo schema
    +
    {
    +  "steps": [
    +    { "type": "model_output",
    +      "content": [ { "type": "text", "text": "Hello!" } ] }
    +  ]
    +}
    +
    +
    + +
    +
    +
    Antes — response_mime_type + image_config
    +
    {
    +  "response_mime_type": "application/json",
    +  "generation_config": {
    +    "image_config": { "aspect_ratio": "1:1", "image_size": "1K" }
    +  }
    +}
    +
    +
    +
    Depois — response_format unificado
    +
    {
    +  "response_format": [
    +    { "type": "text", "mime_type": "application/json", "schema": { } },
    +    { "type": "image", "mime_type": "image/jpeg",
    +      "aspect_ratio": "1:1", "image_size": "1K" }
    +  ]
    +}
    +
    +
    + +

    Renomeação de eventos SSE

    +
    + + + + + + + + + +
    LegadoNovo
    interaction.startinteraction.created
    content.startstep.start
    content.deltastep.delta
    content.stopstep.stop
    interaction.completeinteraction.completed
    +
    + +

    Outras quebras

    +
      +
    • function_call agora vive dentro de steps[] (não em outputs), com id, name, arguments.
    • +
    • Step thought ganha summary[] + signature.
    • +
    • Grounding: result.rendered_content → result.search_suggestions; google_search_call/google_search_result migram para steps e ganham signature.
    • +
    • Annotations: { start_index, end_index, source } → { type: "url_citation", url, title, start_index, end_index }.
    • +
    • O GET agora prefixa um step user_input na timeline.
    • +
    +
    + SDK 1.x falha desde 08/06/2026: conforme anunciado ("As versões do SDK Python 1.x.x e JS 1.x.x vão falhar nas chamadas da API Interactions"), as chamadas em SDK 1.x agora falham. Atualize para google-genai v2.0.0+ / @google/genai v2.0.0+. +
    + +
    + +
    +

    C3. Texto simples

    +
    +
    +
    Antes — generateContent
    +
    from google import genai
    +
    +client = genai.Client()
    +response = client.models.generate_content(
    +    model="gemini-3.5-flash",
    +    contents="How does AI work?",
    +)
    +print(response.text)
    +
    +
    +
    Depois — Interactions API
    +
    from google import genai
    +
    +client = genai.Client()
    +interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="How does AI work?",
    +)
    +print(interaction.output_text)
    +
    +
    +
      +
    • models.generate_content → interactions.create
    • +
    • contents → input · response.text → interaction.output_text
    • +
    +
    + +
    +

    C4. Chat multi-turno

    +

    A maior mudança: você não reenvia o histórico — encadeia via previous_interaction_id.

    +
    +
    +
    Antes — histórico manual
    +
    history = [
    +    {"role": "user", "parts": [{"text": "Hello!"}]},
    +    {"role": "model", "parts": [{"text": "Hi! How can I help?"}]},
    +    {"role": "user", "parts": [{"text": "Capital of France?"}]},
    +]
    +response = client.models.generate_content(
    +    model="gemini-3.5-flash",
    +    contents=history,
    +)
    +print(response.text)
    +
    +
    +
    Depois — estado server-side
    +
    i1 = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Hello!",
    +)
    +i2 = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Capital of France?",
    +    previous_interaction_id=i1.id,
    +)
    +print(i2.output_text)
    +
    +
    +
    Cache implícito: encadear com previous_interaction_id permite ao servidor reaproveitar o histórico em cache — mais barato e rápido que reenviar tudo.
    +
    Interaction-scoped: tools, system_instruction e generation_config NÃO são herdados pelo previous_interaction_id — reespecifique-os a cada turno.
    +
    + +
    +

    C5. Streaming

    +
    +
    +
    Antes — generate_content_stream
    +
    stream = client.models.generate_content_stream(
    +    model="gemini-3.5-flash",
    +    contents="Write a poem.",
    +)
    +for chunk in stream:
    +    print(chunk.text, end="")
    +
    +
    +
    Depois — stream de steps
    +
    stream = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Write a poem.",
    +    stream=True,
    +)
    +for event in stream:
    +    if event.type == "step.delta" and event.delta.type == "text":
    +        print(event.delta.text, end="")
    +
    +
    +
      +
    • O stream agora emite eventos tipados (interaction.created, step.start/delta/stop, interaction.completed) em vez de chunks de texto homogêneos.
    • +
    • Filtre step.delta com delta.type == "text" para a saída textual; outros deltas carregam thoughts, imagens ou argumentos de função.
    • +
    +
    + +
    +

    C6. Multimodal (imagem / áudio / vídeo / PDF)

    +

    Em vez de types.Part.from_bytes, use blocos de conteúdo tipados no input.

    +
    +
    +
    Antes — Part.from_bytes
    +
    from google.genai import types
    +
    +response = client.models.generate_content(
    +    model="gemini-3.5-flash",
    +    contents=[
    +        types.Part.from_bytes(
    +            data=img_bytes, mime_type="image/png"),
    +        "What is in this picture?",
    +    ],
    +)
    +print(response.text)
    +
    +
    +
    Depois — blocos tipados
    +
    interaction = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +        { "type": "text", "text": "What is in this picture?" },
    +        { "type": "image", "data": base64_img,
    +          "mime_type": "image/png" },
    +    ],
    +)
    +print(interaction.output_text)
    +
    +
    +
      +
    • Tipos de bloco: text, image, audio, document (PDF), video (aceita uri do YouTube).
    • +
    • Posicione mídias grandes (PDF/documento) no início do input para maximizar cache; para uma única imagem/PDF curto, coloque o texto depois da mídia.
    • +
    • ainda só em generateContent video_metadata (cortes, FPS customizado).
    • +
    +
    + +
    +

    C7. Geração de imagem

    +
    +
    +
    Antes — response_modalities + image_config
    +
    response = client.models.generate_content(
    +    model="gemini-3.1-flash-image",
    +    contents="A robot holding a red skateboard",
    +    config=types.GenerateContentConfig(
    +        response_modalities=["IMAGE"],
    +        image_config=types.ImageConfig(aspect_ratio="16:9"),
    +    ),
    +)
    +
    +
    +
    Depois — response_format tipo image
    +
    interaction = client.interactions.create(
    +    model="gemini-3.1-flash-image",
    +    input="A robot holding a red skateboard",
    +    response_format={
    +        "type": "image",
    +        "mime_type": "image/jpeg",
    +        "aspect_ratio": "16:9",
    +        "image_size": "1K",
    +    },
    +)
    +img = interaction.output_image
    +
    +
    +
      +
    • image_config (dentro de generation_config) → entrada image em response_format.
    • +
    • Acesse a imagem por interaction.output_image; para histórias intercaladas texto+imagem, itere steps.
    • +
    • Edição: encadeie com previous_interaction_id e peça a alteração (ex.: trocar idioma do gráfico).
    • +
    +
    + +
    +

    C8. Function calling

    +

    O loop muda de "monte contents com functionResponse" para "envie um step function_result com call_id".

    +
    +
    +
    Antes — functionResponse em contents
    +
    resp = client.models.generate_content(
    +    model="gemini-3.5-flash",
    +    contents=contents,
    +    config=types.GenerateContentConfig(tools=[tool]),
    +)
    +fc = resp.candidates[0].content.parts[0].function_call
    +# ... executa ...
    +contents.append({"role": "user", "parts": [{
    +    "function_response": {
    +        "name": fc.name,
    +        "response": {"result": result},
    +    }}]})
    +final = client.models.generate_content(
    +    model="gemini-3.5-flash", contents=contents,
    +    config=types.GenerateContentConfig(tools=[tool]))
    +
    +
    +
    Depois — step function_result
    +
    i = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Weather in Boston?",
    +    tools=[tool],
    +)
    +fc = i.steps[-1]  # type == "function_call"
    +# ... executa ...
    +final = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    previous_interaction_id=i.id,
    +    tools=[tool],
    +    input=[{
    +        "type": "function_result",
    +        "name": fc.name,
    +        "call_id": fc.id,
    +        "result": [{"type": "text", "text": json.dumps(result)}],
    +    }],
    +)
    +print(final.output_text)
    +
    +
    +
    + Correspondência estrita (Gemini 3.x): todo function_result deve incluir o call_id (= id do call) e o name correspondente, e haver exatamente um resultado por chamada. A Interactions API retorna erro em mismatch (generateContent apenas degrada silenciosamente). +
    +
      +
    • Status intermediário: requires_action enquanto aguarda o function_result.
    • +
    • Respostas multimodais: inclua imagem/áudio dentro do result, não como parte separada.
    • +
    • Instruções extras: anexe ao final do texto do resultado, separadas por duas quebras de linha.
    • +
    • só em generateContent chamada automática de função (Python).
    • +
    +
    + +
    +

    C9. Structured Output (JSON)

    +
    +
    +
    Antes — response_schema
    +
    resp = client.models.generate_content(
    +    model="gemini-3.5-flash",
    +    contents="List 3 cookie recipes",
    +    config=types.GenerateContentConfig(
    +        response_mime_type="application/json",
    +        response_schema=Recipe,
    +    ),
    +)
    +print(resp.text)
    +
    +
    +
    Depois — response_format tipo text
    +
    i = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="List 3 cookie recipes",
    +    response_format={
    +        "type": "text",
    +        "mime_type": "application/json",
    +        "schema": {
    +            "type": "object",
    +            "properties": {
    +                "recipe_name": {"type": "string"},
    +                "ingredients": {
    +                    "type": "array",
    +                    "items": {"type": "string"}},
    +            },
    +            "required": ["recipe_name", "ingredients"],
    +        },
    +    },
    +)
    +print(i.output_text)
    +
    +
    +
      +
    • response_mime_type + response_schema → um único response_format tipo text com mime_type: "application/json" e schema.
    • +
    • Pode combinar JSON com ferramentas (Search, URL context, code execution, function calling) na mesma requisição em Gemini 3.x.
    • +
    +
    + +
    +

    C10. Thinking

    +
    +
    +
    Antes — thinking_budget
    +
    resp = client.models.generate_content(
    +    model="gemini-3.5-flash",
    +    contents="Prove sqrt(2) is irrational.",
    +    config=types.GenerateContentConfig(
    +        thinking_config=types.ThinkingConfig(
    +            thinking_budget=7500,
    +        ),
    +    ),
    +)
    +
    +
    +
    Depois — thinking_level
    +
    i = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Prove sqrt(2) is irrational.",
    +    generation_config={"thinking_level": "high"},
    +)
    +# thoughts aparecem como steps type=="thought"
    +for s in i.steps:
    +    if s.type == "thought":
    +        print(s.summary)
    +
    +
    +
      +
    • thinking_budget (numérico) → thinking_level (minimal|low|medium|high). Default em Gemini 3.5 Flash: medium.
    • +
    • Na Interactions API o raciocínio é exposto como steps thought com summary + signature, em ordem cronológica.
    • +
    • Preservação automática: o contexto de raciocínio é mantido entre turnos automaticamente (em generateContent é implícito, exigindo reenviar o histórico com signatures).
    • +
    +
    Nunca modifique blocos thought nem suas signature. Em modo store=false, reenvie-os exatamente como recebidos.
    +
    + +
    +

    C11. Caching

    +
    +
    +
    Antes — cache explícito
    +
    cache = client.caches.create(
    +    model="gemini-3.5-flash",
    +    config=types.CreateCachedContentConfig(
    +        contents=[big_document],
    +        ttl="3600s",
    +    ),
    +)
    +resp = client.models.generate_content(
    +    model="gemini-3.5-flash",
    +    contents="Summarize it",
    +    config=types.GenerateContentConfig(
    +        cached_content=cache.name),
    +)
    +
    +
    +
    Depois — cache implícito
    +
    # 1º turno com o documento grande no início
    +i1 = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input=[
    +      {"type": "document", "data": pdf_b64,
    +       "mime_type": "application/pdf"},
    +      {"type": "text", "text": "Read this."},
    +    ],
    +)
    +# turnos seguintes reaproveitam o cache automaticamente
    +i2 = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Summarize it",
    +    previous_interaction_id=i1.id,
    +)
    +
    +
    +
      +
    • Cache explícito (caches.create / cached_content) ainda é exclusivo de generateContent.
    • +
    • Na Interactions API, o cache é implícito: encadeie com previous_interaction_id e mantenha conteúdo estável no início do prompt.
    • +
    • Acompanhe o aproveitamento por usage.total_cached_tokens.
    • +
    +
    + + + +
    +

    C13. Streaming + Tools (acúmulo de argumentos)

    +

    Em streaming com function calling, os argumentos chegam fragmentados. Acumule e só faça parse no fim do step.

    +
    buffers = {}  # index -> string de argumentos
    +stream = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    input="Weather in Boston and Paris?",
    +    tools=[weather_tool],
    +    stream=True,
    +)
    +for event in stream:
    +    if event.event_type == "step.start" and event.step.type == "function_call":
    +        buffers[event.index] = ""
    +    elif event.event_type == "step.delta" and event.delta.type == "arguments_delta":
    +        buffers[event.index] += event.delta.arguments
    +    elif event.event_type == "step.stop" and event.index in buffers:
    +        args = json.loads(buffers[event.index])  # parse só agora
    +        # ... despacha a função ...
    +
    Regra de ouro: nunca faça JSON.parse/json.loads em arguments_delta parcial — espere o step.stop do índice correspondente.
    +
    + +
    +

    C14. Tabela completa de mapeamento

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    generateContentInteractions APIObservação
    client.models.generate_content()client.interactions.create()Método principal.
    generate_content_stream()create(..., stream=True)Streaming.
    contentsinputString, blocos ou steps tipados.
    Content.parts[]content[] (blocos tipados)text/image/audio/document/video.
    role: "user"/"model"step user_input/model_outputPapéis viram tipos de step.
    config / GenerateContentConfiggeneration_configInteraction-scoped.
    system_instructionsystem_instructionReenviar a cada turno.
    response.textinteraction.output_textConveniência.
    imagem em partsinteraction.output_imageConveniência.
    candidates[]steps[]Timeline tipada.
    candidate.content.parts[]step.content[]—
    finish_reasoninteraction.statuscompleted/requires_action/…
    response_mime_type + response_schemaresponse_format (tipo text)mime_type + schema.
    response_modalities + image_configresponse_format (tipo image) ou arrayModalidades unificadas.
    thinking_config.thinking_budgetgeneration_config.thinking_levelEnum em vez de número.
    function_call (part)step function_call (id,name,arguments)—
    function_response (part)step function_result (call_id,name,result)Match estrito.
    tools=[Tool(google_search=...)]tools=[{"type":"google_search"}]Schema textual.
    grounding_metadatasteps *_call/*_result + annotationsurl_citation.
    caches.create + cached_contentprevious_interaction_id (cache implícito)Explícito ainda só em generateContent.
    histórico manual em contentsprevious_interaction_id (store=true)ou stateless com store=false.
    —background=true + cancel + webhooksTarefas longas / Deep Research.
    +
    +
    + +
    +

    C15. Checklist de migração

    +
      +
    • ☐ Atualizar SDK: google-genai >= 2.0.0 (Python) / @google/genai equivalente — obrigatório desde 08/06/2026 (SDKs 1.x falham).
    • +
    • ☐ Trocar models.generate_content → interactions.create.
    • +
    • ☐ contents → input; response.text → output_text.
    • +
    • ☐ Adotar previous_interaction_id para chat (ou manter store=false se gerencia histórico no cliente).
    • +
    • ☐ Migrar leitura de saída: candidates → steps; tratar status == requires_action.
    • +
    • ☐ Function calling: enviar function_result com call_id + name casados (1:1).
    • +
    • ☐ response_mime_type/response_schema/image_config → response_format.
    • +
    • ☐ thinking_budget → thinking_level; remover temperature/top_p/top_k (Gemini 3.x).
    • +
    • ☐ Atualizar nomes de eventos SSE (content.* → step.*, etc.).
    • +
    • ☐ Atualizar annotations para url_citation e grounding para search_suggestions.
    • +
    • ☐ Reduzir tool calls excessivos via thinking_level menor + instrução de orçamento de ferramentas.
    • +
    • ☐ Verificar recursos ausentes (Batch, cache explícito, video_metadata, auto-function-calling) — manter em generateContent se necessário.
    • +
    +
    Automação: agentes de código com skills (ex.: Antigravity) podem instalar a skill Gemini Interactions API e rodar /gemini-interactions-api migrate my app to Gemini 3.5 Flash.
    +
    + +
    +

    C16. Histórico sem estado (store=false)

    +

    Se você prefere gerenciar o histórico no cliente (sem persistência server-side), use store=false e reenvie a timeline completa como input (array de steps).

    +
    i = client.interactions.create(
    +    model="gemini-3.5-flash",
    +    store=False,
    +    input=[
    +        {"type": "user_input",
    +         "content": [{"type": "text", "text": "Hello!"}]},
    +        {"type": "model_output",
    +         "content": [{"type": "text", "text": "Hi! How can I help?"}]},
    +        {"type": "user_input",
    +         "content": [{"type": "text", "text": "Capital of France?"}]},
    +    ],
    +)
    +print(i.output_text)
    +
    Restrições do store=false: incompatível com background=true e impede usar previous_interaction_id nos turnos seguintes. Reenvie blocos thought/signature intactos.
    +
    + +
    +

    C17. Datas críticas & estratégia

    +
    + + + + + + + + +
    DataEventoAção
    30/11/2025Bibliotecas legadas descontinuadas (google-generativeai etc.).Migrar para google-genai / @google/genai.
    07/05/2026Novo schema disponível para opt-in.Envie Api-Revision: 2026-05-20 para testar.
    26/05/2026Novo schema virou padrão.Opt-out temporário era possível com Api-Revision: 2026-05-07 (janela encerrada).
    08/06/2026Schema legado removido (consumado); SDK 1.x falha.Estar em SDK v2.0.0+ e novo schema. Header Api-Revision é ignorado desde então.
    +
    +
    Janela encerrada: a remoção do schema legado foi consumada em 08/06/2026 — não há rollback e o header Api-Revision é ignorado. Chamadas em SDK 1.x ou no schema legado falham; se ainda não migrou, atualize para google-genai/@google/genai v2.0.0+ e o schema steps imediatamente.
    + +
    + +
    +

    Apêndice

    +
    + +
    +

    Ap1. Cookbook (notebooks oficiais)

    +

    Notebooks do repositório google-gemini/cookbook que usam a Interactions API (client.interactions.*), verificados em 2026-05-24.

    +
    + + + + + + + + +
    NotebookO que demonstra
    quickstarts/Get_started_interactions_api.ipynbGuia inicial da Interactions API: interface unificada modelo+agente, estado server-side, orquestração de ferramentas, texto, multi-turn e tool use.
    quickstarts/Get_started_Deep_Research.ipynbAgente Deep Research via Interactions API: criar interação long-running e fazer polling do status até concluir.
    quickstarts/Get_started_managed_agents.ipynbAgentes gerenciados/custom em VMs isoladas; continuação multi-turn via environment_id + previous_interaction_id.
    quickstarts/Webhooks.ipynbWebhooks para notificação de conclusão de operações assíncronas (inclui Interactions), evitando polling.
    +
    +
    + Ainda em generate_content (não migrados): Function_calling.ipynb, Streaming.ipynb, Caching.ipynb, JSON_mode.ipynb, Enum.ipynb e Get_started.ipynb usam a API legada — não os trate como exemplos de Interactions API. O quickstarts/README.md ainda não tem seção dedicada à Interactions API. +
    +
    + +
    +

    Ap2. Glossário

    +
    + + + + + + + + + + + + + + + +
    TermoDefinição
    InteractionRecurso central — uma rodada completa de execução (entradas, raciocínio, tool calls, saída) como timeline de steps.
    stepItem tipado da timeline (user_input, model_output, thought, *_call, *_result). Substitui candidates/outputs.
    previous_interaction_idID encadeado que ativa estado server-side e cache implícito do histórico.
    storePersistência da interação (default true; false = stateless).
    backgroundExecução assíncrona para tarefas longas; combinada com polling ou webhook.
    signatureHash de validação backend anexado a steps (thought, tool calls). Nunca modificar.
    thinking_levelEsforço de raciocínio: minimal|low|medium|high. Substitui thinking_budget.
    response_formatFormato de saída unificado (text/JSON, image, audio). Absorve response_mime_type + image_config.
    Api-RevisionHeader de versionamento do schema durante a transição de Maio/2026. Ignorado desde 08/06/2026 — o schema steps é o único aceito.
    Cache implícitoReaproveitamento automático do histórico quando se usa previous_interaction_id.
    Deep ResearchAgentes (deep-research-*) para pesquisa longa; sem function calling custom (use MCP) nem saída estruturada.
    +
    +
    + +
    +

    Ap3. Histórico deste guia

    +
      +
    • 2026-05-24 — Versão completa: Parte A (23 capítulos de conceitos/guias), Parte B (referência REST: endpoints, recursos, steps, tools, SSE, modelos/agentes, erros) e Parte C (17 cenários de migração antes/depois + breaking changes Maio/2026 + checklist + datas). Apêndice com cookbook verificado e glossário.
    • +
    • 2026-05-24 (revisão de modelos) — Padronização para apenas os modelos atuais: gemini-3.5-flash, gemini-3.1-pro-preview, gemini-3.1-flash-lite, gemini-3.1-flash-image (Nano Banana 2), TTS gemini-3.1-flash-tts-preview e Live gemini-3.1-flash-live-preview. Exceção: Computer Use usa gemini-3-flash-preview (suporte nativo) e gemini-2.5-computer-use-preview-10-2025 (dedicado), pois não há equivalente 3.5/3.1.
    • +
    • 2026-06-10 — Varredura de atualização: remoção do schema legado tratada como fato consumado em 08/06/2026 — steps[] é o único schema, header Api-Revision ignorado, janela de rollback fechada e SDKs google-genai/@google/genai 1.x quebrados para Interactions (mínimo agora: 2.0.0; último PyPI/npm: 2.8.0). Prosa de transição convertida para o passado (Sobre, TL;DR, §1.4, §2.2, §6, B2, B18, C2, C15, C17, glossário). Nuance adicionada: a página oficial migrate-to-interactions agora descreve a Interactions API como "the standard interface for building with Gemini" e a recomenda para todo desenvolvimento novo; a overview mantém Beta + generateContent para produção estável. Datas de verificação re-stampadas para 2026-06-10.
    • +
    • 2026-06-11 — Reorganização da doc oficial absorvida: a Interactions API ganhou seção própria (/docs/interactions/*) com novo quickstart (interactions/quickstart) e overview (interactions/interactions-overview); URLs de ferramentas/guias atualizadas para os caminhos canônicos /interactions/... (google-search, maps-grounding, code-execution, url-context, computer-use, file-search, tool-combination, webhooks, files, file-input-methods, media-resolution). Nova cobertura de agentes gerenciados: Antigravity agent (antigravity-preview-05-2026, §18.9), environments/sandboxes (§18.10), parâmetro environment/environment_id (§3.1) e AgentOption (B20). §18 renomeada para "Agentes: Deep Research & Antigravity". Reconfirmado na página de breaking changes: header Api-Revision ignorado e schema legado removido desde 08/06/2026 (exemplos oficiais ainda incluem o header; é no-op).
    • +
    • 2026-06-19 — Micro-sweep de superfície e versões. Adicionado caveat Developer API (Beta) vs Vertex / Gemini Enterprise Agent Platform (experimental) no topo (§1) e em §17.3: a Interactions API existe nas duas superfícies, mas code_execution dentro de Interactions é documentado/exemplificado só na Developer API; na Vertex a execução de código é documentada via generateContent e, em teste, code_execution via Interactions não funcionou sob auth Vertex (observação, não limitação oficial). Completada a limitação de MCP remoto (apenas Streamable HTTP; SSE não suportado; name sem hífen) em §1.5 e §22. Versões de SDK atualizadas para google-genai/@google/genai 2.9.0 — a 2.9.0 reimplementou a Interactions internamente mantendo a API pública compatível.
    • +
    +

    Fontes primárias: ai.google.dev/gemini-api/docs/interactions/interactions-overview, interactions/quickstart, ai.google.dev/api/interactions-api, interactions-breaking-changes-may-2026, migrate-to-interactions, docs/agents/antigravity-agent/agent-environment e github.com/google-gemini/cookbook; superfície Vertex em docs.cloud.google.com/gemini-enterprise-agent-platform/reference/models/interactions-api e .../models/tools/code-execution. Verificado em 2026-06-19 — para fatos perecíveis (modelos, datas, limites), consulte sempre a fonte oficial.

    +
    + + +
    +
    + + + + + + diff --git a/references/agents_tools_best_guides/guia_langgraph.html b/references/agents_tools_best_guides/guia_langgraph.html index 2b04975..fe4a417 100644 --- a/references/agents_tools_best_guides/guia_langgraph.html +++ b/references/agents_tools_best_guides/guia_langgraph.html @@ -1,3992 +1,3992 @@ - - - - - -Guia LangGraph — Referência completa (Python) - - - - - - - - -
    -
    -
    Guia LangGraph Python — Referência completa
    -
    - Verificado em 2026-07-09 - langgraph - Python - -
    -
    -
    - -
    - - -
    - -
    -

    Guia LangGraph — Referência completa (Python)

    -

    - Documentação técnica exaustiva do LangGraph em Python, o runtime - de orquestração de baixo nível usado pelo LangChain e pelo Deep Agents para - construir agentes stateful, durables e de longa duração. - Cobre StateGraph, Send, Command, - persistência (checkpointers SQLite/Postgres/Redis), human-in-the-loop, - streaming v2, memória curta e longa, multi-agent (supervisor/swarm), time - travel, durable execution e a Functional API. -

    -
    - langgraph - Python 3.10+ - SOTA · 2026-06-29 -
    -
    - -
    -

    Sobre este guia

    -

    - Este guia é uma conversão fiel da documentação oficial pública - do LangGraph em - docs.langchain.com/oss/python/langgraph, - complementada pelos pacotes prebuilt langgraph-supervisor e - langgraph-swarm e pela referência de API em - reference.langchain.com/python/langgraph. -

    -

    - A Parte A apresenta os conceitos em 26 capítulos, na ordem de - leitura recomendada. A Parte B é a referência técnica de cada - classe pública: assinatura, parâmetros em tabela, métodos relevantes e exemplos. - Todos os exemplos estão em Python — a porta oficial em JavaScript existe em - langchain-ai/langgraphjs - mas tem APIs próprias e não é coberta aqui. -

    -
    - Como ler: a Parte A ensina os padrões e a - mecânica de execução. A Parte B é consulta rápida: cada classe - traz sua assinatura, atributos em tabela e métodos em blocos - <details> expansíveis (clique no ▸ para abrir). -
    -
    - Notas de versão: alguns recursos são recentes — node timeouts - (TimeoutPolicy) e graceful drain (RunControl/ - GraphDrained) exigem langgraph >= 1.2; - DeltaChannel (otimização de armazenamento) também é 1.2+; - add_sequence exige >= 0.2.46; - context_schema substituiu config_schema em - >= 0.6.0. O default da recursion_limit passou a ser - 1000 em >= 1.0.6. -
    Atualização 2026-07-09: último PyPI langgraph 1.2.8 (2026-07-06, bugfix de checkpointing; deps: langchain-core >=1.4,<2, langgraph-checkpoint >=4.1,<5, langgraph-prebuilt >=1.1,<1.2). A 1.2.7 é bugfix sobre a 1.2.6, sem mudança de superfície pública; segue na linha 1.x (compromisso de estabilidade até a 2.0). Ressalva: "estável" não significa zero mudanças no histórico da série — a 1.2.3 foi yanked (regressão de merge) e depois corrigida na 1.2.6, e renomeou ProtocolEvent.eventId→event_id (afeta quem consome o streaming v3/protocolo beta). Fixe uma versão específica testada (ex.: ==1.2.7), não apenas >=1.2. Novidades 1.2.x além das acima: error_handler= por nó (recebe NodeError, retorna Command para compensação/reroteamento — padrão Saga; Python-only), interrupt_mode + predicado when no HumanInTheLoopMiddleware, e event streaming v2/v3 (beta, projeções tipadas por canal). Todos opt-in e retrocompatíveis. Resumo 1.2.2→1.2.4: fix de IDs estáveis para checkpoints com DeltaChannel (1.2.2); streaming v3 no RemoteGraph e rename ProtocolEvent.eventId → event_id (1.2.3 — relevante para quem consome eventos do protocolo beta v3); ensure_config agora faz merge de callbacks/tags/metadata (1.2.3); fix de compatibilidade _on_started (1.2.4); merge de lc_versions nos metadados de config e fix de updateState/DeltaChannel em thread vazia (1.2.5 — só bugfix); nested-subgraph herda checkpoint_ns do pai (regressão da 1.2.3), cancelamento de subgraphs em abort de stream v3 e Tornado→6.5.6 (1.2.6 — só bugfix). Sem mudanças nas superfícies públicas de StateGraph/interrupt/Command. -
    -
    - -
    -

    Fontes oficiais

    - -

    - Última verificação contra estas fontes: 2026-06-10. - Sempre que houver divergência entre este guia e a documentação oficial em - produção, a documentação oficial é a fonte autoritativa. -

    -
    - -
    -

    Parte A — Conceitos

    -

    Vinte e seis capítulos cobrindo o LangGraph na ordem de leitura recomendada da documentação oficial.

    -
    - -
    -

    1. Visão geral

    -

    - O LangGraph é definido pela documentação oficial como - "a low-level orchestration framework and runtime for building, managing, and - deploying long-running, stateful agents". É inspirado em Pregel, Apache Beam - e NetworkX, e modela um workflow como um grafo direcionado com três componentes: -

    -
      -
    1. State — um snapshot compartilhado, definido como - TypedDict, dataclass ou Pydantic BaseModel.
    2. -
    3. Nodes — funções Python que codificam a lógica.
    4. -
    5. Edges — funções (ou edges estáticos) que determinam a - próxima execução.
    6. -
    -

    - A execução acontece em super-steps discretos via passagem de mensagens: - nós começam inactive, ficam active ao receber mensagens e a - execução termina quando todos os nós estão inativos e não há mensagens em - trânsito. Nós que rodam em paralelo compartilham o mesmo super-step; sequenciais - ocupam super-steps distintos. -

    -

    Benefícios principais

    -
    - - - - - - - - - -
    BenefícioDescrição
    Durable executionAgentes persistem por falhas e retomam de checkpoints.
    Human-in-the-loopInspeção e modificação do estado do agente em qualquer ponto.
    Memória abrangenteWorking memory por thread + memória de longo prazo cross-session.
    DebuggingLangSmith provê visualização de traces e métricas de runtime.
    DeploymentInfra escalável para workflows stateful de longa duração.
    -
    -

    Posição no ecossistema

    -
    - - - - - - - - - - -
    ProdutoPapel
    Deep AgentsHarness do agente: planning, subagents, FS, gerenciamento de contexto.
    LangChainFramework de agente: abstrações de modelo/tool e o agent loop.
    LangGraphRuntime de orquestração: durable execution, streaming, HITL.
    LangSmithTracing, evaluations, prompts, deployment.
    LangSmith EngineDetecta issues em traces de produção e propõe correções/PRs automaticamente.
    LangSmith FleetConstrutor no-code de agentes.
    -
    - -
    - -
    -

    2. Instalação

    -
    pip install -U langgraph
    -# ou
    -uv add langgraph
    -

    - Pacotes complementares conforme o uso: -

    -
    - - - - - - - - - - - -
    PacotePropósito
    langgraphNúcleo (StateGraph, runtime, in-memory checkpointer).
    langgraph-checkpoint-sqliteSqliteSaver / AsyncSqliteSaver.
    langgraph-checkpoint-postgresPostgresSaver / AsyncPostgresSaver.
    langgraph-checkpoint-redisRedisSaver / AsyncRedisSaver (community Redis).
    langgraph-supervisorPadrão supervisor multi-agent (create_supervisor).
    langgraph-swarmPadrão swarm (create_swarm).
    langchain / langchain-openai / langchain-anthropic / langchain-google-genaiModelos e mensagens — opcionais, mas a maior parte dos exemplos depende deles.
    -
    -

    O overview oficial não declara versão mínima de Python; na prática, o pacote suporta Python 3.10+.

    - -

    Política de integração de modelos (chat models)

    -

    - O LangGraph não fala com provedores diretamente — ele orquestra - chat models do LangChain. Como cada classe roteia para uma API - diferente, vale fixar a política antes dos exemplos: -

    -
    - - - - - - - -
    ProvedorClasse / pacoteAPI atingida
    OpenAIChatOpenAI · langchain-openaiResponses API quando use_responses_api=True; caso contrário, Chat Completions.
    AnthropicChatAnthropic · langchain-anthropicMessages API nativa da Anthropic (SDK anthropic) — não é wrapper.
    GoogleChatGoogleGenerativeAI · langchain-google-genaiSDK consolidado google-genai (v4.0.0+), via generateContent.
    -
    -
    - OpenAI — Responses API não é automática com string. Passar uma - string "openai:gpt-5.5" a create_agent/create_react_agent - cai em Chat Completions. Para garantir a Responses API (ex.: ZDR, - threading server-side), instancie ChatOpenAI(model="gpt-5.5", use_responses_api=True) - e passe o objeto como model=. -
    -
    from langchain_openai import ChatOpenAI
    -from langchain_anthropic import ChatAnthropic
    -from langchain_google_genai import ChatGoogleGenerativeAI
    -
    -# OpenAI — Responses API (NUNCA Chat Completions): use a flag explícita.
    -openai_llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    -
    -# Anthropic — SDK nativo (Messages API):
    -anthropic_llm = ChatAnthropic(model="claude-sonnet-4-6")
    -
    -# Google — SDK google-genai (>= 4.0); em strings provider:model use "google_genai:"
    -google_llm = ChatGoogleGenerativeAI(model="gemini-3.5-flash")  # str: "google_genai:gemini-3.5-flash"
    -
    -# (opcional) threading server-side por response id no OpenAI:
    -openai_llm = ChatOpenAI(model="gpt-5.4-mini", use_previous_response_id=True)
    -

    - O roteamento para a Responses API também é automático (sem a - flag) quando o modelo usa: (a) built-in tools (web_search, - file_search, image generation, computer use, code interpreter, - remote MCP), (b) o parâmetro reasoning={"effort": ..., "summary": ...}, - ou (c) previous_response_id na invocação. Não existe flag - output_version nem um ID de modelo que "force" Responses — o caminho - é use_responses_api=True ou um desses gatilhos. -

    -
    # Estes já roteiam para a Responses API automaticamente:
    -llm        = ChatOpenAI(model="gpt-5.5", reasoning={"effort": "medium", "summary": "auto"})
    -llm_tools  = ChatOpenAI(model="gpt-5.4-mini").bind_tools([{"type": "web_search_preview"}])
    -
    - Gemini Interactions API: a Interactions API do Gemini (endpoint - /interactions, stateful/agêntica) não tem integração - nativa com LangChain/LangGraph/Deep Agents (maio/2026). - ChatGoogleGenerativeAI usa generateContent via - google-genai; recursos exclusivos da Interactions API - (histórico server-side via previous_interaction_id, agentes - gerenciados) não são expostos. Não existe - ChatGoogleGenerativeAI(use_interactions_api=...). Para usá-la hoje, - chame o SDK google-genai diretamente — a Interactions API é coberta - no guia dedicado Gemini Interactions API. -
    - -
    - -
    -

    3. Modelo conceitual

    -

    Hello-world

    -
    from langgraph.graph import StateGraph, MessagesState, START, END
    -
    -def mock_llm(state: MessagesState):
    -    return {"messages": [{"role": "ai", "content": "hello world"}]}
    -
    -graph = StateGraph(MessagesState)
    -graph.add_node(mock_llm)
    -graph.add_edge(START, "mock_llm")
    -graph.add_edge("mock_llm", END)
    -graph = graph.compile()
    -
    -graph.invoke({"messages": [{"role": "user", "content": "hi!"}]})
    -

    Super-steps

    -

    - Cada tick do grafo é um super-step. Para um pipeline sequencial - START → A → B → END, quatro checkpoints são produzidos - (vazio/inicial, após input, após A, após B). Nós com múltiplas arestas de saída - disparam todos os destinos em paralelo no super-step seguinte. -

    -

    Graph API vs Functional API

    -
    - - - - - - - - -
    AspectoFunctional APIGraph API
    Controle de fluxoPython padrão (if, for, chamadas)Estrutura explícita de grafo/DAG
    EstadoEscopo da função; sem state explícitoRequer State + reducers
    CheckpointingSalva resultados de @task no checkpoint atualNovo checkpoint após cada super-step
    VisualizaçãoNão suportada (dinâmico em runtime)Suportada; útil para debug
    -
    - -
    - -
    -

    4. StateGraph

    -

    - StateGraph é o construtor de grafo. Recebe o schema de estado e, - opcionalmente, schemas de contexto, input e output. -

    -
    from langgraph.graph import StateGraph, START, END
    -from typing_extensions import TypedDict
    -
    -class State(TypedDict):
    -    foo: int
    -    bar: list[str]
    -
    -builder = StateGraph(State)
    -# ... add_node / add_edge ...
    -graph = builder.compile()
    -

    Schemas de entrada, saída e privados

    -

    - O schema principal define o overall state. Schemas opcionais permitem - expor um contrato mais estrito para o cliente: -

    -
    class InputState(TypedDict):
    -    user_input: str
    -
    -class OutputState(TypedDict):
    -    graph_output: str
    -
    -class OverallState(TypedDict):
    -    foo: str
    -    user_input: str
    -    graph_output: str
    -
    -class PrivateState(TypedDict):
    -    bar: str
    -
    -def node_1(state: InputState) -> OverallState:
    -    return {"foo": state["user_input"] + " name"}
    -
    -def node_2(state: OverallState) -> PrivateState:
    -    return {"bar": state["foo"] + " is"}
    -
    -def node_3(state: PrivateState) -> OutputState:
    -    return {"graph_output": state["bar"] + " Lance"}
    -
    -builder = StateGraph(OverallState, input_schema=InputState, output_schema=OutputState)
    -builder.add_node("node_1", node_1)
    -builder.add_node("node_2", node_2)
    -builder.add_node("node_3", node_3)
    -builder.add_edge(START, "node_1")
    -builder.add_edge("node_1", "node_2")
    -builder.add_edge("node_2", "node_3")
    -builder.add_edge("node_3", END)
    -
    -graph = builder.compile()
    -graph.invoke({"user_input": "My"})
    -# {'graph_output': 'My name is Lance'}
    -
    - Um nó pode escrever em qualquer chave do estado — não apenas - nas que estão no seu schema de entrada. PrivateState é registrado - automaticamente quando referenciado em assinaturas de nó. -
    - -
    - -
    -

    5. Schemas de estado

    -

    - O estado pode ser declarado de três formas: TypedDict (recomendado - por performance), dataclass ou Pydantic BaseModel (com - validação recursiva, mas mais lento). -

    -
    from typing_extensions import TypedDict
    -
    -class State(TypedDict):
    -    foo: int
    -    bar: list[str]
    -
    - Limitações conhecidas do Pydantic como state schema: -
      -
    • A saída não é uma instância Pydantic.
    • -
    • Validação roda apenas nos inputs do primeiro nó.
    • -
    • O traceback não identifica o nó que falhou.
    • -
    -
    - -
    - -
    -

    6. Reducers

    -

    - Cada chave do estado tem um reducer independente. Sem reducer, atualizações - sobrescrevem a chave. Para acumular, use Annotated: -

    -
    from typing import Annotated
    -from operator import add
    -from typing_extensions import TypedDict
    -
    -class State(TypedDict):
    -    foo: int                        # overwrite
    -    bar: Annotated[list[str], add]  # concat
    -

    Bypass de reducer com Overwrite

    -
    from langgraph.types import Overwrite
    -
    -def replace_messages(state: State):
    -    return {"messages": Overwrite(["replacement message"])}
    -# Forma JSON-compatível:
    -# return {"messages": {"__overwrite__": ["replacement message"]}}
    -
    - Receber múltiplos Overwrite para a mesma chave em - um único super-step levanta InvalidUpdateError. -
    - -

    Canais do Pregel (camada de baixo nível)

    -

    - Por baixo de reducers e Annotated, cada chave do estado é um - canal do Pregel. O tipo do canal define a semântica de escrita ao - longo dos super-steps. A maioria dos grafos nunca instancia canais - diretamente — eles são inferidos do schema —, mas conhecê-los ajuda a - entender o comportamento de acumulação e a API Pregel crua. -

    -
    - - - - - - - - - -
    CanalImportSemântica
    LastValuelanggraph.channelsDefault; guarda apenas o último valor escrito (sobrescreve).
    Topiclanggraph.channelsPubSub; Topic(str, accumulate=True) acumula todos os valores escritos no run.
    BinaryOperatorAggregatelanggraph.channelsAgregado corrente via operador binário (ex.: operator.add).
    EphemeralValuelanggraph.channelsValor transitório: existe só durante o super-step; não é persistido entre steps.
    DeltaChannel betalanggraph.channelsReducer em bulk com snapshots periódicos (requer langgraph >= 1.2).
    -
    -
    from langgraph.channels import (
    -    LastValue, Topic, BinaryOperatorAggregate, EphemeralValue, DeltaChannel,
    -)
    -import operator
    -
    -ch: LastValue[int] = LastValue(int)                 # default; sobrescreve valor anterior
    -topic: Topic[str] = Topic(str, accumulate=True)     # PubSub; acumula valores no run
    -total = BinaryOperatorAggregate(int, operator.add)  # agregado corrente via operador binário
    - -

    DeltaChannel — reducer em bulk com snapshots beta · langgraph >= 1.2

    -

    - O DeltaChannel usa um bulk reducer: em vez de ser - chamado pairwise (estado atual + uma write por vez), recebe o estado atual mais - uma sequência com todas as writes do super-step numa - única chamada — útil quando o reducer é associativo e se beneficia de processar - o lote inteiro de uma vez. -

    -
    from typing import Annotated
    -from typing_extensions import TypedDict
    -from langgraph.channels import DeltaChannel
    -
    -class State(TypedDict):
    -    messages: Annotated[list[str], DeltaChannel(my_reducer, snapshot_frequency=5)]
    -
      -
    • snapshot_frequency=K grava um snapshot completo a cada K steps, limitando a latência de leitura a O(K); None (default) = sem snapshots.
    • -
    • API ainda beta — pode mudar entre versões.
    • -
    - -

    API Pregel crua

    -

    - Para construir grafos sem o açúcar de StateGraph, há a API de - baixo nível com Pregel e NodeBuilder: -

    -
    from langgraph.channels import EphemeralValue
    -from langgraph.pregel import Pregel, NodeBuilder
    - -
    - -
    -

    7. MessagesState e add_messages

    -

    - add_messages é o reducer canônico para listas de mensagens. Por - padrão concatena; quando uma mensagem nova tem o mesmo - id de uma existente, sobrescreve; ainda - desserializa dicts em objetos de mensagem do LangChain. -

    -
    from langchain.messages import AnyMessage
    -from langgraph.graph.message import add_messages
    -from typing import Annotated
    -from typing_extensions import TypedDict
    -
    -class GraphState(TypedDict):
    -    messages: Annotated[list[AnyMessage], add_messages]
    -

    Atalho MessagesState

    -
    from langgraph.graph import MessagesState
    -
    -class State(MessagesState):
    -    documents: list[str]   # estende com campos extras
    -

    Formato OpenAI

    -

    - add_messages(format="langchain-openai") reformata o conteúdo em - blocos text/image_url e converte respostas de - ferramenta em ToolMessage. Requer - langchain-core >= 0.3.11 (piso mínimo do recurso). Atenção: a linha atual de - langchain-core é a 1.x (último 1.4.8) — a virada 0.3.x→1.0 trouxe - mudanças incompatíveis (ex.: AIMessage como tipo concreto de retorno, .text() virou - property, Python 3.9 removido); o 0.3.x está em maintenance mode até dez/2026. Pacotes - relacionados na 1.x: langchain 1.3.11, langchain-anthropic 1.4.8, - langchain-google-genai 4.2.6 (requer langchain-core>=1.4.7). -

    -
    - -
    -

    8. Nodes

    -

    - Um nó é uma função Python cujo primeiro argumento é o estado. Argumentos - opcionais (por nome+tipo): config: RunnableConfig e - runtime: Runtime[ContextT]. -

    -
    from langgraph.runtime import Runtime
    -from dataclasses import dataclass
    -from typing_extensions import TypedDict
    -from langgraph.graph import StateGraph
    -
    -class State(TypedDict):
    -    input: str
    -    results: str
    -
    -@dataclass
    -class Context:
    -    user_id: str
    -
    -builder = StateGraph(State)
    -
    -def plain_node(state: State):
    -    return state
    -
    -def node_with_runtime(state: State, runtime: Runtime[Context]):
    -    print("In node: ", runtime.context.user_id)
    -    return {"results": f"Hello, {state['input']}!"}
    -
    -def node_with_execution_info(state: State, runtime: Runtime):
    -    print("Thread:", runtime.execution_info.thread_id)
    -    return {"results": f"Hello, {state['input']}!"}
    -
    -builder.add_node("plain_node", plain_node)
    -builder.add_node("node_with_runtime", node_with_runtime)
    -builder.add_node("node_with_execution_info", node_with_execution_info)
    -

    - Auto-naming: builder.add_node(my_node) registra como - "my_node". -

    -
    - -
    -

    9. Edges

    -

    Edges normais e condicionais

    -
    graph.add_edge("node_a", "node_b")
    -graph.add_conditional_edges("node_a", routing_function)
    -graph.add_conditional_edges("node_a", routing_function, {True: "node_b", False: "node_c"})
    -graph.add_edge(START, "node_a")
    -graph.add_conditional_edges(START, routing_function)
    -graph.add_conditional_edges(START, routing_function, {True: "node_b", False: "node_c"})
    -
    - Para cada nó, escolha um mecanismo de roteamento: edges - estáticos para roteamento fixo, ou edges condicionais / Command - para roteamento dinâmico. Nós com múltiplas saídas executam todos os - destinos em paralelo. -
    -

    Atalho de sequência (langgraph >= 0.2.46)

    -
    builder = StateGraph(State).add_sequence([step_1, step_2, step_3])
    -builder.add_edge(START, "step_1")
    -

    Fan-out / fan-in, defer

    -
    builder.add_edge(START, "a")
    -builder.add_edge("a", "b")
    -builder.add_edge("a", "c")
    -builder.add_edge("b", "d")
    -builder.add_edge("c", "d")
    -builder.add_edge("d", END)
    -

    - Quando ramos têm comprimentos diferentes, marque o nó de junção como - deferred: -

    -
    builder.add_node(d, defer=True)
    -
    - -
    -

    10. Send (map-reduce)

    -

    - Send(node_name, state_dict) despacha uma cópia distinta do estado - para o nó nomeado. O uso principal é map-reduce com fan-out paralelo. -

    -
    from langgraph.types import Send
    -
    -def continue_to_jokes(state: OverallState):
    -    return [Send("generate_joke", {"subject": s}) for s in state['subjects']]
    -
    -graph.add_conditional_edges("node_a", continue_to_jokes)
    -
    - -
    -

    11. Command (roteamento + atualização de estado)

    -

    - Command permite que um nó atualize estado e roteie - dinamicamente, tudo no retorno: -

    -
    from langgraph.types import Command
    -from typing_extensions import Literal
    -
    -def my_node(state: State) -> Command[Literal["my_other_node"]]:
    -    return Command(update={"foo": "bar"}, goto="my_other_node")
    -
    - A anotação de retorno Command[Literal[...]] é necessária para que - o LangGraph renderize e valide o grafo. Edges estáticos continuam executando - em paralelo com o roteamento dinâmico do Command. -
    -

    Command.PARENT — sair de um subgraph

    -
    def my_node(state: State) -> Command[Literal["my_other_node"]]:
    -    return Command(update={"foo": "bar"}, goto="other_subgraph", graph=Command.PARENT)
    -

    - O state key do pai deve ter um reducer para que o - update seja aceito. -

    -

    Resume após interrupt — única forma válida como input

    -
    result = graph.invoke(Command(resume="yes"), config, version="v2")
    -
    - -
    -

    12. Runtime e context

    -

    - context_schema declara o contexto imutável por chamada (ex.: - user_id, conexão de DB). O contexto é injetado em runtime via - Runtime[ContextT]. -

    -
    from dataclasses import dataclass
    -from langgraph.runtime import Runtime
    -
    -@dataclass
    -class ContextSchema:
    -    llm_provider: str = "openai"
    -
    -graph = StateGraph(State, context_schema=ContextSchema)
    -graph.invoke(inputs, context={"llm_provider": "anthropic"})
    -
    -def node_a(state: State, runtime: Runtime[ContextSchema]):
    -    llm = get_llm(runtime.context.llm_provider)
    -

    - config_schema está depreciado desde a v0.6.0 — use - context_schema. -

    -

    Acessar metadados do runtime

    -

    - runtime.execution_info expõe thread_id, - run_id, checkpoint_id, checkpoint_ns, - task_id, node_attempt, - node_first_attempt_time. Em LangGraph Server, - runtime.server_info traz assistant_id, - graph_id e user. -

    -
    - -
    -

    13. Subgraphs

    -

    Duas estratégias de comunicação

    -
    - - - - - - -
    PadrãoQuando usarComo
    Schemas diferentesNenhuma chave em comumFunção wrapper dentro de um nó chama subgraph.invoke({...}), traduz entrada/saída
    Schema compartilhadoPai e subgraph compartilham chavesPasse o subgraph compilado diretamente para add_node
    -
    -

    Matriz de capacidades por modo de compilação

    -
    - - - - - - - - - -
    FeaturePer-invocation
    checkpointer=None (default)
    Per-thread
    checkpointer=True
    Stateless
    checkpointer=False
    Interrupts (HITL)SimSimNão
    Multi-turn memoryNãoSimNão
    Múltiplos subgraphs diferentesSimLimitadoSim
    Múltiplas calls do mesmo subgraphSimNãoSim
    Inspeção de estadoApenas atualSimNão
    -
    -
    - Subgraphs per-thread não suportam chamadas paralelas (conflito de - namespace de checkpoint). Para múltiplos subagents do mesmo tipo, embrulhe - cada um em um StateGraph com nome único: -
    -
    def create_sub_agent(model, *, name, **kwargs):
    -    agent = create_agent(model=model, name=name, **kwargs)
    -    return (
    -        StateGraph(MessagesState)
    -        .add_node(name, agent)
    -        .add_edge("__start__", name)
    -        .compile()
    -    )
    -

    Streaming dentro de subgraphs

    -
    for chunk in graph.stream(
    -    {"foo": "foo"}, subgraphs=True, stream_mode="updates", version="v2"
    -):
    -    # chunk["ns"] == () para o grafo raiz;
    -    # chunk["ns"] == ("node_2:<uuid>",) para um subgraph
    -    print(chunk["ns"], chunk["data"])
    -
    - -
    -

    14. Recursion limit e RemainingSteps

    -

    - O limite padrão é 1000 supersteps (default desde a v1.0.6). - Ultrapassá-lo levanta GraphRecursionError. - recursion_limit é uma chave de topo em - config (não dentro de configurable): -

    -
    graph.invoke(inputs, config={"recursion_limit": 5}, context={"llm": "anthropic"})
    -

    Metadados do passo

    -
    from langchain_core.runnables import RunnableConfig
    -
    -def my_node(state: dict, config: RunnableConfig) -> dict:
    -    current_step = config["metadata"]["langgraph_step"]
    -    return state
    -

    - Campos disponíveis: langgraph_step, langgraph_node, - langgraph_triggers, langgraph_path, - langgraph_checkpoint_ns. -

    -

    Alternativa proativa — RemainingSteps

    -
    from langgraph.managed import RemainingSteps
    -from typing import Annotated, Literal
    -
    -class State(TypedDict):
    -    messages: Annotated[list, lambda x, y: x + y]
    -    remaining_steps: RemainingSteps
    -
    -def reasoning_node(state: State) -> dict:
    -    if state["remaining_steps"] <= 2:
    -        return {"messages": ["Approaching limit, wrapping up..."]}
    -    return {"messages": ["thinking..."]}
    -
    - - - - - - -
    AbordagemQuando detectaOnde tratarFluxo
    Proativa (RemainingSteps)Antes do limiteDentro do grafo, via roteamentoGrafo termina normalmente
    Reativa (GraphRecursionError)Depois do limiteFora do grafo, em try/exceptExecução abortada
    -
    -
    - -
    -

    15. Cache · Retry · Timeout · Error handlers

    -

    Caching de nó

    -
    import time
    -from langgraph.cache.memory import InMemoryCache
    -from langgraph.types import CachePolicy
    -
    -def expensive_node(state: State) -> dict[str, int]:
    -    time.sleep(2)
    -    return {"result": state["x"] * 2}
    -
    -builder.add_node("expensive_node", expensive_node, cache_policy=CachePolicy(ttl=3))
    -graph = builder.compile(cache=InMemoryCache())
    -

    - Parâmetros de CachePolicy: key_func (default: pickle - hash do input) e ttl (segundos; sem TTL = nunca expira). Hits - aparecem em streaming com '__metadata__': {'cached': True}. -

    -

    Retry policy

    -
    from langgraph.types import RetryPolicy
    -import sqlite3
    -
    -builder.add_node(
    -    "query_database",
    -    query_database,
    -    retry_policy=RetryPolicy(retry_on=sqlite3.OperationalError),
    -)
    -builder.add_node("model", call_model, retry_policy=RetryPolicy(max_attempts=5))
    -

    - O retry_on padrão exclui ValueError, - TypeError, ArithmeticError, - ImportError, LookupError, NameError, - SyntaxError, RuntimeError, - ReferenceError, StopIteration, - StopAsyncIteration, OSError. Para HTTP libs, só 5xx. -

    -

    Timeouts (langgraph >= 1.2)

    -
    from langgraph.types import TimeoutPolicy
    -
    -builder.add_node("call_model", call_model, timeout=1.0)
    -builder.add_node(
    -    "call_model_complex",
    -    call_model,
    -    timeout=TimeoutPolicy(run_timeout=120, idle_timeout=30),
    -)
    -

    - Exceder timeout levanta NodeTimeoutError (subclass de - TimeoutError). Apenas async. -

    -

    Error handlers

    -
    from langgraph.errors import NodeError
    -from langgraph.types import Command, RetryPolicy
    -
    -def payment_error_handler(state: State, error: NodeError) -> Command:
    -    return Command(
    -        update={"status": f"compensated: {error.error}"},
    -        goto="finalize",
    -    )
    -
    -builder.add_node(
    -    "charge_payment",
    -    charge_payment,
    -    retry_policy=RetryPolicy(max_attempts=3, retry_on=ConnectionError),
    -    error_handler=payment_error_handler,
    -)
    - -

    Defaults graph-wide com set_node_defaults()

    -

    - Em vez de repetir retry_policy/timeout/cache_policy/error_handler - em cada add_node(), aplique-os ao grafo inteiro com - builder.set_node_defaults(...): -

    -
    from langgraph.types import RetryPolicy, TimeoutPolicy
    -
    -builder.set_node_defaults(
    -    retry_policy=RetryPolicy(max_attempts=3),
    -    error_handler=default_error_handler,
    -    timeout=TimeoutPolicy(run_timeout=30),
    -)
    -
    - Precedência: valores passados diretamente em - add_node() sempre vencem os defaults de - set_node_defaults(). Os defaults resolvem em compile-time, - então a ordem das chamadas não importa. -
    -
    - O error_handler e o cache_policy default não - se aplicam aos próprios nós error-handler; já retry_policy e - timeout aplicam-se a ambos. -
    - -

    Idle timeout, refresh_on e heartbeat

    -

    - Além de run_timeout (limite total), o TimeoutPolicy - suporta idle_timeout (limite sem atividade). O campo - refresh_on controla o que reseta o relógio idle: -

    -
    from langgraph.types import TimeoutPolicy
    -
    -# "auto" (default): writes de estado, stream output, agendamento de child-task,
    -#   chamadas do stream-writer e qualquer callback LangChain resetam o relógio idle.
    -timeout = TimeoutPolicy(idle_timeout=30, refresh_on="heartbeat")
    -
    -# Dentro do nó — só "heartbeat" depende de chamada explícita:
    -def long_node(state, runtime):
    -    runtime.heartbeat()   # reseta o relógio idle; seguro chamar incondicionalmente
    -    ...
    -
    - - - - - - -
    refresh_onReseta o relógio idle quando…
    "auto" (default)Há writes de estado, stream output, agendamento de child-task, chamadas do stream-writer ou qualquer callback LangChain.
    "heartbeat"Apenas via runtime.heartbeat() explícito (no-op fora de um attempt idle-timed).
    -
    -

    - Estourar o limite levanta NodeTimeoutError (subclass de - TimeoutError), com os campos: node: str, - elapsed: float, kind: Literal["idle", "run"], - idle_timeout: float | None, run_timeout: float | None. -

    - -

    default_retry_on extensível

    -

    - Para construir um retry_on= que estende a lógica padrão (em vez de - substituí-la), importe e reutilize default_retry_on dentro do seu - callable: -

    -
    from langgraph.types import RetryPolicy, default_retry_on
    -
    -def retry_on(exc: Exception) -> bool:
    -    # mantém o comportamento default e adiciona um caso próprio
    -    return default_retry_on(exc) or isinstance(exc, MyTransientError)
    -
    -builder.add_node("call_api", call_api, retry_policy=RetryPolicy(retry_on=retry_on))
    - -
    - -
    -

    16. Visualização

    -
    from IPython.display import Image, display
    -
    -# PNG via Mermaid.Ink (default)
    -display(Image(graph.get_graph().draw_mermaid_png()))
    -
    -# Mermaid syntax (texto)
    -print(app.get_graph().draw_mermaid())
    -
    -# Customizado via Pyppeteer
    -from langchain_core.runnables.graph import CurveStyle, MermaidDrawMethod, NodeStyles
    -
    -display(Image(app.get_graph().draw_mermaid_png(
    -    curve_style=CurveStyle.LINEAR,
    -    node_colors=NodeStyles(first="#ffdfba", last="#baffc9", default="#fad7de"),
    -    wrap_label_n_words=9,
    -    output_file_path=None,
    -    draw_method=MermaidDrawMethod.PYPPETEER,
    -    background_color="white",
    -    padding=10,
    -)))
    -
    -# Graphviz
    -display(Image(app.get_graph().draw_png()))
    -

    - ASCII também está disponível via graph.get_graph().draw_ascii(). -

    -
    - -
    -

    17. Streaming

    -

    - O LangGraph oferece graph.stream(input, stream_mode=..., version="v2", - subgraphs=False, config=None) e .astream(...). No - v2, todo chunk tem o shape: -

    -
    StreamPart = {"type": str, "ns": tuple, "data": Any}
    -

    Modos disponíveis

    -
    - - - - - - - - - - - -
    ModoEmitePayload (chunk["data"])Requer checkpointer
    valuesSnapshot completo após cada stepdict (ou modelo tipado)Não
    updatesDelta retornado por nó{"node_name": {...}}Não
    messagesTokens de LLM(LLM_token_chunk, metadata)Não
    customDados emitidos via get_stream_writer ou writerQualquer JSONNão
    checkpointsEventos de checkpointShape de get_state()Sim
    tasksStart/finish/erro de tasksTask dictSim
    debugcheckpoints + tasks + extraComboSim
    -
    -

    Multi-mode

    -
    for chunk in graph.stream(inputs, stream_mode=["updates", "custom"], version="v2"):
    -    if chunk["type"] == "updates": ...
    -    elif chunk["type"] == "custom": ...
    -

    Emitir custom de dentro de um nó

    -
    from langgraph.config import get_stream_writer
    -
    -def node(state):
    -    writer = get_stream_writer()
    -    writer({"status": "thinking..."})
    -    return {"answer": "x"}
    -

    Injeção de StreamWriter (necessário em Python < 3.11 async)

    -
    from langgraph.types import StreamWriter
    -
    -async def generate_joke(state: State, writer: StreamWriter):
    -    writer({"custom_key": "..."})
    -

    Filtrar tokens por nó / tag

    -
      -
    • metadata["langgraph_node"] — qual nó emitiu.
    • -
    • metadata["tags"] — tags do modelo (via init_chat_model(..., tags=[...])).
    • -
    • Tag ["nostream"] em um modelo exclui seus tokens do modo messages.
    • -
    • init_chat_model(..., streaming=False) ou model.disable_streaming = True.
    • -
    -

    v1 vs v2 — diferenças de retorno

    -
    - - - - - - - -
    Itemv1 (default)v2 (>= 1.1)
    invoke() retornadictGraphOutput com .value, .interrupts
    Payload de interruptresult["__interrupt__"]result.interrupts (tuple)
    Eventos de subgraphtuplas (ns, data)StreamPart unificado
    -
    - -

    Event streaming (stream_events / version="v3") recomendado

    -
    - API recomendada para código novo. - graph.stream_events(...) / graph.astream_events(..., version="v3") - substitui o antigo astream_events(..., version="v2") com - projeções tipadas sobre o fluxo de eventos, em vez de um dict - cru por evento. -
    -
    - Não confunda esta version="v3" (específica de - stream_events/astream_events) com o version="v2" - de graph.invoke(...)/graph.stream(...), que continua - válido para GraphOutput, interrupts tipados e - resume_map (ver §19 e §18). -
    -

    - O objeto retornado expõe o stream cru e várias projeções tipadas - que você itera conforme a necessidade: -

    -
    # Streaming de mensagens (canônico)
    -stream = graph.stream_events(
    -    {"messages": [{"role": "user", "content": "What is 42 * 17?"}]},
    -    version="v3",
    -)
    -for message in stream.messages:
    -    for token in message.text:
    -        print(token, end="", flush=True)
    -
    -final_state = stream.output       # saída final (awaitable no modo async)
    -
    - - - - - - - - - - - - - -
    ProjeçãoEmite
    streamEventos crus (iterável base).
    stream.messagesMensagens/tokens do LLM (com .text, .node).
    stream.valuesSnapshots completos de estado após cada step.
    stream.outputSaída final do grafo (awaitable em async).
    stream.subgraphsEventos originados de subgraphs.
    stream.interruptsInterrupts emitidos durante o run.
    stream.interruptedbool — se o run pausou em um interrupt.
    stream.extensionsProjeções de transformers customizados (stream.extensions["<name>"]).
    stream.tool_callsTool calls (quando um ToolCallTransformer está registrado).
    -
    -

    Consumir múltiplas projeções em ordem de chegada

    -
    for name, item in stream.interleave("values", "messages", "subgraphs"):
    -    if name == "values":
    -        print(f"[state] keys={list(item)}")
    -    elif name == "messages":
    -        print(f"[llm] node={item.node}")
    -

    Transformers customizados (StreamTransformer)

    -

    - Transformers implementam o protocolo StreamTransformer com - init(), process(event), finalize() e - fail(err), e declaram os modos Pregel de que precisam via - required_stream_modes (tupla, ex.: ("custom",)). - Projeções customizadas aparecem em stream.extensions["<name>"]. -

    -
    from langgraph.stream import ProtocolEvent, StreamTransformer
    -
    -# StreamTransformer é o protocolo (init/process/finalize/fail) implementado
    -# por transformers customizados; subclasse-o ou implemente a mesma interface.
    -
    -class MyTransformer(StreamTransformer):
    -    required_stream_modes = ("custom",)
    -
    -    def init(self):
    -        ...
    -
    -    def process(self, event: ProtocolEvent) -> bool:  # retorne False só p/ suprimir o evento
    -        ...
    -
    -    def finalize(self):
    -        ...
    -
    -    def fail(self, err):
    -        ...
    -
    -# Registro em call-time…
    -stream = graph.stream_events(inputs, version="v3", transformers=[MyTransformer()])
    -
    -# …ou no compile:
    -graph = builder.compile(transformers=[MyTransformer()])
    - -
    - -
    -

    18. Persistência (checkpointers)

    -

    - Cada execução persistente é indexada por um thread_id passado em - {"configurable": {"thread_id": "<id>"}}. Mesmo - thread_id ⇒ retoma; novo ⇒ estado fresco. -

    -

    Catálogo de checkpointers

    -
    - - - - - - - - - - - -
    ClassePacoteUso
    InMemorySaver / MemorySaverlanggraph-checkpoint (bundled)Dev/test; tem variante async
    SqliteSaverlanggraph-checkpoint-sqliteLocal sync
    AsyncSqliteSaverlanggraph-checkpoint-sqliteLocal async
    PostgresSaverlanggraph-checkpoint-postgresProdução sync
    AsyncPostgresSaverlanggraph-checkpoint-postgresProdução async
    RedisSaver / AsyncRedisSaverlanggraph-checkpoint-redisProdução, opcional vector
    CosmosDBSaver(Sync)langchain-azure-cosmosdbAzure
    -
    -

    StateSnapshot — campos

    -
    - - - - - - - - - - - -
    CampoTipoSignificado
    valuesdictValores dos canais
    nexttuple[str, ...]Próximos nós; () = completo
    configdictTem thread_id, checkpoint_ns, checkpoint_id
    metadatadictsource (input/loop/update), writes, step
    created_atstrISO 8601
    parent_configdict\|NoneConfig do checkpoint anterior
    taskstuple[PregelTask, ...]id, name, error, interrupts, state
    -
    -

    Setup de produção com Postgres

    -
    from langgraph.checkpoint.postgres import PostgresSaver
    -from langgraph.store.postgres import PostgresStore
    -
    -DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"
    -
    -with (
    -    PostgresStore.from_conn_string(DB_URI) as store,
    -    PostgresSaver.from_conn_string(DB_URI) as checkpointer,
    -):
    -    checkpointer.setup()       # idempotente; cria tabelas/índices
    -    store.setup()
    -    graph = builder.compile(checkpointer=checkpointer, store=store)
    -    graph.invoke(inputs, {"configurable": {"thread_id": "1"}})
    -

    Async Postgres

    -
    from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
    -
    -DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"
    -async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
    -    await checkpointer.setup()
    -    graph = builder.compile(checkpointer=checkpointer)
    -    async for chunk in graph.astream(
    -        inputs, {"configurable": {"thread_id": "1"}}, stream_mode="values"
    -    ):
    -        chunk["messages"][-1].pretty_print()
    -

    Serialização e criptografia

    -

    - O serializador padrão é JsonPlusSerializer (ormsgpack + JSON). - Pickle fallback é opt-in: -

    -
    from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
    -
    -graph.compile(
    -    checkpointer=InMemorySaver(serde=JsonPlusSerializer(pickle_fallback=True))
    -)
    -

    Criptografia AES (lê LANGGRAPH_AES_KEY):

    -
    from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
    -from langgraph.checkpoint.postgres import PostgresSaver
    -
    -serde = EncryptedSerializer.from_pycryptodome_aes()
    -checkpointer = PostgresSaver.from_conn_string("postgresql://...", serde=serde)
    -checkpointer.setup()
    -

    Custom: implemente CipherProtocol em langgraph.checkpoint.serde.base.

    -

    Pending writes — recuperação parcial de super-step

    -

    - Quando vários nós executam no mesmo super-step e um deles falha, o - checkpointer guarda as writes intermediárias dos nós que já - concluíram (via .put_writes). No resume, esses nós - não reexecutam — apenas o que faltou roda de novo. Essas - writes aparecem como pending_writes no snapshot, permitindo - inspecionar o progresso parcial antes da retomada. -

    -
    snapshot = graph.get_state(config)
    -print(snapshot.tasks)            # tasks pendentes do super-step
    -# writes intermediárias persistidas ficam disponíveis como pending_writes
    -# e são reaplicadas no resume sem reexecutar os nós já concluídos.
    - -
    - -
    -

    19. Human-in-the-loop

    -

    - interrupt(value) (de langgraph.types) pausa a - execução, persiste o estado, surface o value ao chamador e - aguarda indefinidamente o Command(resume=...). Requer - checkpointer e thread_id. -

    -
    from langgraph.types import Command, interrupt
    -from langgraph.checkpoint.memory import InMemorySaver
    -

    Gotchas críticos

    -
      -
    1. Não envelope interrupt() em try/except Exception - — ele levanta uma exceção especial usada para pausar.
    2. -
    3. A reentrada é indexada por posição: nunca reordene ou - pule condicionalmente chamadas a interrupt() dentro de um nó.
    4. -
    5. Passe apenas valores JSON-serializáveis para interrupt() — - funções e instâncias de classes não.
    6. -
    7. Side effects antes de interrupt() reexecutam no resume — - torne-os idempotentes (upserts, não inserts).
    8. -
    9. Subgraphs chamados como funções: o nó pai e o nó do subgraph reiniciam - do começo no resume.
    10. -
    -

    Receita 1 — aprovar antes de chamar

    -
    from typing import Literal, Optional, TypedDict
    -from langgraph.checkpoint.memory import InMemorySaver
    -from langgraph.graph import END, START, StateGraph
    -from langgraph.types import Command, interrupt
    -
    -class ApprovalState(TypedDict):
    -    action_details: str
    -    status: Optional[Literal["pending", "approved", "rejected"]]
    -
    -def approval_node(state: ApprovalState) -> Command[Literal["proceed", "cancel"]]:
    -    decision = interrupt({"question": "Approve this action?", "details": state["action_details"]})
    -    return Command(goto="proceed" if decision else "cancel")
    -
    -def proceed_node(state): return {"status": "approved"}
    -def cancel_node(state):  return {"status": "rejected"}
    -
    -builder = StateGraph(ApprovalState)
    -builder.add_node("approval", approval_node)
    -builder.add_node("proceed", proceed_node)
    -builder.add_node("cancel", cancel_node)
    -builder.add_edge(START, "approval")
    -builder.add_edge("proceed", END)
    -builder.add_edge("cancel", END)
    -graph = builder.compile(checkpointer=InMemorySaver())
    -
    -config = {"configurable": {"thread_id": "approval-123"}}
    -initial = graph.invoke({"action_details": "Transfer $500", "status": "pending"},
    -                       config=config, version="v2")
    -print(initial.interrupts)
    -resumed = graph.invoke(Command(resume=True), config=config, version="v2")
    -print(resumed.value["status"])
    -

    Receita 2 — editar estado

    -
    def review_node(state):
    -    edited = interrupt({"instruction": "Review and edit", "content": state["generated_text"]})
    -    return {"generated_text": edited}
    -
    -graph.invoke(Command(resume="Improved draft"), config=config, version="v2")
    -

    Receita 3 — revisar tool call

    -
    from langchain.tools import tool
    -from langgraph.types import interrupt
    -
    -@tool
    -def send_email(to: str, subject: str, body: str):
    -    """Send an email to a recipient."""
    -    response = interrupt({
    -        "action": "send_email", "to": to, "subject": subject, "body": body,
    -        "message": "Approve sending this email?",
    -    })
    -    if response.get("action") == "approve":
    -        return f"Email sent to {response.get('to', to)} subj '{response.get('subject', subject)}'"
    -    return "Email cancelled by user"
    -
    -graph.invoke(
    -    Command(resume={"action": "approve", "subject": "Updated"}),
    -    config=config, version="v2"
    -)
    -

    Receita 4 — validar input humano (loop)

    -
    def get_age_node(state):
    -    prompt = "What is your age?"
    -    while True:
    -        answer = interrupt(prompt)
    -        if isinstance(answer, int) and answer > 0:
    -            return {"age": answer}
    -        prompt = f"'{answer}' is not a valid age. Please enter a positive number."
    -

    Static interrupts (apenas debug)

    -
    graph = builder.compile(interrupt_before=["node_a"], interrupt_after=["node_b"],
    -                        checkpointer=cp)
    -# ou em runtime
    -graph.invoke(inputs, interrupt_before=["node_a"], interrupt_after=["node_b"], config=cfg)
    -graph.invoke(None, config=cfg)  # resume até o próximo breakpoint
    -

    Resumir múltiplos interrupts paralelos com resume_map

    -

    - Quando vários nós em paralelo (ex.: fan-out via Send) chamam - interrupt() no mesmo super-step, o resume precisa endereçar cada um - pelo seu id. Em vez de um único Command(resume=valor), - passe um mapa {interrupt_id: valor}. Isto exige o - fluxo tipado de version="v2" (ver §17 e §18): -

    -
    from langgraph.types import Command
    -
    -interrupted = graph.invoke({"vals": []}, config, version="v2")
    -resume_map = {i.id: f"answer for {i.value}" for i in interrupted.interrupts}
    -result = graph.invoke(Command(resume=resume_map), config, version="v2")
    - -
    - -
    -

    20. Memória curta e longa (Store)

    -

    - Curta (short-term) = escopo de thread, persistida pelo - checkpointer (histórico de conversa, arquivos enviados, docs recuperados, - artefatos gerados). Longa (long-term) = cross-thread, com - escopo de namespace, acessada via BaseStore. -

    -

    Taxonomia de memória

    -
    - - - - - - - -
    TipoArmazenaPadrão
    SemânticaFatosProfile (1 JSON único, regenerado) ou Collection (muitos docs estreitos)
    EpisódicaExperiências passadasFew-shot examples no Store ou em LangSmith Dataset
    ProceduralRegras/instruçõesSystem prompt versionado persistido no Store
    -
    -

    CRUD do Store

    -
    from langgraph.store.memory import InMemoryStore
    -from langgraph.store.postgres import PostgresStore
    -
    -store = InMemoryStore()
    -store.put(namespace, key, value)
    -store.get(namespace, key)            # retorna Item ou None
    -store.search(namespace, filter=..., query=..., limit=..., offset=...)
    -store.delete(namespace, key)
    -store.list_namespaces(prefix=..., max_depth=...)
    -
    - Ordenação: PostgresStore / - AsyncPostgresStore ordenam por updated_at desc; - InMemoryStore respeita a ordem de inserção. Ordene no cliente - quando precisar de garantia. -
    -

    Busca semântica

    -
    from langchain.embeddings import init_embeddings
    -from langgraph.store.memory import InMemoryStore
    -
    -store = InMemoryStore(index={
    -    "embed": init_embeddings("openai:text-embedding-3-small"),
    -    "dims": 1536,
    -    "fields": ["food_preference", "$"],  # "$" = doc inteiro
    -})
    -store.put(ns, key,  {"food_preference": "I love Italian"}, index=["food_preference"])
    -store.put(ns, key2, {"system_info": "..."},                index=False)
    -memories = store.search(ns, query="What does the user like?", limit=3)
    -

    Acessar Store de dentro de um nó

    -
    from langgraph.runtime import Runtime
    -from dataclasses import dataclass
    -import uuid
    -
    -@dataclass
    -class Context:
    -    user_id: str
    -
    -async def update_memory(state, runtime: Runtime[Context]):
    -    namespace = (runtime.context.user_id, "memories")
    -    await runtime.store.aput(
    -        namespace, str(uuid.uuid4()),
    -        {"memory": "User prefers concise replies"}
    -    )
    -

    Stores de produção

    -

    - Além do PostgresStore / AsyncPostgresStore, há backends - de produção mantidos para MongoDB e Redis. Todos estendem BaseStore; - o InMemoryStore serve apenas para dev/teste. -

    -
    - - - - - - - - -
    StoreImportUso
    PostgresStore / AsyncPostgresStorefrom langgraph.store.postgres import PostgresStoreProdução; ordena search por updated_at desc.
    MongoDBStorefrom langgraph.store.mongodb import MongoDBStoreProdução sobre MongoDB.
    RedisStore / AsyncRedisStorefrom langgraph.store.redis import RedisStoreProdução sobre Redis (RedisStack para vetor).
    InMemoryStorefrom langgraph.store.memory import InMemoryStoreApenas dev/teste.
    -
    -
    - -
    -

    21. Time travel — replay e fork

    -
    - - - - - - - -
    APIO que faz
    graph.get_state(config, subgraphs=False)Último StateSnapshot (ou específico via checkpoint_id no config)
    graph.get_state_history(config)Iterador reverso de StateSnapshot
    graph.update_state(config, values, as_node=None)Cria um novo checkpoint partindo de config
    -
    -

    Replay

    -
    history = list(graph.get_state_history(config))
    -before_joke = next(s for s in history if s.next == ("write_joke",))
    -replay_result = graph.invoke(None, before_joke.config)
    -

    - No replay, apenas nós após o checkpoint reexecutam. Chamadas a LLM, - APIs e interrupt() disparam de novo. -

    -

    Fork

    -
    fork_config = graph.update_state(
    -    before_joke.config,
    -    values={"topic": "chickens"},
    -    as_node="generate_topic",
    -)
    -fork_result = graph.invoke(None, fork_config)
    -

    - as_node é explícito quando: há ramos paralelos, em thread sem - histórico, ou quando você quer que o grafo "ache" que um nó posterior já - rodou. -

    -

    Subgraphs e time travel

    -
      -
    • Default (checkpointer herdado): subgraph é um único super-step do ponto - de vista do pai; não dá pra viajar entre nós internos.
    • -
    • compile(checkpointer=True) no subgraph: checkpoints por step - internamente; acesso via - graph.get_state(config, subgraphs=True).tasks[0].state.config.
    • -
    -
    - -
    -

    22. Durable execution & drain

    -

    - Durable execution requer: (a) checkpointer, (b) thread_id, (c) - side effects envolvidos em @task. Modos: -

    -
    - - - - - - - -
    Modo (durability=)PersisteTrade-off
    "exit"Apenas no exit (sucesso, erro, interrupt)Melhor performance; sem recovery no meio
    "async"Assíncrono enquanto o próximo step rodaBalanceado; pequena janela de risco
    "sync"Síncrono antes do próximo step começarMáxima durabilidade; overhead
    -
    -

    Onde o resume começa

    -
    - - - - - - - -
    APIResume retoma em
    Nó de StateGraphInício do nó onde parou
    Subgraph chamado dentro de um nóInício do nó pai + início do nó do subgraph
    Functional APIInício do entrypoint (resultados de @task são recarregados, não reexecutados)
    -
    -

    Graceful shutdown (langgraph >= 1.2)

    -
    import signal
    -from langgraph.runtime import RunControl
    -from langgraph.errors import GraphDrained
    -
    -control = RunControl()
    -signal.signal(signal.SIGTERM, lambda *_: control.request_drain("sigterm"))
    -
    -try:
    -    result = graph.invoke(inputs, config, control=control)
    -except GraphDrained as e:
    -    log.info("drained: %s", e.reason)
    -
    -# Reiniciar em outro processo:
    -result = graph.invoke(None, config)
    -

    Dentro de um nó:

    -
    from langgraph.runtime import Runtime
    -
    -async def my_node(state, runtime: Runtime):
    -    if runtime.drain_requested:
    -        return {"status": "skipped", "reason": runtime.drain_reason}
    -    return {"status": await do_work()}
    -

    - request_drain() não cancela tasks assíncronas nem mata threads — - deixa o nó atual terminar; políticas de retry rodam até esgotar; se há mais - supersteps, levanta GraphDrained e o checkpoint é salvo. -

    -
    - -
    -

    23. Functional API

    -
    from langgraph.func import entrypoint, task
    -

    - @entrypoint(checkpointer=..., store=...) decora uma função com - UM argumento posicional (use um dict para vários). Retorna um - Pregel com .invoke/.ainvoke/ - .stream/.astream. Inputs e outputs devem ser - JSON-serializáveis. -

    -

    Parâmetros injetáveis (por nome+tipo)

    -
    - - - - - - - - -
    NomeTipoPropósito
    previousAnyValor de retorno do checkpoint anterior (ou entrypoint.final.save)
    storeBaseStoreStore de longo prazo
    writerStreamWriterStreaming custom (necessário em Python < 3.11 async)
    configRunnableConfigConfig de runtime
    -
    -

    Memória curta via previous

    -
    @entrypoint(checkpointer=cp)
    -def workflow(number: int, *, previous=None) -> int:
    -    previous = previous or 0
    -    return number + previous
    -

    entrypoint.final — desacoplar retorno do que persiste

    -
    @entrypoint(checkpointer=cp)
    -def workflow(number, *, previous=None) -> entrypoint.final[int, int]:
    -    previous = previous or 0
    -    return entrypoint.final(value=previous, save=2 * number)
    -

    @task — unidade de trabalho com checkpoint

    -
    from typing import NotRequired
    -from typing_extensions import TypedDict
    -from langchain_core.utils.uuid import uuid7
    -from langgraph.checkpoint.memory import InMemorySaver
    -from langgraph.func import task
    -from langgraph.graph import StateGraph, START, END
    -import requests
    -
    -class State(TypedDict):
    -    urls: list[str]
    -    result: NotRequired[list[str]]
    -
    -@task
    -def _make_request(url: str):
    -    return requests.get(url).text[:100]
    -
    -def call_api(state: State):
    -    futures = [_make_request(url) for url in state['urls']]
    -    results = [f.result() for f in futures]
    -    return {"results": results}
    -
    -builder = StateGraph(State)
    -builder.add_node("call_api", call_api)
    -builder.add_edge(START, "call_api")
    -builder.add_edge("call_api", END)
    -
    -checkpointer = InMemorySaver()
    -graph = builder.compile(checkpointer=checkpointer)
    -
    -thread_id = str(uuid7())
    -config = {"configurable": {"thread_id": thread_id}}
    -graph.invoke({"urls": ["https://www.example.com"]}, config)
    -

    - @task só pode ser chamada de dentro de - @entrypoint, de outra @task, ou de um nó de grafo. - Outputs precisam ser JSON-serializáveis. No resume, o resultado persistido é - recarregado — não recomputado. -

    -
    - -
    -

    24. Multi-agent (supervisor & swarm)

    -

    - LangGraph oferece dois pacotes prebuilt — langgraph-supervisor e - langgraph-swarm — além do primitivo - Command(goto=..., graph=Command.PARENT, update=...) que viabiliza - qualquer padrão custom. -

    -

    Padrões

    -
    - - - - - - - - - -
    PadrãoResumo
    SupervisorLLM central roteia para subagents especializados via tool calls
    SwarmPeer-to-peer; agents transferem controle entre si; sistema lembra o último active agent
    NetworkComunicação many-to-many
    HierarchicalSupervisores aninhados (multi-team)
    Custom workflowStateGraph manual com handoffs via Command
    -
    -

    Handoff tool via Command (padrão canônico)

    -
    from typing import Annotated
    -from langchain_core.tools import tool, InjectedToolCallId
    -from langchain_core.messages import ToolMessage
    -from langgraph.types import Command
    -from langgraph.prebuilt import InjectedState
    -
    -@tool("transfer_to_bob", description="Hand off to Bob")
    -def transfer_to_bob(
    -    task_description: Annotated[str, "What Bob should do"],
    -    state: Annotated[dict, InjectedState],
    -    tool_call_id: Annotated[str, InjectedToolCallId],
    -):
    -    msg = ToolMessage(content="Transferred to Bob", name="transfer_to_bob",
    -                      tool_call_id=tool_call_id)
    -    return Command(
    -        goto="Bob",
    -        graph=Command.PARENT,
    -        update={"messages": state["messages"] + [msg], "active_agent": "Bob"},
    -    )
    -

    Supervisor

    -
    pip install langgraph-supervisor
    -
    from langchain_openai import ChatOpenAI
    -from langgraph_supervisor import create_supervisor, create_handoff_tool
    -from langgraph.prebuilt import create_react_agent
    -from langgraph.checkpoint.memory import InMemorySaver
    -
    -model = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    -
    -def add(a: float, b: float) -> float: return a + b
    -def web_search(q: str) -> str: return "..."
    -
    -math_agent = create_react_agent(model=model, tools=[add],
    -                                name="math_expert", prompt="You are a math expert.")
    -research_agent = create_react_agent(model=model, tools=[web_search],
    -                                    name="research_expert",
    -                                    prompt="You are a world-class researcher.")
    -
    -workflow = create_supervisor(
    -    [research_agent, math_agent],
    -    model=model,
    -    prompt="You are a team supervisor managing a research expert and a math expert.",
    -    tools=[
    -        create_handoff_tool(agent_name="math_expert",
    -                            name="assign_to_math_expert",
    -                            description="Assign task to math expert"),
    -        create_handoff_tool(agent_name="research_expert",
    -                            name="assign_to_research_expert",
    -                            description="Assign task to research expert"),
    -    ],
    -    output_mode="last_message",
    -)
    -
    -app = workflow.compile(checkpointer=InMemorySaver())
    -result = app.invoke({"messages": [{"role": "user", "content": "..."}]},
    -                    config={"configurable": {"thread_id": "1"}})
    -

    - output_mode: - "full_history" (anexa todas as mensagens do subagent) ou - "last_message" (anexa apenas a resposta final). - Helpers extras: create_forward_message_tool, - METADATA_KEY_HANDOFF_DESTINATION em - langgraph_supervisor.handoff. -

    -

    Swarm

    -
    pip install langgraph-swarm
    -
    from langchain_openai import ChatOpenAI
    -from langgraph.checkpoint.memory import InMemorySaver
    -from langgraph_swarm import create_handoff_tool, create_swarm
    -from langgraph.prebuilt import create_react_agent
    -
    -model = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    -def add(a: int, b: int) -> int: return a + b
    -
    -alice = create_react_agent(
    -    model,
    -    tools=[add, create_handoff_tool(agent_name="Bob", description="Transfer to Bob")],
    -    prompt="You are Alice, an addition expert.",
    -    name="Alice",
    -)
    -bob = create_react_agent(
    -    model,
    -    tools=[create_handoff_tool(agent_name="Alice", description="Transfer to Alice for math")],
    -    prompt="You are Bob, you speak like a pirate.",
    -    name="Bob",
    -)
    -
    -workflow = create_swarm([alice, bob], default_active_agent="Alice")
    -app = workflow.compile(checkpointer=InMemorySaver())
    -
    -config = {"configurable": {"thread_id": "1"}}
    -app.invoke({"messages": [{"role": "user", "content": "I want to talk to Bob"}]}, config)
    -app.invoke({"messages": [{"role": "user", "content": "What's 2+2?"}]}, config)
    -# Bob devolve para Alice via handoff tool
    -
    - Sem checkpointer, o swarm esquece o agent ativo entre invocações — sempre - passe checkpointer= no compile(). -
    -
    - -
    -

    25. Padrões de workflow

    -

    - A página workflows-agents documenta seis arquiteturas canônicas - construídas em LangGraph puro. -

    -

    1. Prompt chaining

    -
    from typing_extensions import TypedDict
    -from langgraph.graph import StateGraph, START, END
    -
    -class State(TypedDict):
    -    topic: str
    -    joke: str
    -    improved_joke: str
    -    final_joke: str
    -
    -def generate_joke(state: State):
    -    msg = llm.invoke(f"Write a short joke about {state['topic']}")
    -    return {"joke": msg.content}
    -
    -def check_punchline(state: State):
    -    return "Pass" if "?" in state["joke"] or "!" in state["joke"] else "Fail"
    -
    -def improve_joke(state: State):
    -    msg = llm.invoke(f"Make this joke funnier by adding wordplay: {state['joke']}")
    -    return {"improved_joke": msg.content}
    -
    -def polish_joke(state: State):
    -    msg = llm.invoke(f"Add a surprising twist to this joke: {state['improved_joke']}")
    -    return {"final_joke": msg.content}
    -
    -workflow = StateGraph(State)
    -workflow.add_node("generate_joke", generate_joke)
    -workflow.add_node("improve_joke", improve_joke)
    -workflow.add_node("polish_joke", polish_joke)
    -workflow.add_edge(START, "generate_joke")
    -workflow.add_conditional_edges("generate_joke", check_punchline,
    -                               {"Fail": "improve_joke", "Pass": END})
    -workflow.add_edge("improve_joke", "polish_joke")
    -workflow.add_edge("polish_joke", END)
    -chain = workflow.compile()
    -state = chain.invoke({"topic": "cats"})
    -

    2. Parallelization

    -
    parallel_builder = StateGraph(State)
    -parallel_builder.add_node("call_llm_1", call_llm_1)
    -parallel_builder.add_node("call_llm_2", call_llm_2)
    -parallel_builder.add_node("call_llm_3", call_llm_3)
    -parallel_builder.add_node("aggregator", aggregator)
    -parallel_builder.add_edge(START, "call_llm_1")
    -parallel_builder.add_edge(START, "call_llm_2")
    -parallel_builder.add_edge(START, "call_llm_3")
    -parallel_builder.add_edge("call_llm_1", "aggregator")
    -parallel_builder.add_edge("call_llm_2", "aggregator")
    -parallel_builder.add_edge("call_llm_3", "aggregator")
    -parallel_builder.add_edge("aggregator", END)
    -

    3. Routing (com structured output)

    -
    from typing_extensions import Literal
    -from langchain.messages import HumanMessage, SystemMessage
    -from pydantic import BaseModel, Field
    -
    -class Route(BaseModel):
    -    step: Literal["poem", "story", "joke"] = Field(None,
    -        description="The next step in the routing process")
    -
    -router = llm.with_structured_output(Route)
    -
    -def llm_call_router(state: State):
    -    decision = router.invoke([
    -        SystemMessage(content="Route the input to story, joke, or poem based on the user's request."),
    -        HumanMessage(content=state["input"]),
    -    ])
    -    return {"decision": decision.step}
    -
    -def route_decision(state: State):
    -    return {"story": "llm_call_1", "joke": "llm_call_2", "poem": "llm_call_3"}[state["decision"]]
    -
    -router_builder = StateGraph(State)
    -router_builder.add_node("llm_call_1", llm_call_1)
    -router_builder.add_node("llm_call_2", llm_call_2)
    -router_builder.add_node("llm_call_3", llm_call_3)
    -router_builder.add_node("llm_call_router", llm_call_router)
    -router_builder.add_edge(START, "llm_call_router")
    -router_builder.add_conditional_edges("llm_call_router", route_decision,
    -    {"llm_call_1": "llm_call_1", "llm_call_2": "llm_call_2", "llm_call_3": "llm_call_3"})
    -router_builder.add_edge("llm_call_1", END)
    -router_builder.add_edge("llm_call_2", END)
    -router_builder.add_edge("llm_call_3", END)
    -

    4. Orchestrator-worker (Send)

    -
    from typing import Annotated, List
    -import operator
    -from langgraph.types import Send
    -
    -class Section(BaseModel):
    -    name: str = Field(description="Name for this section of the report.")
    -    description: str = Field(description="Brief overview of the section.")
    -
    -class Sections(BaseModel):
    -    sections: List[Section] = Field(description="Sections of the report.")
    -
    -planner = llm.with_structured_output(Sections)
    -
    -class State(TypedDict):
    -    topic: str
    -    sections: list[Section]
    -    completed_sections: Annotated[list, operator.add]
    -    final_report: str
    -
    -class WorkerState(TypedDict):
    -    section: Section
    -    completed_sections: Annotated[list, operator.add]
    -
    -def orchestrator(state: State):
    -    report_sections = planner.invoke([
    -        SystemMessage(content="Generate a plan for the report."),
    -        HumanMessage(content=f"Here is the report topic: {state['topic']}"),
    -    ])
    -    return {"sections": report_sections.sections}
    -
    -def llm_call(state: WorkerState):
    -    section = llm.invoke([
    -        SystemMessage(content="Write a report section..."),
    -        HumanMessage(content=f"name: {state['section'].name}, description: {state['section'].description}"),
    -    ])
    -    return {"completed_sections": [section.content]}
    -
    -def synthesizer(state: State):
    -    return {"final_report": "\n\n---\n\n".join(state["completed_sections"])}
    -
    -def assign_workers(state: State):
    -    return [Send("llm_call", {"section": s}) for s in state["sections"]]
    -
    -builder = StateGraph(State)
    -builder.add_node("orchestrator", orchestrator)
    -builder.add_node("llm_call", llm_call)
    -builder.add_node("synthesizer", synthesizer)
    -builder.add_edge(START, "orchestrator")
    -builder.add_conditional_edges("orchestrator", assign_workers, ["llm_call"])
    -builder.add_edge("llm_call", "synthesizer")
    -builder.add_edge("synthesizer", END)
    -orchestrator_worker = builder.compile()
    -

    5. Evaluator-optimizer (loop com feedback)

    -
    class Feedback(BaseModel):
    -    grade: Literal["funny", "not funny"] = Field(description="Decide if the joke is funny.")
    -    feedback: str = Field(description="Feedback on how to improve.")
    -
    -evaluator = llm.with_structured_output(Feedback)
    -
    -def llm_call_generator(state: State):
    -    if state.get("feedback"):
    -        msg = llm.invoke(f"Write a joke about {state['topic']} considering feedback: {state['feedback']}")
    -    else:
    -        msg = llm.invoke(f"Write a joke about {state['topic']}")
    -    return {"joke": msg.content}
    -
    -def llm_call_evaluator(state: State):
    -    grade = evaluator.invoke(f"Grade the joke {state['joke']}")
    -    return {"funny_or_not": grade.grade, "feedback": grade.feedback}
    -
    -def route_joke(state: State):
    -    return "Accepted" if state["funny_or_not"] == "funny" else "Rejected + Feedback"
    -
    -builder = StateGraph(State)
    -builder.add_node("llm_call_generator", llm_call_generator)
    -builder.add_node("llm_call_evaluator", llm_call_evaluator)
    -builder.add_edge(START, "llm_call_generator")
    -builder.add_edge("llm_call_generator", "llm_call_evaluator")
    -builder.add_conditional_edges("llm_call_evaluator", route_joke,
    -    {"Accepted": END, "Rejected + Feedback": "llm_call_generator"})
    -optimizer_workflow = builder.compile()
    -

    6. Agente ReAct manual

    -
    from langgraph.graph import MessagesState
    -from langchain.messages import SystemMessage, HumanMessage, ToolMessage
    -
    -def llm_call(state: MessagesState):
    -    return {"messages": [llm_with_tools.invoke(
    -        [SystemMessage(content="You are a helpful assistant for arithmetic.")]
    -        + state["messages"]
    -    )]}
    -
    -def tool_node(state: dict):
    -    result = []
    -    for tool_call in state["messages"][-1].tool_calls:
    -        tool = tools_by_name[tool_call["name"]]
    -        observation = tool.invoke(tool_call["args"])
    -        result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
    -    return {"messages": result}
    -
    -def should_continue(state: MessagesState) -> Literal["tool_node", END]:
    -    last_message = state["messages"][-1]
    -    return "tool_node" if last_message.tool_calls else END
    -
    -agent_builder = StateGraph(MessagesState)
    -agent_builder.add_node("llm_call", llm_call)
    -agent_builder.add_node("tool_node", tool_node)
    -agent_builder.add_edge(START, "llm_call")
    -agent_builder.add_conditional_edges("llm_call", should_continue, ["tool_node", END])
    -agent_builder.add_edge("tool_node", "llm_call")
    -agent = agent_builder.compile()
    - -
    - -
    -

    26. Migrações de grafo (com checkpointer)

    -
    - - - - - - - - - - -
    CenárioSuportado
    Threads no fim do grafo — mudanças totais de topologiaSim
    Threads interrompidas — adicionar/modificar nósSim
    Threads interrompidas — renomear/remover nósContate o time
    Adicionar/remover chaves de estadoSim (forwards/backwards compat)
    Renomear chavesNão (perde estado salvo)
    Mudanças incompatíveis de tipoPode causar problemas
    -
    - -

    Deprecations do LangGraph v1

    -

    - O LangGraph v1 deprecou os prebuilts agênticos em favor de - langchain.agents. Os símbolos abaixo continuam funcionando (com - aviso @deprecated), mas código novo deve usar as alternativas: -

    -
    - - - - - - - - - - - - - -
    DeprecadoAlternativa
    create_react_agent (langgraph.prebuilt)from langchain.agents import create_agent — use system_prompt=, não prompt=
    MessageGraphStateGraph com a chave messages (como create_agent provê)
    ValidationNodeRemovido — tools validam o input automaticamente com create_agent
    AgentStatelangchain.agents.AgentState
    AgentStatePydanticlangchain.agents.AgentState (sem estado Pydantic)
    AgentStateWithStructuredResponselangchain.agents.AgentState
    HumanInterruptlangchain.agents.middleware.human_in_the_loop.HITLRequest
    HumanInterruptConfiglangchain.agents.middleware.human_in_the_loop.InterruptOnConfig
    ActionRequestlangchain.agents.middleware.human_in_the_loop.InterruptOnConfig
    -
    -
    # v1 (novo)
    -from langchain.agents import create_agent
    -agent = create_agent(model, tools, system_prompt="You are a helpful assistant.")
    -
    -# v0 (antigo, deprecado)
    -from langgraph.prebuilt import create_react_agent
    -agent = create_react_agent(model, tools, prompt="You are a helpful assistant.")
    -
    - Breaking change: o suporte a Python 3.9 foi removido — todos os - pacotes LangChain agora exigem Python 3.10+ (Python 3.9 chegou - ao fim de vida em out/2025). -
    -
    - create_supervisor / create_swarm vêm dos pacotes - separados langgraph-supervisor / - langgraph-swarm e ainda podem usar create_react_agent - internamente. Verifique a versão do pacote antes de trocar cegamente — a - deprecação v1 acima é especificamente sobre - langgraph.prebuilt.create_react_agent. -
    - -
    - -
    -

    Parte B — Referência de API

    -

    Referência das classes públicas relevantes do LangGraph e dos pacotes prebuilt. Cada entrada inclui import, assinatura e atributos principais.

    -
    - -
    -

    StateGraph

    -
    from langgraph.graph import StateGraph
    -
    -StateGraph(
    -    state_schema: type[StateT],
    -    context_schema: type[ContextT] | None = None,
    -    *,
    -    input_schema: type[InputT] | None = None,
    -    output_schema: type[OutputT] | None = None,
    -)
    -
    - - - - - - - - -
    ParâmetroTipoDefaultDescrição
    state_schematype[StateT]obrigatórioSchema do estado (TypedDict/dataclass/Pydantic)
    context_schematype[ContextT] \| NoneNoneSchema de runtime context (substitui o depreciado config_schema)
    input_schematype[InputT] \| NoneNoneSchema de entrada
    output_schematype[OutputT] \| NoneNoneSchema de saída
    -
    -

    Métodos principais

    -
    add_node(node, name=None, *, retry_policy=None, cache_policy=None, timeout=None, defer=False, error_handler=None, metadata=None) -
    -

    Registra um nó. Sem name, usa o nome da função. retry_policy, cache_policy, timeout, defer e error_handler são opcionais e independentes.

    -
    -
    add_edge(start_key, end_key) -

    Edge estático.

    -
    add_conditional_edges(source, path, path_map=None) -

    Roteamento dinâmico. path é uma função que recebe o estado e devolve um nome de nó, lista, ou lista de Send; path_map traduz retornos para nomes.

    -
    add_sequence(nodes) >= 0.2.46 -

    Atalho que registra os nós e conecta sequencialmente.

    -
    set_entry_point(node) · set_finish_point(node) · set_conditional_entry_point(path, path_map=None) -

    Açúcar para add_edge(START, node) / add_edge(node, END).

    -
    compile(checkpointer=None, store=None, cache=None, interrupt_before=None, interrupt_after=None, debug=False, name=None) -
    -

    Retorna um CompiledStateGraph com invoke, ainvoke, stream, astream, get_state, get_state_history, update_state, get_graph.

    -

    checkpointer=None usa o do pai (em subgraph) ou nenhum; checkpointer=True habilita per-thread state em subgraph; checkpointer=False torna o subgraph stateless.

    -
    -
    - -
    -

    START · END

    -
    from langgraph.graph import START, END
    -

    Sentinelas usados em add_edge(START, "node") e add_edge("node", END) ou em maps de edges condicionais.

    -
    - -
    -

    MessagesState

    -
    from langgraph.graph import MessagesState
    -
    -class MessagesState(TypedDict):
    -    messages: Annotated[list[AnyMessage], add_messages]
    -

    Extenda subclassando — campos extras coexistem com messages.

    -
    - -
    -

    add_messages

    -
    from langgraph.graph.message import add_messages
    -
    -add_messages(
    -    left: Messages,
    -    right: Messages,
    -    *,
    -    format: Literal['langchain-openai'] | None = None,
    -) -> Messages
    -

    Reducer canônico para listas de mensagens: append-only com overwrite por id. format="langchain-openai" reescreve content em blocos text/image_url (requer langchain-core >= 0.3.11).

    -
    - -
    -

    Send

    -
    from langgraph.types import Send
    -
    -Send(node: str, arg: Any, *, timeout: float | timedelta | TimeoutPolicy | None = None)
    -

    Retornada (em lista) por uma função de edge condicional para fan-out paralelo com estado distinto por destino.

    -
    - -
    -

    Command

    -
    from langgraph.types import Command
    -
    -Command(
    -    *,
    -    graph: str | None = None,
    -    update: Any | None = None,
    -    resume: dict | Any | None = None,
    -    goto: Send | Sequence[Send | str] | str = (),
    -)
    -
    - - - - - - - - -
    ParamTipoDefaultDescrição
    graphstr \| NoneNoneGrafo alvo; None = atual, Command.PARENT = pai mais próximo
    updateAny \| NoneNoneAtualização de estado
    resumedict \| Any \| NoneNoneValor para retomar após interrupt()
    gotostr \| Send \| Sequence()Próximo(s) nó(s)
    -
    -

    Constante: Command.PARENT — referência para o grafo pai imediato.

    -
    - -
    -

    Overwrite

    -
    from langgraph.types import Overwrite
    -
    -Overwrite(value: Any)
    -

    Bypassa o reducer e escreve o valor literalmente. Forma JSON: {"__overwrite__": value}. Múltiplos Overwrite para a mesma chave em um super-step ⇒ InvalidUpdateError.

    -
    - -
    -

    Runtime

    -
    from langgraph.runtime import Runtime
    -
    -Runtime(
    -    *,
    -    context: ContextT = None,
    -    store: BaseStore | None = None,
    -    stream_writer: StreamWriter = _no_op_stream_writer,
    -    heartbeat: Callable[[], None] = _no_op_heartbeat,
    -    previous: Any = None,
    -    execution_info: ExecutionInfo | None = None,
    -    server_info: ServerInfo | None = None,
    -    control: RunControl | None = None,
    -)
    -

    Atributos

    -
    - - - - - - - - - - - - - -
    AtributoDescrição
    contextInstância de context_schema
    storeBaseStore long-term
    stream_writerFunção para emitir custom events
    previousRetorno do checkpoint anterior (Functional API)
    execution_infoExecutionInfo: thread_id, run_id, checkpoint_id, checkpoint_ns, task_id, node_attempt, node_first_attempt_time
    server_infoServerInfo: assistant_id, graph_id, user (None fora do LangGraph Server)
    controlRunControl da invocação atual
    drain_requestedbool — true quando request_drain foi chamado
    drain_reasonstr — motivo
    -
    -

    Adicionado em v0.6.0. ToolRuntime (em langgraph.prebuilt) é subclasse que adiciona config, state, tool_call_id.

    -
    - -
    -

    RunControl

    -
    from langgraph.runtime import RunControl
    -

    Métodos: request_drain(reason: str) dispara drenagem cooperativa no próximo boundary de super-step. Não cancela tasks assíncronas. Adicionado em langgraph >= 1.2.

    -
    - -
    -

    RetryPolicy · TimeoutPolicy · CachePolicy

    -
    from langgraph.types import RetryPolicy, TimeoutPolicy, CachePolicy
    -
    RetryPolicy(initial_interval=0.5, backoff_factor=2.0, max_interval=128.0, max_attempts=3, jitter=True, retry_on=...) -
    -

    retry_on: callable ou tupla de tipos. Defaults excluem ValueError, TypeError, ArithmeticError, ImportError, LookupError, NameError, SyntaxError, RuntimeError, ReferenceError, StopIteration, StopAsyncIteration, OSError. HTTP libs só retentam 5xx.

    -
    -
    TimeoutPolicy(run_timeout=..., idle_timeout=...) >= 1.2 -
    -

    run_timeout = limite total; idle_timeout = limite sem atividade. Apenas em runtime async. Estourar levanta NodeTimeoutError.

    -
    -
    CachePolicy(key_func=None, ttl=None) -

    key_func: callable que produz a chave (default: pickle hash do input). ttl em segundos; sem TTL = nunca expira. Combinada com cache=InMemoryCache() ou SqliteCache em compile.

    -
    - -
    -

    RemainingSteps

    -
    from langgraph.managed import RemainingSteps
    -

    Managed value type para uma chave do estado. O runtime injeta automaticamente o orçamento restante de supersteps, permitindo encerrar antes de bater no recursion_limit.

    -
    - -
    -

    interrupt

    -
    from langgraph.types import interrupt
    -
    -interrupt(value: JSONLike) -> Any
    -

    Pausa o nó, persiste o estado e devolve o valor passado em Command(resume=...) no resume. Requer checkpointer + thread_id. Payload precisa ser JSON-serializável.

    -
    - -
    -

    entrypoint · task

    -
    from langgraph.func import entrypoint, task
    -
    -@entrypoint(checkpointer=..., store=...)
    -def workflow(input, *, previous=None, store=None, writer=None, config=None):
    -    ...
    -
    -@task
    -def my_task(...):
    -    ...
    -
    -# entrypoint.final[ReturnT, SaveT]
    -def workflow(...) -> entrypoint.final[int, int]:
    -    return entrypoint.final(value=..., save=...)
    -

    Decoradores da Functional API. @entrypoint retorna um Pregel; @task retorna future via .result() ou await; resultados são checkpointed e recarregados no resume.

    -
    - -
    -

    Stream parts

    -
    from langgraph.types import (
    -    StreamPart, ValuesStreamPart, UpdatesStreamPart, MessagesStreamPart,
    -    CustomStreamPart, CheckpointStreamPart, TasksStreamPart, DebugStreamPart,
    -)
    -

    Tipos do payload v2 — todos no formato {"type": str, "ns": tuple, "data": Any}.

    -
    - -
    -

    StreamWriter · get_stream_writer

    -
    from langgraph.types import StreamWriter
    -from langgraph.config import get_stream_writer
    -
    -def node(state):
    -    writer = get_stream_writer()
    -    writer({"phase": "starting"})
    -
    -async def node_async(state, writer: StreamWriter):  # < Python 3.11
    -    writer({"phase": "starting"})
    -
    - -
    -

    BaseCheckpointSaver

    -
    from langgraph.checkpoint.base import BaseCheckpointSaver
    -

    Classe-base para checkpointers customizados.

    -

    Métodos obrigatórios

    -
    - - - - - - - - - -
    MétodoPropósito
    put(config, checkpoint, metadata, new_versions)Armazena um checkpoint
    put_writes(config, writes, task_id)Armazena writes pendentes do super-step atual
    get_tuple(config) -> CheckpointTupleBusca por thread_id/checkpoint_id
    list(config, filter=..., before=..., limit=...)Itera checkpoints
    aput, aput_writes, aget_tuple, alistContrapartes async
    -
    -
    - -
    -

    InMemorySaver

    -
    from langgraph.checkpoint.memory import InMemorySaver, MemorySaver
    -
    -InMemorySaver(serde=None)
    -

    Para dev/test. serde opcional permite trocar o serializador (ex.: JsonPlusSerializer(pickle_fallback=True)). MemorySaver é alias comum.

    -
    - -
    -

    SqliteSaver · AsyncSqliteSaver

    -
    from langgraph.checkpoint.sqlite import SqliteSaver
    -from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
    -
    -SqliteSaver.from_conn_string(":memory:")
    -# ou
    -import sqlite3
    -SqliteSaver(sqlite3.connect("file.db"))
    -
    -# Async
    -async with AsyncSqliteSaver.from_conn_string("file.db") as cp:
    -    ...
    -
    - -
    -

    PostgresSaver · AsyncPostgresSaver

    -
    from langgraph.checkpoint.postgres import PostgresSaver
    -from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
    -
    -with PostgresSaver.from_conn_string(uri) as cp:
    -    cp.setup()
    -    graph = builder.compile(checkpointer=cp)
    -
    -async with AsyncPostgresSaver.from_conn_string(uri) as cp:
    -    await cp.setup()
    -    graph = builder.compile(checkpointer=cp)
    -

    .setup() é idempotente — cria tabelas e índices.

    -
    - -
    -

    RedisSaver · AsyncRedisSaver

    -
    from langgraph.checkpoint.redis import RedisSaver
    -from langgraph.checkpoint.redis.aio import AsyncRedisSaver
    -
    -cp = RedisSaver.from_conn_string("redis://localhost:6379")
    -cp.setup()
    -
    -async_cp = AsyncRedisSaver.from_conn_string("redis://localhost:6379")
    -await async_cp.asetup()
    -

    Mantido pela community (redis-developer/langgraph-redis). Opcional: indexação vetorial via RedisStack.

    -
    - -
    -

    Serializadores

    -
    from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
    -from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
    -from langgraph.checkpoint.serde.base import CipherProtocol
    -
    -# Pickle fallback opt-in
    -JsonPlusSerializer(pickle_fallback=True)
    -
    -# AES via pycryptodome (lê LANGGRAPH_AES_KEY)
    -serde = EncryptedSerializer.from_pycryptodome_aes()
    -

    O serializador padrão é JsonPlusSerializer (ormsgpack + JSON).

    -
    - -
    -

    BaseStore

    -
    from langgraph.store.base import BaseStore
    -

    Interface abstrata. Item tem value, key, namespace, created_at, updated_at.

    -

    CRUD

    -
    put(namespace, key, value, *, index=None) -

    Cria/atualiza item. index=False desliga embedding; index=["campo"] aplica apenas a campos selecionados.

    -
    get(namespace, key) -> Item | None

    Recupera por chave exata.

    -
    search(namespace, *, filter=None, query=None, limit=10, offset=0) -

    Filtros estruturados e/ou busca semântica. query exige índice de embeddings configurado.

    -
    delete(namespace, key)

    Remove o item.

    -
    list_namespaces(prefix=None, max_depth=None)

    Itera namespaces conhecidos.

    -

    Versões async: aput, aget, asearch, adelete, alist_namespaces.

    -
    - -
    -

    InMemoryStore

    -
    from langgraph.store.memory import InMemoryStore
    -from langgraph.store.base import IndexConfig
    -
    -InMemoryStore(index=IndexConfig(embed=embed_fn, dims=1536, fields=["$"]))
    -

    Para dev/test e cenários em que a memória do processo é suficiente. Não há ordenação implícita por updated_at.

    -
    - -
    -

    PostgresStore

    -
    from langgraph.store.postgres import PostgresStore
    -
    -with PostgresStore.from_conn_string(uri) as store:
    -    store.setup()
    -    # store.put(...), store.search(..., query="...", limit=3)
    -

    Ordena search por updated_at desc. Há também AsyncPostgresStore em langgraph.store.postgres.aio.

    -
    - -
    -

    create_react_agent (legado) deprecated

    -
    from langgraph.prebuilt import create_react_agent
    -
    -def create_react_agent(
    -    model: str | LanguageModelLike | Callable[..., BaseChatModel],
    -    tools: Sequence[BaseTool | Callable | dict[str, Any]] | ToolNode,
    -    *,
    -    prompt: Prompt | None = None,
    -    response_format: StructuredResponseSchema | tuple[str, StructuredResponseSchema] | None = None,
    -    pre_model_hook: RunnableLike | None = None,
    -    post_model_hook: RunnableLike | None = None,
    -    state_schema: StateSchemaType | None = None,
    -    context_schema: type[Any] | None = None,
    -    checkpointer: Checkpointer | None = None,
    -    store: BaseStore | None = None,
    -    interrupt_before: list[str] | None = None,
    -    interrupt_after: list[str] | None = None,
    -    debug: bool = False,
    -    version: Literal["v1", "v2"] = "v2",
    -    name: str | None = None,
    -) -> CompiledStateGraph
    -

    - Função decorada como @deprecated — direciona usuários a - langchain.agents.create_agent (que delega para o LangGraph). - Constrói um agente que chama tools em loop até atingir o stopping condition. -

    -
    - Note a mudança de assinatura: create_agent usa - system_prompt= em vez de prompt=. Veja a - tabela completa de deprecations v1 (§26). -
    -

    - Quando remaining_steps < 2 e há tool calls, devolve - "Sorry, need more steps to process this request." em vez de - levantar GraphRecursionError. -

    -

    Versões v1 vs v2

    -
    - - - - - - -
    VersãoDiferença
    v1Processa uma mensagem por vez
    v2 (default)Distribui tool calls via Send API (paralelo)
    -
    -
    - -
    -

    ToolNode · tools_condition

    -
    from langchain.tools import tool
    -from langgraph.prebuilt import ToolNode, tools_condition
    -from langgraph.graph import MessagesState, StateGraph
    -
    -@tool
    -def search(query: str) -> str:
    -    """Search for information."""
    -    return f"Results for: {query}"
    -
    -@tool
    -def calculator(expression: str) -> str:
    -    """Evaluate a math expression."""
    -    return str(eval(expression))
    -
    -builder = StateGraph(MessagesState)
    -builder.add_node("tools", ToolNode([search, calculator]))
    -# ... tools_condition decide entre "tools" e END
    -graph = builder.compile()
    -

    - ToolNode executa tool calls em paralelo, lida com erros e - injeção de estado (InjectedState, InjectedToolCallId, - InjectedStore). Atributo público: tools_by_name. -

    -

    - tools_condition(state) inspeciona a última mensagem; se tem - tool_calls, retorna "tools"; caso contrário, - END. -

    -
    - -
    -

    langgraph-supervisor

    -
    from langgraph_supervisor import (
    -    create_supervisor, create_handoff_tool,
    -)
    -from langgraph_supervisor.handoff import (
    -    create_forward_message_tool, METADATA_KEY_HANDOFF_DESTINATION,
    -)
    -

    create_supervisor

    -
    create_supervisor(
    -    agents: list,
    -    model: BaseChatModel,
    -    prompt: str = None,
    -    output_mode: Literal["full_history", "last_message"] = "full_history",
    -    tools: list = None,
    -    add_handoff_messages: bool = True,
    -    handoff_tool_prefix: str = "transfer_to",
    -    supervisor_name: str = "supervisor",
    -) -> StateGraph
    -

    create_handoff_tool

    -
    create_handoff_tool(agent_name: str, name: str | None = None, description: str | None = None)
    -
    - -
    -

    langgraph-swarm

    -
    from langgraph_swarm import (
    -    create_swarm, create_handoff_tool, add_active_agent_router,
    -)
    -

    create_swarm

    -
    create_swarm(
    -    agents: list,
    -    default_active_agent: str,
    -) -> StateGraph
    -

    add_active_agent_router

    -
    add_active_agent_router(builder, route_to: list[str], default_active_agent: str)
    -

    Para builds manuais que querem a mesma semântica de "último agent" do swarm.

    -
    - -
    -

    Exceções

    -
    from langgraph.errors import (
    -    GraphRecursionError, InvalidUpdateError, NodeInterrupt,
    -    GraphInterrupt, NodeError, NodeTimeoutError, GraphDrained,
    -    GraphBubbleUp, ParentCommand, EmptyInputError, TaskNotFound, ErrorCode,
    -)
    -
    - - - - - - - - - - - - - -
    ExceçãoHerdaSignificado
    GraphRecursionErrorRecursionErrorExcedeu recursion_limit (default 1000)
    InvalidUpdateErrorExceptionUpdate inválido em um canal (ex.: múltiplos Overwrite)
    NodeInterrupt(value, id=None)GraphInterruptDepreciado — use langgraph.types.interrupt
    GraphInterrupt—Base de exceções de interrupt
    NodeError—Passado ao error_handler após retries esgotarem
    NodeTimeoutErrorTimeoutErrorEstourou timeout/TimeoutPolicy (1.2+)
    GraphDrained—Levantada após RunControl.request_drain() (1.2+). Tem .reason
    EmptyInputError—Input vazio quando não permitido
    TaskNotFound—Functional API: task referenciada não existe
    -
    -
    - -
    -

    Parte C — Plataforma LangGraph

    -

    A camada Platform entrega tudo o que está fora do runtime in-process: servidor HTTP com REST + SSE, persistência durável em Postgres, fila por thread, autenticação plugável, Studio, CLI de build/deploy, SDK Python/JS, e integrações (A2A, MCP, RemoteGraph). Esta parte cobre a superfície completa.

    -
    - Quando usar a plataforma. O StateGraph compilado roda bem em qualquer processo Python. A camada Platform é necessária quando você precisa de: 1) execução background com retomada após desconexão, 2) threads persistentes acessíveis por múltiplos clientes, 3) Crons, 4) Auth multi-tenant centralizada, 5) Studio (debug/replay/fork), 6) deploy gerenciado. -
    -
    - -
    -

    27. Visão geral e arquitetura

    -

    O Agent Server é uma aplicação ASGI (FastAPI/Starlette) que expõe seus grafos via REST + SSE. Ele orquestra runs com a garantia de "no máximo 1 run ativo por thread", persiste estado em Postgres via PostgresSaver, faz fan-out de streaming via Redis pubsub e enfileira tarefas para os workers.

    -
    ┌───────────────────────────────────────────────────────────────┐
    -│  Clientes (langgraph_sdk, REST, Studio, browser SSE)          │
    -└──────────────────┬────────────────────────────────────────────┘
    -                   │ HTTPS  (X-Api-Key  /  custom auth)
    -┌──────────────────▼────────────────────────────────────────────┐
    -│  API Server  (FastAPI/Starlette ASGI)                          │
    -│   • REST: /threads /runs /assistants /crons /store             │
    -│   • SSE streaming  /stream                                     │
    -│   • Auth hooks  (@auth.authenticate, @auth.on...)              │
    -└──────────────────┬───────────────────────────┬─────────────────┘
    -                   │ enqueue                   │ pubsub
    -                   ▼                           ▼
    -            ┌─────────────┐            ┌────────────────┐
    -            │ Postgres    │            │ Redis pubsub   │
    -            │ checkpoints,│◀──ckpt─────│ event bus,     │
    -            │ assistants, │            │ stream fanout  │
    -            │ threads,    │            └────────────────┘
    -            │ runs, crons,│
    -            │ store       │
    -            └─────▲───────┘
    -                  │ lease
    -        ┌─────────┴────────────┐
    -        │ Queue Workers        │  1 run/thread, N_JOBS_PER_WORKER concorrentes
    -        │ (graph executors)    │
    -        └──────────────────────┘
    -
    - - - - - - - - -
    ComponentePapelSubstituível?
    API ServerHTTP+SSE, auth, validação de payloadNão (parte do pacote langgraph-api)
    PostgresCheckpoints, assistants, threads, runs, crons, storeSim (qualquer Postgres ≥ 14)
    RedisPubsub para fan-out de streaming; sem persistênciaSim (qualquer Redis ≥ 6)
    WorkersExecutam grafos; cada thread vira 1 worker dedicadoSim (escala horizontal independente)
    -
    -

    Variáveis-chave (self-hosted Standalone): DATABASE_URI, REDIS_URI, LANGGRAPH_CLOUD_LICENSE_KEY (Enterprise). Em modos avançados, queue.enabled: true separa workers dedicados, e o distributed runtime ainda divide API e execução em frota distinta.

    -
    - -
    -

    28. CLI langgraph

    -

    Instale com:

    -
    pip install -U "langgraph-cli[inmem]"
    -

    Todos os comandos leem ./langgraph.json por padrão. Cinco subcomandos cobrem o ciclo completo: dev, build, up, deploy, dockerfile.

    - -

    28.1 langgraph dev — servidor local in-memory

    -

    Dev server leve com hot-reload e estado pickleado em disco — sem Docker.

    -
    - - - - - - - - - - - - - - -
    FlagDefaultFunção
    -c, --config FILElanggraph.jsonCaminho do config
    --host TEXT127.0.0.1Bind host
    --port INTEGER2024Porta
    --no-reloadoffDesliga auto-reload
    --n-jobs-per-worker10Runs concorrentes por worker
    --debug-port INTEGER—Porta do depurador DAP
    --wait-for-clientoffPausa até o depurador conectar
    --no-browseroffNão abre Studio automaticamente
    --studio-url TEXThttps://smith.langchain.comURL do Studio
    --allow-blockingoffSuprime warnings de I/O síncrono
    --tunneloffExpõe via Cloudflare tunnel público
    -
    langgraph dev --port 2024 --no-browser --debug-port 5678
    - -

    28.2 langgraph build — imagem Docker

    -
    langgraph build -t myorg/my-agent:1.0 --platform linux/amd64,linux/arm64
    -
    - - - - - - - - -
    FlagDefaultFunção
    -t, --tag TEXTobrigatórioTag da imagem
    --platform TEXThostLista de plataformas alvo
    --pull / --no-pull--pullPull da base
    --build-command TEXT—JS: comando de build (ex.: yarn run turbo build)
    --install-command TEXT—JS: comando de install
    - -

    28.3 langgraph up — stack Docker local

    -

    Sobe API + Postgres + Redis localmente. Compose-style.

    -
    langgraph up -p 8123 --watch --postgres-uri "postgres://..." --debugger-port 5678
    -
    - - - - - - - - - - - - - - - -
    FlagDefaultFunção
    -p, --port INTEGER8123Porta de host para API
    --waitoffEspera healthy (implica --detach)
    --watchoffRestart on file change
    --base-image TEXTlangchain/langgraph-apiImagem base
    --image TEXT—Pré-built; pula o build
    --postgres-uri TEXTcontainer internoPostgres externo
    -d, --docker-compose FILE—Compose extra para serviços auxiliares
    --debugger-port INTEGER—Porta do depurador
    --debugger-base-url TEXThttp://127.0.0.1:[PORT]URL pública do depurador
    --recreate / --no-recreate--no-recreateForça recriação
    --pull / --no-pull--pullPull de imagens
    --verboseoffLog estendido
    - -

    28.4 langgraph deploy — push para LangSmith

    -
    langgraph deploy --name my-agent --deployment-type prod --api-key $LANGSMITH_API_KEY
    -
    - - - - - - - - - - -
    FlagDefaultFunção
    --api-key TEXTenvLangSmith API key
    --name TEXTcwdNome do deployment
    --deployment-id TEXT—Atualiza deployment existente
    --deployment-type TEXTdevdev ou prod
    --remote / --no-remoteautoForçar build remoto/local
    --no-waitoffPula polling pós-push
    --verboseoffMostra build/Docker
    -

    Subcomandos: langgraph deploy list, ... revisions list ID, ... delete ID, ... logs [-f] [-q TEXT] [--type deploy|build] [--deployment-id ID | --name NAME].

    - -

    28.5 langgraph dockerfile — gera Dockerfile

    -
    langgraph dockerfile ./Dockerfile -c langgraph.json
    -

    Re-execute sempre que langgraph.json mudar — o arquivo não é regenerado automaticamente.

    - -
    - JS/TS: npm create langgraph config escaneia createAgent(), StateGraph.compile() e workflow.compile() e gera langgraph.json. O CLI também expõe langgraph new para scaffold de projetos. -
    -
    - -
    -

    29. langgraph.json — schema completo

    -

    Schema JSON em https://langgra.ph/schema.json. Use no header:

    -
    {
    -  "$schema": "https://langgra.ph/schema.json",
    -  ...
    -}
    -
    - - - - - - - - - - - - - - - - - - -
    CampoTipoDefaultFunção
    dependenciesstring[]obrigatórioCaminhos locais (".", "./pkg") + pacotes PyPI/npm
    graphs{ name: "path:variable" }obrigatórioMap de IDs de grafo → grafo compilado ou factory function
    envstring | object—Caminho do .env ou {KEY: value} inline
    python_versionstring"3.11"3.11/3.12/3.13
    node_versionstring"20"Versão de Node para projetos JS
    pip_config_filestring—Caminho de pip.conf
    dockerfile_linesstring[][]Linhas extras anexadas ao Dockerfile
    image_distro"debian" | "wolfi" | "bookworm" | "bullseye""debian"Wolfi = menor e mais seguro · CLI ≥ 0.2.11
    auth{ path, openapi?, disable_studio_auth? }—Módulo de auth
    httpobject (abaixo)—Liga/desliga grupos de rotas built-in
    store{ index?, ttl? }—Configura store; index ativa busca semântica
    checkpointer{ ttl? }—TTL/retenção dos checkpoints
    ui{ name: "path" }—Componentes Generative UI
    webhooks{ headers?, url?, env_prefix? }—Política de webhooks de saída
    keep_pkg_toolsbool | string[]falseMantém build tools na imagem (deps nativas em runtime)
    - -

    Sub-schema http

    -

    Booleanos para desabilitar grupos: disable_meta, disable_assistants, disable_runs, disable_threads, disable_store, disable_ui, disable_webhooks. /ok liveness fica disponível mesmo com disable_meta: true.

    - -

    Sub-schema store.index — busca semântica

    -
    "store": {
    -  "index": {
    -    "embed": "openai:text-embedding-3-small",
    -    "dims": 1536,
    -    "fields": ["$"]
    -  }
    -}
    - -

    Exemplo completo

    -
    {
    -  "$schema": "https://langgra.ph/schema.json",
    -  "python_version": "3.12",
    -  "image_distro": "wolfi",
    -  "dependencies": [".", "langchain_openai", "tavily-python"],
    -  "graphs": {
    -    "agent": "./src/agent.py:graph",
    -    "research": "./src/research.py:make_graph"
    -  },
    -  "env": "./.env",
    -  "auth": {
    -    "path": "./src/auth.py:auth",
    -    "disable_studio_auth": false
    -  },
    -  "store": {
    -    "index": {
    -      "embed": "openai:text-embedding-3-small",
    -      "dims": 1536,
    -      "fields": ["$"]
    -    },
    -    "ttl": { "default_ttl": 60, "refresh_on_read": true }
    -  },
    -  "checkpointer": { "ttl": { "default_ttl": 30, "strategy": "delete" } },
    -  "http": { "disable_ui": false, "disable_webhooks": false },
    -  "webhooks": {
    -    "url": { "allowed_domains": ["*.mycompany.com"], "require_https": true },
    -    "headers": { "Authorization": "Bearer ${{ env.LG_WEBHOOK_TOKEN }}" }
    -  },
    -  "dockerfile_lines": ["RUN apt-get update && apt-get install -y libpq-dev"]
    -}
    -
    - -
    -

    30. Threads · Assistants · Runs · Crons

    -
    - - - - - - - - - -
    ConceitoIdentidadeSignificado
    Graphnome em langgraph.jsonBlueprint de código (ex.: ./agent.py:graph)
    AssistantUUIDGraph + snapshot de configuração (modelo, prompt, tools); versionado a cada update
    ThreadUUIDContainer persistente que segura os checkpoints (estado)
    RunUUIDExecução de (assistant_id, thread_id, input); 1 ativo por thread
    CronUUIDRun agendado (5-field cron em UTC)
    StorenamespaceMemória longa BaseStore-backed, opcional busca semântica
    - -

    30.1 Thread — schema

    -
    - - - - - - - - - -
    CampoTipoNotas
    thread_idUUIDPK
    created_at / updated_atISO timestamp—
    metadataobjectFiltrável: graph_id, assistant_id, langgraph_auth_user_id, cron_id...
    statusenumidle | busy | interrupted | error
    configobject{ configurable: {...} }
    valuesobjectSnapshot atual do estado
    - -

    30.2 Status de Run

    -

    pending · running · success · error · interrupted · timeout. multitask_strategy default em uma thread é "reject" (background) ou "enqueue" dependendo do path do SDK.

    - -

    30.3 Grupos de endpoints REST

    -
    - Assistants -
      -
    • POST /assistants · GET /assistants/{id} · PATCH /assistants/{id} · DELETE /assistants/{id}
    • -
    • POST /assistants/search · GET /assistants/{id}/versions
    • -
    -
    -
    - Threads -
      -
    • POST /threads · GET /threads/{id} · PATCH /threads/{id} · DELETE /threads/{id}
    • -
    • POST /threads/search · POST /threads/{id}/copy
    • -
    • GET /threads/{id}/state · POST /threads/{id}/state (update_state) · GET /threads/{id}/history
    • -
    -
    -
    - Runs em uma thread -
      -
    • POST /threads/{tid}/runs · POST /threads/{tid}/runs/stream · POST /threads/{tid}/runs/wait
    • -
    • GET /threads/{tid}/runs · GET /threads/{tid}/runs/{rid}
    • -
    • POST /threads/{tid}/runs/{rid}/cancel
    • -
    • GET /threads/{tid}/runs/{rid}/join · GET /threads/{tid}/runs/{rid}/stream (join_stream)
    • -
    • GET /threads/{tid}/stream (stream da thread inteira, atravessa runs)
    • -
    -
    -
    - Stateless runs -
    • POST /runs · POST /runs/stream · POST /runs/wait
    -
    -
    - Crons -
      -
    • POST /runs/crons · POST /threads/{tid}/runs/crons
    • -
    • POST /runs/crons/search · DELETE /runs/crons/{cid}
    • -
    -
    -
    - Store -
      -
    • PUT /store/items · GET /store/items · DELETE /store/items
    • -
    • POST /store/items/search · POST /store/namespaces
    • -
    -
    - -

    30.4 Cron expressions

    -

    5-field POSIX cron m h dom mon dow, sempre em UTC.

    -
    - - - - - - -
    ExpressãoSignificado
    "*/5 * * * *"A cada 5 minutos
    "0 9 * * 1-5"Dias úteis, 09:00 UTC
    "27 15 * * *"Diariamente, 15:27 UTC
    -

    on_run_completed="delete" (default) deleta a thread após cada run stateless do cron; "keep" retém.

    -
    - -
    -

    31. SDK Python (langgraph_sdk)

    -

    Cliente HTTP+SSE oficial; síncrono ou assíncrono.

    -
    from langgraph_sdk import get_client, get_sync_client
    -
    -client = get_client(url="https://my-deployment.langgraph.app", api_key=API_KEY)
    - -

    31.1 Threads

    -
    await client.threads.create(metadata={"user_id": "u1"}, if_exists="raise")
    -await client.threads.get(thread_id)
    -await client.threads.update(thread_id, metadata={...})
    -await client.threads.delete(thread_id)
    -await client.threads.search(metadata={"graph_id": "agent"}, limit=20, offset=0)
    -await client.threads.copy(thread_id)
    -
    -# Time travel
    -await client.threads.get_state(thread_id, checkpoint={"checkpoint_id": "..."})
    -await client.threads.update_state(thread_id, values={...}, as_node="my_node")
    -await client.threads.get_history(thread_id, limit=10, before=...)
    - -

    31.2 Runs

    -
    await client.runs.create(
    -    thread_id, assistant_id, input=...,
    -    config=..., metadata=...,
    -    multitask_strategy="enqueue",        # reject | interrupt | rollback
    -    webhook="https://...",
    -    on_disconnect="cancel",              # ou "continue" (default)
    -    after_seconds=0,
    -)
    -
    -async for chunk in client.runs.stream(
    -    thread_id, assistant_id, input=...,
    -    stream_mode="updates",               # ou ["updates","messages-tuple"] ...
    -    stream_subgraphs=False,
    -):
    -    print(chunk.event, chunk.data)
    -
    -await client.runs.wait(thread_id, assistant_id, input=...)   # bloqueante
    -await client.runs.get(thread_id, run_id)
    -await client.runs.list(thread_id)
    -await client.runs.cancel(thread_id, run_id, wait=False, action="interrupt")  # ou "rollback"
    -await client.runs.join(thread_id, run_id)
    -async for c in client.runs.join_stream(thread_id, run_id): ...
    - -

    31.3 Assistants

    -
    await client.assistants.create(
    -    graph_id="agent",
    -    config={"configurable": {"model_name": "openai"}},
    -    metadata={"team": "support"},
    -    if_exists="raise",
    -)
    -await client.assistants.get(assistant_id)
    -await client.assistants.update(assistant_id, config=..., metadata=...)
    -await client.assistants.delete(assistant_id)
    -await client.assistants.search(metadata={"team": "support"}, limit=20)
    -await client.assistants.get_versions(assistant_id)
    - -

    31.4 Crons

    -
    await client.crons.create(
    -    assistant_id,
    -    schedule="27 15 * * *",
    -    input=...,
    -    on_run_completed="delete",           # ou "keep"
    -)
    -await client.crons.create_for_thread(thread_id, assistant_id, schedule="0 9 * * 1", input=...)
    -await client.crons.search(assistant_id=..., limit=20)
    -await client.crons.delete(cron_id)
    - -

    31.5 Store (memória longa)

    -
    await client.store.put_item(namespace=("users", user_id), key="profile", value={...})
    -await client.store.get_item(namespace=("users", user_id), key="profile")
    -await client.store.search_items(
    -    namespace_prefix=("users", user_id),
    -    query="prefers vegetarian",
    -    limit=10,
    -)
    -await client.store.delete_item(namespace=("users", user_id), key="profile")
    -await client.store.list_namespaces(prefix=("users",), limit=100)
    - -

    31.6 Dois assistants em uma thread

    -
    thread = await client.threads.create()
    -
    -# Pergunta para o OpenAI
    -async for ev in client.runs.stream(
    -    thread["thread_id"], openai_assistant["assistant_id"],
    -    input={"messages":[{"role":"user","content":"who made you?"}]},
    -    stream_mode="updates",
    -):
    -    print(ev.data)
    -
    -# Continua a conversa, agora com o Anthropic — mesma thread, contexto preservado
    -async for ev in client.runs.stream(
    -    thread["thread_id"], anthropic_assistant["assistant_id"],
    -    input={"messages":[{"role":"user","content":"and you?"}]},
    -    stream_mode="updates",
    -):
    -    print(ev.data)
    -
    - -
    -

    32. Streaming, join e retomada (Platform)

    -

    Além dos modos do runtime (values, updates, messages-tuple, debug, custom, events), a Platform adiciona thread streams de longa duração e retomada via SSE Last-Event-ID.

    - -

    32.1 Stream em background — join_stream

    -

    Conecta-se a um run que já está executando. Eventos antes do join não são reproduzidos.

    -
    async for chunk in client.runs.join_stream(thread_id, run_id):
    -    print(chunk)
    - -

    32.2 Thread stream — atravessa runs

    -

    Canal de eventos por thread, persiste enquanto a thread existir.

    -
    async for chunk in client.threads.join_stream(
    -    thread_id,
    -    stream_mode=["run_modes", "lifecycle", "state_update"],
    -):
    -    print(chunk.event, chunk.data)
    - -

    32.3 Retomada com last_event_id

    -
    async for chunk in client.threads.join_stream(
    -    thread_id,
    -    last_event_id="<id do último chunk recebido>",
    -):
    -    ...
    -

    last_event_id="-" reproduz do começo. Em HTTP cru, o mesmo é feito via header Last-Event-ID.

    - -

    32.4 Política on_disconnect

    -
    - - - - - -
    ValorComportamento
    "continue" (default)Run continua mesmo se o cliente SSE desconectar
    "cancel"Run termina se o cliente SSE sair
    -
    - -
    -

    33. Autenticação personalizada (@auth)

    -

    Duas fases em cada request: 1) Autenticação (@auth.authenticate devolve o usuário), 2) Autorização (handler mais específico decide; retorna None/True = permite, False = 403, ou um dict filtro restringindo metadata).

    - -
    "auth": { "path": "./auth.py:auth", "disable_studio_auth": false }
    - -

    33.1 @auth.authenticate

    -

    Aceita qualquer subconjunto de: request, body, path, method, path_params, query_params, headers, authorization.

    -
    from langgraph_sdk import Auth
    -auth = Auth()
    -
    -@auth.authenticate
    -async def authenticate(authorization: str | None, headers: dict) -> Auth.types.MinimalUserDict:
    -    if not authorization or not authorization.startswith("Bearer "):
    -        raise Auth.exceptions.HTTPException(status_code=401, detail="Missing token")
    -    token = authorization.removeprefix("Bearer ")
    -    user = await verify_jwt(token)
    -    return {
    -        "identity": user["sub"],                       # obrigatório
    -        "is_authenticated": True,
    -        "permissions": user.get("permissions", []),
    -        "display_name": user.get("name"),
    -        "org_id": user.get("org_id"),                  # campo custom
    -    }
    - -

    33.2 Hierarquia de autorização

    -

    Recursos: threads · assistants · crons · store. Verbos: create · read · update · delete · search (e threads.create_run). Fallback global: @auth.on.

    -
    @auth.on
    -async def reject_unmatched(ctx, value):
    -    raise Auth.exceptions.HTTPException(403, detail="Forbidden")
    -
    -@auth.on.threads.create
    -async def on_thread_create(ctx, value: Auth.types.ThreadsCreate):
    -    md = value.setdefault("metadata", {})
    -    md["owner"] = ctx.user.identity
    -    return {"owner": ctx.user.identity}            # filtra leituras futuras
    -
    -@auth.on.threads.read
    -async def on_thread_read(ctx, value):
    -    return {"owner": ctx.user.identity}
    -
    -@auth.on.threads.create_run
    -async def on_run_create(ctx, value):
    -    value.setdefault("metadata", {})["owner"] = ctx.user.identity
    -    return {"owner": ctx.user.identity}
    -
    -@auth.on.assistants.create
    -async def on_assistant_create(ctx, value):
    -    if "assistants:create" not in ctx.permissions:
    -        raise Auth.exceptions.HTTPException(403, "Missing assistants:create")
    -    value.setdefault("metadata", {})["owner"] = ctx.user.identity
    -    return {"owner": ctx.user.identity}
    -
    -@auth.on.store
    -async def on_store(ctx, value):
    -    # Namespace do store deve começar com o próprio identity
    -    if value["namespace"][0] != ctx.user.identity:
    -        raise Auth.exceptions.HTTPException(403, "Cross-user store access denied")
    -    return True
    - -

    33.3 Dialeto de filtros

    -
    {"owner": user_id}                              # match exato
    -{"owner": {"$eq": user_id}}
    -{"allowed_users": {"$contains": user_id}}       # lista contém
    -{"owner": org_id, "allowed_users": {"$contains": user_id}}   # AND
    - -

    AuthContext expõe ctx.user.identity, ctx.user.is_authenticated, ctx.permissions, ctx.path, além de campos custom retornados em authenticate. Dentro de um nó, o usuário aparece em config["configurable"]["langgraph_auth_user"].

    - -
    - Bypass do Studio. Requests do Studio carregam um header especial — handlers podem deixar desenvolvedores passarem irrestritamente. Para forçar auth também no Studio, ative "disable_studio_auth": true. -
    -
    - -
    -

    34. Double-texting (4 estratégias)

    -

    Quando uma nova mensagem chega numa thread cujo run anterior ainda está rodando, a estratégia multitask_strategy decide o destino do novo run.

    -
    - - - - - - - -
    EstratégiaComportamentoQuando usar
    enqueueNovo run entra na fila, executa após o atualChat onde ordem importa
    rejectNovo run rejeitado com HTTP 409Operações caras e não-duplicáveis
    interruptRun atual interrompe; novo começa do checkpoint construído até aquiAgente em tempo real — trabalho intermediário é descartável
    rollbackRun atual é cancelado e suas escritas são revertidas; novo run começa do estado pré-runReinício totalmente limpo
    - -
    # Enqueue
    -await client.runs.create(thread_id, aid, input=msg1, multitask_strategy="enqueue")
    -await client.runs.create(thread_id, aid, input=msg2, multitask_strategy="enqueue")
    -
    -# Reject (409 se há run em andamento)
    -await client.runs.create(thread_id, aid, input=msg, multitask_strategy="reject")
    -
    -# Interrupt (preserva progresso parcial; cuidado com tool calls em andamento)
    -await client.runs.create(thread_id, aid, input=msg, multitask_strategy="interrupt")
    -
    -# Rollback (descarta progresso do run atual)
    -await client.runs.create(thread_id, aid, input=msg, multitask_strategy="rollback")
    - -
    - Em interrupt, o estado refletirá tudo que foi checkpointado até a interrupção — seus nós devem ser projetados para serem retomáveis em qualquer ponto, inclusive no meio de tool calls. -
    -
    - -
    -

    35. Webhooks

    -

    Webhooks disparam quando um run alcança status terminal. São aceitos como parâmetro webhook em runs.create, runs.stream, runs.wait e crons.create.

    -
    await client.runs.stream(
    -    thread_id, assistant_id, input=msg,
    -    stream_mode="events",
    -    webhook="https://my-server.app/hook?token=SECRET",
    -)
    - -

    35.1 Payload (objeto Run)

    -
    {
    -  "run_id": "1ef6a5b8-...",
    -  "thread_id": "5d7a-...",
    -  "assistant_id": "agent",
    -  "status": "success",
    -  "values": { "messages": [{"role":"assistant","content":"Hi"}] },
    -  "kwargs": { "input": {...}, "config": {...} },
    -  "webhook_sent_at": "2026-05-24T15:01:23Z",
    -  "error": null
    -}
    -

    Em falha, error = {"error": "TimeoutError", "message": "Run exceeded max time"}.

    - -

    35.2 Segurança

    -

    Não há HMAC nativo. Duas opções suportadas:

    -
      -
    1. Token na query string: https://my-server/hook?token=$SECRET e validação no servidor.
    2. -
    3. Headers estáticos (requer langgraph-api ≥ 0.5.36) declarados em langgraph.json:
    4. -
    -
    "webhooks": {
    -  "headers": { "Authorization": "Bearer ${{ env.LG_WEBHOOK_TOKEN }}" },
    -  "url": { "allowed_domains": ["*.mycompany.com"], "require_https": true },
    -  "env_prefix": "LG_WEBHOOK_"
    -}
    -

    Só variáveis de ambiente que casam com env_prefix são interpoláveis (default LG_WEBHOOK_). Para desligar webhooks: "http": { "disable_webhooks": true } (langgraph-api ≥ 0.2.78).

    - -
    - Não há política documentada de retry. Trate a entrega como at-most-once; se precisar de garantia, reconcilie via client.runs.get(thread_id, run_id). -
    -
    - -
    -

    36. LangGraph Studio

    -

    Studio é a aplicação web em smith.langchain.com que conecta a um servidor LangGraph (local ou deployment) para visualizar grafos, percorrer threads, editar estado, refazer steps e iterar prompts.

    - -

    36.1 Dois modos de execução

    -
    - - - - - -
    ModoComo conectarAuth
    Locallanggraph dev em :2024; Studio aponta para localhostHandlers recebem contexto Studio-tagged (a menos que disable_studio_auth: true)
    CloudLangSmith Deployment publicado via langgraph deployAuth normal; 1-click deploy a partir do Studio é suportado
    - -

    36.2 Dois modos de UI

    -
      -
    • Graph mode — grafo completo, inspeção de estado, tool calls, datasets, playground.
    • -
    • Chat mode — UI simplificada; exige estado compatível com MessagesState.
    • -
    - -

    36.3 Capacidades-chave

    -
      -
    • Time travel: slider através do histórico de checkpoints da thread; inspecione qualquer um.
    • -
    • Editar estado em um nó (ícone de lápis) → Fork cria nova branch a partir do checkpoint com a edição.
    • -
    • Re-run from here: repete sem editar estado (útil para trocar assistant ou versão de modelo).
    • -
    • Interrupt coloca breakpoint pré/pós-nó; Continue retoma.
    • -
    • Experiments: roda eval contra datasets direto na UI.
    • -
    • Long-term memory: navega/edita namespaces do Store.
    • -
    -
    - -
    -

    37. Opções de deployment

    -
    - - - - - - - -
    OpçãoControl planeData planeInfraPlano
    CloudLangChainLangChain (AWS/GCP)GerenciadoPlus+
    HybridLangChainCliente (K8s)K8s + listenerEnterprise
    Self-Hosted Full PlatformClienteClienteK8s + LangSmith self-hosted + CRD langgraphPlatformEnterprise
    Self-Hosted Standalone Server—ClienteDocker / Compose / K8sEnterprise
    -

    Para Standalone, as 3 variáveis decisivas são DATABASE_URI (Postgres), REDIS_URI (Redis) e LANGGRAPH_CLOUD_LICENSE_KEY. Tiers opcionais: queue.enabled: true dedica hosts para workers; o distributed runtime separa orquestração da execução.

    -
    - -
    -

    Parte D — Receituário de padrões

    -

    Catorze padrões canônicos da documentação oficial LangGraph, condensados em ~30 linhas cada. Os nomes de classes/funções batem com os notebooks oficiais em github.com/langchain-ai/langgraph/tree/main/examples.

    -
    - A tabela abaixo resume quando aplicar cada padrão. -
    -
    - - - - - - - - - - - - - - - - - -
    PadrãoBom paraCusto (calls LLM)
    ReAct estruturadoOutput schema garantidobaixo
    Plan-and-executeTarefas longas com passos discretosmédio
    ReflectionQualidade de escrita/código2–4× ReAct
    ReflexionLoops de auto-crítica estruturada3–5× ReAct
    Self-DiscoverTarefas novas exigindo "como pensar"3–4 calls extras
    ReWOOReduzir LLM calls (planner-once)baixo
    SupervisorEspecialistas dedicados, controle centralmédio
    NetworkColaboração peer-to-peermédio
    HierárquicoTimes de timesalto
    CRAGRAG quando retrieval falha às vezes+1 call (grader)
    Self-RAGGrounding e utilidade garantidos+3 calls (graders)
    Adaptive RAGRoteia entre vectorstore e web+1 call (router)
    LATSRaciocínio difícil com busca em árvore5–20× ReAct
    STORMArtigos longos com fontesalto
    -
    - -
    -

    R1. ReAct com saída estruturada

    -

    Ideia. Loop ReAct padrão, mas a resposta final passa por um schema Pydantic via uma tool dedicada WeatherResponse que termina a execução.

    -

    URL canônica: examples/react-agent-structured-output.ipynb

    -
    from typing import Literal
    -from pydantic import BaseModel
    -from langchain_openai import ChatOpenAI
    -from langgraph.graph import StateGraph, MessagesState, END
    -from langgraph.prebuilt import ToolNode
    -
    -class WeatherResponse(BaseModel):
    -    temperature: float
    -    conditions: str
    -
    -@tool
    -def search(query: str) -> str: ...
    -def respond(state: MessagesState):
    -    return {"final": state["messages"][-1].tool_calls[0]["args"]}
    -
    -llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([search, WeatherResponse])
    -
    -def call_model(state: MessagesState):
    -    return {"messages": [llm.invoke(state["messages"])]}
    -
    -def route(state) -> Literal["tools", "respond", END]:
    -    last = state["messages"][-1]
    -    if not last.tool_calls: return END
    -    if last.tool_calls[0]["name"] == "WeatherResponse": return "respond"
    -    return "tools"
    -
    -g = StateGraph(MessagesState)
    -g.add_node("agent", call_model); g.add_node("tools", ToolNode([search]))
    -g.add_node("respond", respond)
    -g.set_entry_point("agent"); g.add_conditional_edges("agent", route)
    -g.add_edge("tools", "agent"); g.add_edge("respond", END)
    -app = g.compile()
    -
    - -
    -

    R2. Plan-and-execute

    -

    Ideia. Gera plano completo upfront, executa step-a-step e replaneja quando necessário.

    -

    URL: examples/plan-and-execute

    -
    from pydantic import BaseModel
    -from langgraph.graph import StateGraph, END
    -
    -class Plan(BaseModel):
    -    steps: list[str]
    -
    -class PlanExecute(TypedDict):
    -    input: str
    -    plan: list[str]
    -    past_steps: list[tuple[str, str]]
    -    response: str
    -
    -planner   = planner_prompt   | ChatOpenAI(model="gpt-5.5", use_responses_api=True).with_structured_output(Plan)
    -executor  = create_react_agent("openai:gpt-5.4-mini", tools=[search])
    -replanner = replanner_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True).with_structured_output(Plan)
    -
    -async def plan_step(s):    return {"plan": (await planner.ainvoke({"input": s["input"]})).steps}
    -async def execute_step(s):
    -    step = s["plan"][0]
    -    out  = await executor.ainvoke({"messages":[("user", step)]})
    -    return {"past_steps": [(step, out["messages"][-1].content)]}
    -async def replan_step(s):  return {"plan": (await replanner.ainvoke(s)).steps}
    -def should_end(s):         return END if not s["plan"] else "agent"
    -
    -g = StateGraph(PlanExecute)
    -g.add_node("planner", plan_step); g.add_node("agent", execute_step); g.add_node("replan", replan_step)
    -g.set_entry_point("planner"); g.add_edge("planner", "agent")
    -g.add_edge("agent", "replan"); g.add_conditional_edges("replan", should_end)
    -app = g.compile()
    -
    - -
    -

    R3. Reflection

    -

    Ideia. Generator escreve, reflector critica, loop até crítico satisfeito ou N rodadas.

    -

    URL: examples/reflection · blog

    -
    from langgraph.graph import StateGraph, MessagesState, END
    -
    -generate = generator_prompt  | ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    -reflect  = reflection_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    -
    -async def generation_node(state: MessagesState):
    -    return {"messages": [await generate.ainvoke(state["messages"])]}
    -
    -async def reflection_node(state: MessagesState):
    -    # Flip roles para que o LLM veja o draft do assistente como input do usuário
    -    flipped = [HumanMessage(m.content) if isinstance(m, AIMessage) else AIMessage(m.content)
    -               for m in state["messages"][1:]]
    -    crit = await reflect.ainvoke([state["messages"][0]] + flipped)
    -    return {"messages": [HumanMessage(content=crit.content)]}
    -
    -def should_continue(state):
    -    return END if len(state["messages"]) > 6 else "reflect"
    -
    -g = StateGraph(MessagesState)
    -g.add_node("generate", generation_node); g.add_node("reflect", reflection_node)
    -g.set_entry_point("generate")
    -g.add_conditional_edges("generate", should_continue)
    -g.add_edge("reflect", "generate")
    -app = g.compile()
    -
    - -
    -

    R4. Reflexion

    -

    Ideia. Após cada trial, o agente produz auto-feedback verbal estruturado (missing/superfluous/search_queries) que entra em memória persistente consultada no próximo trial.

    -

    URL: examples/reflexion

    -
    from pydantic import BaseModel, Field
    -from langgraph.graph import StateGraph, MessagesState, END
    -
    -class Reflection(BaseModel):
    -    missing: str = Field(description="What's missing.")
    -    superfluous: str = Field(description="What's unnecessary.")
    -
    -class AnswerQuestion(BaseModel):
    -    answer: str
    -    reflection: Reflection
    -    search_queries: list[str] = Field(description="1-3 queries to address gaps.")
    -
    -responder = responder_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([AnswerQuestion])
    -revisor   = revisor_prompt   | ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([AnswerQuestion])
    -
    -def run_tools(state):
    -    queries = state["messages"][-1].tool_calls[0]["args"]["search_queries"]
    -    results = [tavily.invoke(q) for q in queries]
    -    return {"messages": [ToolMessage(content=str(results), tool_call_id="t")]}
    -
    -def event_loop(state):
    -    return END if state["messages"][-1].additional_kwargs.get("trial", 0) >= 3 else "execute_tools"
    -
    -g = StateGraph(MessagesState)
    -g.add_node("draft", lambda s: {"messages":[responder.invoke(s["messages"])]})
    -g.add_node("execute_tools", run_tools)
    -g.add_node("revise", lambda s: {"messages":[revisor.invoke(s["messages"])]})
    -g.set_entry_point("draft")
    -g.add_edge("draft","execute_tools"); g.add_edge("execute_tools","revise")
    -g.add_conditional_edges("revise", event_loop, {"execute_tools":"execute_tools", END:END})
    -app = g.compile()
    -
    - -
    -

    R5. Self-Discover

    -

    Ideia. Três passos: SELECT (módulos de raciocínio relevantes) → ADAPT (adapta ao problema) → IMPLEMENT (plano JSON) → solve. A estrutura de raciocínio é composta em runtime em vez de hardcoded.

    -

    URL: examples/self-discover

    -
    from langgraph.graph import StateGraph, END
    -
    -class State(TypedDict):
    -    task: str; modules: list[str]
    -    selected: str; adapted: str; plan: str; answer: str
    -
    -llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    -
    -def select(s):    return {"selected": llm.invoke(f"Select modules for: {s['task']}\nFrom: {s['modules']}").content}
    -def adapt(s):     return {"adapted":  llm.invoke(f"Adapt these to the task '{s['task']}': {s['selected']}").content}
    -def implement(s): return {"plan":     llm.invoke(f"Produce a JSON reasoning plan from: {s['adapted']}").content}
    -def solve(s):     return {"answer":   llm.invoke(f"Follow the plan to solve.\nTask: {s['task']}\nPlan: {s['plan']}").content}
    -
    -g = StateGraph(State)
    -g.add_node("select", select); g.add_node("adapt", adapt)
    -g.add_node("implement", implement); g.add_node("solve", solve)
    -g.set_entry_point("select")
    -g.add_edge("select", "adapt"); g.add_edge("adapt", "implement")
    -g.add_edge("implement", "solve"); g.add_edge("solve", END)
    -app = g.compile()
    -
    - -
    -

    R6. ReWOO (Reasoning WithOut Observation)

    -

    Ideia. Planner emite plano completo com placeholders de evidência (#E1, #E2); workers rodam tools para preencher; solver sintetiza. Sem diálogo intercalado LLM↔tool → menos tokens que ReAct.

    -

    URL: examples/rewoo

    -
    import re
    -from langgraph.graph import StateGraph, END
    -
    -PLAN_RE = re.compile(r"Plan:\s*(.*?)\n#E(\d+)\s*=\s*(\w+)\[(.*?)\]")
    -
    -class S(TypedDict):
    -    task: str; steps: list; results: dict; result: str
    -
    -def plan(s):
    -    raw = llm.invoke(planner_prompt.format(task=s["task"])).content
    -    return {"steps": PLAN_RE.findall(raw)}
    -
    -def tool_execution(s):
    -    _, n, tool, args = s["steps"][len(s["results"])]
    -    args = re.sub(r"#E(\d+)", lambda m: s["results"][f"#E{m.group(1)}"], args)
    -    return {"results": {**s["results"], f"#E{n}": tools[tool].invoke(args)}}
    -
    -def solve(s):
    -    plan = "\n".join(f"Plan: {p}\n#E{n} = {t}[{a}] = {s['results'][f'#E{n}']}"
    -                     for p,n,t,a in s["steps"])
    -    return {"result": llm.invoke(solver_prompt.format(task=s["task"], plan=plan)).content}
    -
    -def route(s): return END if len(s["results"]) == len(s["steps"]) else "tool"
    -
    -g = StateGraph(S)
    -g.add_node("plan", plan); g.add_node("tool", tool_execution); g.add_node("solve", solve)
    -g.set_entry_point("plan"); g.add_edge("plan", "tool")
    -g.add_conditional_edges("tool", route, {"tool":"tool","solve":"solve"}); g.add_edge("solve", END)
    -app = g.compile()
    -
    - -
    -

    R7. Multi-agent supervisor

    -

    Ideia. Um LLM supervisor escolhe qual especialista chamar próximo; cada chamada retorna controle ao supervisor.

    -

    URL: langgraph-supervisor-py

    -
    from langgraph_supervisor import create_supervisor
    -from langgraph.prebuilt import create_react_agent
    -from langgraph.checkpoint.memory import InMemorySaver
    -
    -def add(a: float, b: float) -> float: return a + b
    -def web_search(q: str) -> str: return tavily.invoke(q)
    -
    -math_agent     = create_react_agent(model="openai:gpt-5.5", tools=[add], name="math_expert")
    -research_agent = create_react_agent(model="openai:gpt-5.5", tools=[web_search], name="research_expert")
    -
    -workflow = create_supervisor(
    -    [research_agent, math_agent],
    -    model=ChatOpenAI(model="gpt-5.5", use_responses_api=True),
    -    prompt="You manage a research expert and a math expert. Route accordingly.",
    -)
    -app = workflow.compile(checkpointer=InMemorySaver())
    -result = app.invoke({"messages":[{"role":"user",
    -    "content":"What's the combined FAANG headcount in 2024?"}]})
    -
    - Note o contraste: os subagents acima usam a string "openai:gpt-5.5" - (que cai em Chat Completions), enquanto o supervisor recebe um - ChatOpenAI(..., use_responses_api=True) explícito. Para forçar a - Responses API nos subagents, instancie o modelo e passe o objeto em vez da - string — ver a política de integração (§2). -
    -
    - -
    -

    R8. Multi-agent network (colaboração)

    -

    Ideia. Cada agent pode passar trabalho para qualquer peer; roteamento decidido por tool calls. FINAL ANSWER termina.

    -

    URL: multi-agent-collaboration.ipynb

    -
    from langgraph.graph import StateGraph, MessagesState, END
    -
    -def make_node(agent, name):
    -    def node(state):
    -        result = agent.invoke(state)
    -        result["messages"][-1].name = name
    -        return {"messages": result["messages"]}
    -    return node
    -
    -def route(state):
    -    last = state["messages"][-1]
    -    if "FINAL ANSWER" in last.content: return END
    -    return "Chart Generator" if last.name == "Researcher" else "Researcher"
    -
    -researcher = create_react_agent(llm, tools=[search],     prompt=research_prompt)
    -charter    = create_react_agent(llm, tools=[python_repl], prompt=chart_prompt)
    -
    -g = StateGraph(MessagesState)
    -g.add_node("Researcher",      make_node(researcher, "Researcher"))
    -g.add_node("Chart Generator", make_node(charter,    "Chart Generator"))
    -g.set_entry_point("Researcher")
    -g.add_conditional_edges("Researcher",      route, {"Chart Generator":"Chart Generator", END:END})
    -g.add_conditional_edges("Chart Generator", route, {"Researcher":"Researcher", END:END})
    -app = g.compile()
    -
    - -
    -

    R9. Times hierárquicos

    -

    Ideia. Cada sub-time é um subgrafo com seu próprio supervisor; um supervisor de topo roteia entre times.

    -

    URL: hierarchical_agent_teams.ipynb

    -
    from langgraph.graph import StateGraph, MessagesState, END
    -
    -def call_research(state): return research_team.invoke({"messages": state["messages"]})
    -def call_writing(state):  return writing_team.invoke({"messages":  state["messages"]})
    -
    -def top_supervisor(state):
    -    return llm.with_structured_output(Route).invoke(supervisor_prompt + state["messages"])
    -
    -def route(state):
    -    decision = state["next"]   # "research_team" | "writing_team" | "FINISH"
    -    return END if decision == "FINISH" else decision
    -
    -g = StateGraph(MessagesState)
    -g.add_node("supervisor",    lambda s: {"next": top_supervisor(s).destination})
    -g.add_node("research_team", call_research)
    -g.add_node("writing_team",  call_writing)
    -g.set_entry_point("supervisor")
    -g.add_conditional_edges("supervisor", route)
    -g.add_edge("research_team", "supervisor"); g.add_edge("writing_team", "supervisor")
    -app = g.compile()
    -
    - -
    -

    R10. Corrective RAG (CRAG)

    -

    Ideia. Grader avalia docs recuperados; se relevância baixa, reescreve a query e cai em web search antes de gerar.

    -

    URL: examples/rag/langgraph_crag.ipynb

    -
    from langgraph.graph import StateGraph, END
    -
    -class S(TypedDict):
    -    question: str; documents: list; web_search: str; generation: str
    -
    -def retrieve(s):
    -    return {"documents": retriever.invoke(s["question"])}
    -
    -def grade(s):
    -    kept = [d for d in s["documents"]
    -            if "yes" in grader.invoke({"q": s["question"], "d": d.page_content}).binary_score]
    -    return {"documents": kept, "web_search": "Yes" if not kept else "No"}
    -
    -def transform_query(s):
    -    return {"question": rewriter.invoke({"question": s["question"]}).content}
    -
    -def web_search_node(s):
    -    docs = tavily.invoke(s["question"])
    -    return {"documents": s["documents"] + [Document(page_content=d["content"]) for d in docs]}
    -
    -def generate(s):
    -    return {"generation": rag_chain.invoke({"q": s["question"], "docs": s["documents"]})}
    -
    -def decide(s): return "transform_query" if s["web_search"]=="Yes" else "generate"
    -
    -g = StateGraph(S)
    -for n, f in [("retrieve",retrieve),("grade",grade),("transform_query",transform_query),
    -             ("web_search",web_search_node),("generate",generate)]:
    -    g.add_node(n, f)
    -g.set_entry_point("retrieve"); g.add_edge("retrieve","grade")
    -g.add_conditional_edges("grade", decide); g.add_edge("transform_query","web_search")
    -g.add_edge("web_search","generate"); g.add_edge("generate", END)
    -app = g.compile()
    -
    - -
    -

    R11. Self-RAG

    -

    Ideia. Três graders independentes: relevância por doc, grounding (alucinação) e utilidade da resposta. Retry de retrieval ou geração até passar nos três.

    -

    URL: examples/rag/langgraph_self_rag.ipynb

    -
    from langgraph.graph import StateGraph, END
    -
    -class S(TypedDict): question: str; documents: list; generation: str
    -
    -def retrieve(s):  return {"documents": retriever.invoke(s["question"])}
    -def grade_docs(s):
    -    kept = [d for d in s["documents"]
    -            if doc_grader.invoke({"q": s["question"], "d": d.page_content}).score == "yes"]
    -    return {"documents": kept}
    -def generate(s):  return {"generation": rag.invoke({"q": s["question"], "docs": s["documents"]})}
    -def transform(s): return {"question": rewriter.invoke({"q": s["question"]}).content}
    -
    -def decide_after_grade(s):    return "generate" if s["documents"] else "transform_query"
    -def decide_after_generate(s):
    -    grounded = halluc_grader.invoke({"docs": s["documents"], "gen": s["generation"]}).score == "yes"
    -    if not grounded: return "generate"
    -    useful = answer_grader.invoke({"q": s["question"], "gen": s["generation"]}).score == "yes"
    -    return END if useful else "transform_query"
    -
    -g = StateGraph(S)
    -for n, f in [("retrieve",retrieve),("grade",grade_docs),
    -             ("generate",generate),("transform_query",transform)]:
    -    g.add_node(n, f)
    -g.set_entry_point("retrieve"); g.add_edge("retrieve","grade")
    -g.add_conditional_edges("grade",    decide_after_grade)
    -g.add_edge("transform_query","retrieve")
    -g.add_conditional_edges("generate", decide_after_generate)
    -app = g.compile()
    -
    - -
    -

    R12. Adaptive RAG

    -

    Ideia. Router escolhe vectorstore vs. web search por query, depois roda um loop Self-RAG. Adapta a estratégia de retrieval à classe da pergunta.

    -

    URL: examples/rag/langgraph_adaptive_rag.ipynb

    -
    from pydantic import BaseModel, Field
    -from langgraph.graph import StateGraph, END
    -
    -class Route(BaseModel):
    -    datasource: Literal["vectorstore","web_search"] = Field(description="Pick one")
    -
    -router = (router_prompt | ChatOpenAI(model="gpt-5.4-mini", temperature=0, use_responses_api=True)
    -                          .with_structured_output(Route))
    -
    -def route_query(s):
    -    return "web_search" if router.invoke({"question": s["question"]}).datasource == "web_search" \
    -                        else "retrieve"
    -
    -g = StateGraph(S)
    -g.add_node("retrieve", retrieve); g.add_node("web_search", web_search_node)
    -g.add_node("grade", grade_docs); g.add_node("generate", generate)
    -g.add_node("transform_query", transform)
    -g.set_conditional_entry_point(route_query, {"retrieve":"retrieve", "web_search":"web_search"})
    -g.add_edge("retrieve","grade"); g.add_edge("web_search","generate")
    -g.add_conditional_edges("grade", lambda s: "generate" if s["documents"] else "transform_query")
    -g.add_edge("transform_query","retrieve")
    -g.add_conditional_edges("generate", decide_after_generate)
    -app = g.compile()
    -
    - -
    -

    R13. LATS — Language Agent Tree Search

    -

    Ideia. MCTS sobre trajetórias de raciocínio LLM com seleção UCB, avaliação por reflexão e backpropagation. Troca 5–20× LLM calls por taxa de solução maior em raciocínio difícil.

    -

    URL: examples/lats/lats.ipynb

    -
    import math
    -from dataclasses import dataclass, field
    -
    -@dataclass
    -class Node:
    -    messages: list
    -    parent: "Node | None" = None
    -    children: list = field(default_factory=list)
    -    value: float = 0.0
    -    visits: int = 0
    -    reflection: str | None = None
    -
    -    def uct(self, c=1.4):
    -        if self.visits == 0: return float("inf")
    -        return self.value/self.visits + c*math.sqrt(math.log(self.parent.visits)/self.visits)
    -
    -    def best_child(self): return max(self.children, key=lambda n: n.uct())
    -    def is_solved(self):  return self.reflection and "SOLVED" in self.reflection
    -
    -def expand(node):
    -    candidates = generator.batch([node.messages]*5)
    -    node.children = [Node(node.messages+[c], parent=node) for c in candidates]
    -
    -def evaluate(node):
    -    node.reflection = reflector.invoke(node.messages).content
    -    score = float(reflector_score(node.reflection))
    -    while node:
    -        node.visits += 1; node.value += score
    -        node = node.parent
    -
    -def lats(root, max_rollouts=10):
    -    for _ in range(max_rollouts):
    -        leaf = root
    -        while leaf.children: leaf = leaf.best_child()
    -        expand(leaf)
    -        for child in leaf.children:
    -            evaluate(child)
    -            if child.is_solved(): return child
    -    return root.best_child()
    -
    - -
    -

    R14. STORM — pesquisa + escrita

    -

    Ideia. Gera outline, simula entrevistas com múltiplos experts (cada um busca e responde em paralelo via Send), refina outline, escreve seções, monta artigo.

    -

    URL: examples/storm/storm.ipynb

    -
    from langgraph.graph import StateGraph, END
    -from langgraph.constants import Send
    -
    -def outline(s):      return {"outline":  outline_llm.invoke({"topic": s["topic"]})}
    -def perspectives(s): return {"experts":  expert_llm.invoke({"outline": s["outline"]}).experts}
    -
    -def dispatch(s):  # fan-out paralelo
    -    return [Send("interview", {"expert": e, "topic": s["topic"]}) for e in s["experts"]]
    -
    -def interview(s):
    -    qa = []
    -    for _ in range(3):
    -        q    = question_llm.invoke({"expert": s["expert"], "qa": qa})
    -        docs = search.invoke(q)
    -        a    = answer_llm.invoke({"q": q, "docs": docs})
    -        qa.append({"q": q, "a": a})
    -    return {"interviews": [{"expert": s["expert"], "qa": qa}]}
    -
    -def refine(s):  return {"outline_v2": refine_llm.invoke({"out": s["outline"], "int": s["interviews"]})}
    -def write(s):   return {"article":    writer_llm.invoke({"outline": s["outline_v2"], "int": s["interviews"]})}
    -
    -g = StateGraph(STORMState)
    -for n, f in [("outline",outline),("perspectives",perspectives),
    -             ("interview",interview),("refine",refine),("write",write)]:
    -    g.add_node(n, f)
    -g.set_entry_point("outline"); g.add_edge("outline","perspectives")
    -g.add_conditional_edges("perspectives", dispatch, ["interview"])
    -g.add_edge("interview","refine"); g.add_edge("refine","write"); g.add_edge("write", END)
    -app = g.compile()
    -
    - -
    -

    Apêndice — endpoints REST e variáveis-chave

    -

    HTTP cheat-sheet

    -
    # Threads
    -POST   /threads
    -POST   /threads/search
    -GET    /threads/{id}
    -PATCH  /threads/{id}
    -DELETE /threads/{id}
    -POST   /threads/{id}/copy
    -GET    /threads/{id}/state
    -POST   /threads/{id}/state           # update_state
    -GET    /threads/{id}/history
    -GET    /threads/{id}/stream          # thread-wide SSE (atravessa runs)
    -
    -# Runs (em uma thread)
    -POST   /threads/{tid}/runs
    -POST   /threads/{tid}/runs/stream
    -POST   /threads/{tid}/runs/wait
    -GET    /threads/{tid}/runs
    -GET    /threads/{tid}/runs/{rid}
    -POST   /threads/{tid}/runs/{rid}/cancel
    -GET    /threads/{tid}/runs/{rid}/join
    -GET    /threads/{tid}/runs/{rid}/stream  # join_stream
    -
    -# Stateless runs
    -POST   /runs
    -POST   /runs/stream
    -POST   /runs/wait
    -
    -# Assistants
    -POST   /assistants
    -POST   /assistants/search
    -GET    /assistants/{id}
    -PATCH  /assistants/{id}
    -DELETE /assistants/{id}
    -GET    /assistants/{id}/versions
    -
    -# Crons
    -POST   /runs/crons
    -POST   /threads/{tid}/runs/crons
    -POST   /runs/crons/search
    -DELETE /runs/crons/{cid}
    -
    -# Store
    -PUT    /store/items
    -GET    /store/items
    -DELETE /store/items
    -POST   /store/items/search
    -POST   /store/namespaces
    -
    -# Health
    -GET    /ok
    - -

    Variáveis-chave Standalone Server

    -
    - - - - - - - - -
    VariávelFunção
    DATABASE_URIPostgres ≥ 14 (checkpoints, assistants, threads, runs, crons, store)
    REDIS_URIRedis ≥ 6 (pubsub para fan-out de streaming)
    LANGGRAPH_CLOUD_LICENSE_KEYLicença Enterprise
    LANGSMITH_API_KEYPush para LangSmith / tracing
    LG_WEBHOOK_*Variáveis seguras interpoláveis em headers de webhook
    -
    - -
    -
    - - - - - + + + + + +Guia LangGraph — Referência completa (Python) + + + + + + + + +
    +
    +
    Guia LangGraph Python — Referência completa
    +
    + Verificado em 2026-07-12 + langgraph + Python + +
    +
    +
    + +
    + + +
    + +
    +

    Guia LangGraph — Referência completa (Python)

    +

    + Documentação técnica exaustiva do LangGraph em Python, o runtime + de orquestração de baixo nível usado pelo LangChain e pelo Deep Agents para + construir agentes stateful, durables e de longa duração. + Cobre StateGraph, Send, Command, + persistência (checkpointers SQLite/Postgres/Redis), human-in-the-loop, + streaming v2, memória curta e longa, multi-agent (supervisor/swarm), time + travel, durable execution e a Functional API. +

    +
    + langgraph + Python 3.10+ + SOTA · 2026-06-29 +
    +
    + +
    +

    Sobre este guia

    +

    + Este guia é uma conversão fiel da documentação oficial pública + do LangGraph em + docs.langchain.com/oss/python/langgraph, + complementada pelos pacotes prebuilt langgraph-supervisor e + langgraph-swarm e pela referência de API em + reference.langchain.com/python/langgraph. +

    +

    + A Parte A apresenta os conceitos em 26 capítulos, na ordem de + leitura recomendada. A Parte B é a referência técnica de cada + classe pública: assinatura, parâmetros em tabela, métodos relevantes e exemplos. + Todos os exemplos estão em Python — a porta oficial em JavaScript existe em + langchain-ai/langgraphjs + mas tem APIs próprias e não é coberta aqui. +

    +
    + Como ler: a Parte A ensina os padrões e a + mecânica de execução. A Parte B é consulta rápida: cada classe + traz sua assinatura, atributos em tabela e métodos em blocos + <details> expansíveis (clique no ▸ para abrir). +
    +
    + Notas de versão: alguns recursos são recentes — node timeouts + (TimeoutPolicy) e graceful drain (RunControl/ + GraphDrained) exigem langgraph >= 1.2; + DeltaChannel (otimização de armazenamento) também é 1.2+; + add_sequence exige >= 0.2.46; + context_schema substituiu config_schema em + >= 0.6.0. O default da recursion_limit passou a ser + 1000 em >= 1.0.6. +
    Atualização 2026-07-12: último PyPI langgraph 1.2.9 (2026-07-10; deps: langchain-core >=1.4.7,<2, langgraph-checkpoint >=4.1,<5, langgraph-prebuilt >=1.1,<1.2). As 1.2.7→1.2.9 são bugfix sobre a 1.2.6, sem mudança de superfície pública; seguem na linha 1.x (compromisso de estabilidade até a 2.0). Ressalva: "estável" não significa zero mudanças no histórico da série — a 1.2.3 foi yanked (regressão de merge) e depois corrigida na 1.2.6, e renomeou ProtocolEvent.eventId→event_id (afeta quem consome o streaming v3/protocolo beta). Fixe uma versão específica testada (ex.: ==1.2.9), não apenas >=1.2. Novidades 1.2.x além das acima: error_handler= por nó (recebe NodeError, retorna Command para compensação/reroteamento — padrão Saga; Python-only), interrupt_mode + predicado when no HumanInTheLoopMiddleware, e event streaming v2/v3 (beta, projeções tipadas por canal). Todos opt-in e retrocompatíveis. Resumo 1.2.2→1.2.4: fix de IDs estáveis para checkpoints com DeltaChannel (1.2.2); streaming v3 no RemoteGraph e rename ProtocolEvent.eventId → event_id (1.2.3 — relevante para quem consome eventos do protocolo beta v3); ensure_config agora faz merge de callbacks/tags/metadata (1.2.3); fix de compatibilidade _on_started (1.2.4); merge de lc_versions nos metadados de config e fix de updateState/DeltaChannel em thread vazia (1.2.5 — só bugfix); nested-subgraph herda checkpoint_ns do pai (regressão da 1.2.3), cancelamento de subgraphs em abort de stream v3 e Tornado→6.5.6 (1.2.6 — só bugfix). Sem mudanças nas superfícies públicas de StateGraph/interrupt/Command. +
    +
    + +
    +

    Fontes oficiais

    + +

    + Última verificação contra estas fontes: 2026-06-10. + Sempre que houver divergência entre este guia e a documentação oficial em + produção, a documentação oficial é a fonte autoritativa. +

    +
    + +
    +

    Parte A — Conceitos

    +

    Vinte e seis capítulos cobrindo o LangGraph na ordem de leitura recomendada da documentação oficial.

    +
    + +
    +

    1. Visão geral

    +

    + O LangGraph é definido pela documentação oficial como + "a low-level orchestration framework and runtime for building, managing, and + deploying long-running, stateful agents". É inspirado em Pregel, Apache Beam + e NetworkX, e modela um workflow como um grafo direcionado com três componentes: +

    +
      +
    1. State — um snapshot compartilhado, definido como + TypedDict, dataclass ou Pydantic BaseModel.
    2. +
    3. Nodes — funções Python que codificam a lógica.
    4. +
    5. Edges — funções (ou edges estáticos) que determinam a + próxima execução.
    6. +
    +

    + A execução acontece em super-steps discretos via passagem de mensagens: + nós começam inactive, ficam active ao receber mensagens e a + execução termina quando todos os nós estão inativos e não há mensagens em + trânsito. Nós que rodam em paralelo compartilham o mesmo super-step; sequenciais + ocupam super-steps distintos. +

    +

    Benefícios principais

    +
    + + + + + + + + + +
    BenefícioDescrição
    Durable executionAgentes persistem por falhas e retomam de checkpoints.
    Human-in-the-loopInspeção e modificação do estado do agente em qualquer ponto.
    Memória abrangenteWorking memory por thread + memória de longo prazo cross-session.
    DebuggingLangSmith provê visualização de traces e métricas de runtime.
    DeploymentInfra escalável para workflows stateful de longa duração.
    +
    +

    Posição no ecossistema

    +
    + + + + + + + + + + +
    ProdutoPapel
    Deep AgentsHarness do agente: planning, subagents, FS, gerenciamento de contexto.
    LangChainFramework de agente: abstrações de modelo/tool e o agent loop.
    LangGraphRuntime de orquestração: durable execution, streaming, HITL.
    LangSmithTracing, evaluations, prompts, deployment.
    LangSmith EngineDetecta issues em traces de produção e propõe correções/PRs automaticamente.
    LangSmith FleetConstrutor no-code de agentes.
    +
    + +
    + +
    +

    2. Instalação

    +
    pip install -U langgraph
    +# ou
    +uv add langgraph
    +

    + Pacotes complementares conforme o uso: +

    +
    + + + + + + + + + + + +
    PacotePropósito
    langgraphNúcleo (StateGraph, runtime, in-memory checkpointer).
    langgraph-checkpoint-sqliteSqliteSaver / AsyncSqliteSaver.
    langgraph-checkpoint-postgresPostgresSaver / AsyncPostgresSaver.
    langgraph-checkpoint-redisRedisSaver / AsyncRedisSaver (community Redis).
    langgraph-supervisorPadrão supervisor multi-agent (create_supervisor).
    langgraph-swarmPadrão swarm (create_swarm).
    langchain / langchain-openai / langchain-anthropic / langchain-google-genaiModelos e mensagens — opcionais, mas a maior parte dos exemplos depende deles.
    +
    +

    O overview oficial não declara versão mínima de Python; na prática, o pacote suporta Python 3.10+.

    + +

    Política de integração de modelos (chat models)

    +

    + O LangGraph não fala com provedores diretamente — ele orquestra + chat models do LangChain. Como cada classe roteia para uma API + diferente, vale fixar a política antes dos exemplos: +

    +
    + + + + + + + +
    ProvedorClasse / pacoteAPI atingida
    OpenAIChatOpenAI · langchain-openaiResponses API quando use_responses_api=True; caso contrário, Chat Completions.
    AnthropicChatAnthropic · langchain-anthropicMessages API nativa da Anthropic (SDK anthropic) — não é wrapper.
    GoogleChatGoogleGenerativeAI · langchain-google-genaiSDK consolidado google-genai (v4.0.0+), via generateContent.
    +
    +
    + OpenAI — Responses API não é automática com string. Passar uma + string "openai:gpt-5.5" a create_agent/create_react_agent + cai em Chat Completions. Para garantir a Responses API (ex.: ZDR, + threading server-side), instancie ChatOpenAI(model="gpt-5.5", use_responses_api=True) + e passe o objeto como model=. +
    +
    from langchain_openai import ChatOpenAI
    +from langchain_anthropic import ChatAnthropic
    +from langchain_google_genai import ChatGoogleGenerativeAI
    +
    +# OpenAI — Responses API (NUNCA Chat Completions): use a flag explícita.
    +openai_llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    +
    +# Anthropic — SDK nativo (Messages API):
    +anthropic_llm = ChatAnthropic(model="claude-sonnet-4-6")
    +
    +# Google — SDK google-genai (>= 4.0); em strings provider:model use "google_genai:"
    +google_llm = ChatGoogleGenerativeAI(model="gemini-3.5-flash")  # str: "google_genai:gemini-3.5-flash"
    +
    +# (opcional) threading server-side por response id no OpenAI:
    +openai_llm = ChatOpenAI(model="gpt-5.4-mini", use_previous_response_id=True)
    +

    + O roteamento para a Responses API também é automático (sem a + flag) quando o modelo usa: (a) built-in tools (web_search, + file_search, image generation, computer use, code interpreter, + remote MCP), (b) o parâmetro reasoning={"effort": ..., "summary": ...}, + ou (c) previous_response_id na invocação. Não existe flag + output_version nem um ID de modelo que "force" Responses — o caminho + é use_responses_api=True ou um desses gatilhos. +

    +
    # Estes já roteiam para a Responses API automaticamente:
    +llm        = ChatOpenAI(model="gpt-5.5", reasoning={"effort": "medium", "summary": "auto"})
    +llm_tools  = ChatOpenAI(model="gpt-5.4-mini").bind_tools([{"type": "web_search_preview"}])
    +
    + Gemini Interactions API: a Interactions API do Gemini (endpoint + /interactions, stateful/agêntica) não tem integração + nativa com LangChain/LangGraph/Deep Agents (maio/2026). + ChatGoogleGenerativeAI usa generateContent via + google-genai; recursos exclusivos da Interactions API + (histórico server-side via previous_interaction_id, agentes + gerenciados) não são expostos. Não existe + ChatGoogleGenerativeAI(use_interactions_api=...). Para usá-la hoje, + chame o SDK google-genai diretamente — a Interactions API é coberta + no guia dedicado Gemini Interactions API. +
    + +
    + +
    +

    3. Modelo conceitual

    +

    Hello-world

    +
    from langgraph.graph import StateGraph, MessagesState, START, END
    +
    +def mock_llm(state: MessagesState):
    +    return {"messages": [{"role": "ai", "content": "hello world"}]}
    +
    +graph = StateGraph(MessagesState)
    +graph.add_node(mock_llm)
    +graph.add_edge(START, "mock_llm")
    +graph.add_edge("mock_llm", END)
    +graph = graph.compile()
    +
    +graph.invoke({"messages": [{"role": "user", "content": "hi!"}]})
    +

    Super-steps

    +

    + Cada tick do grafo é um super-step. Para um pipeline sequencial + START → A → B → END, quatro checkpoints são produzidos + (vazio/inicial, após input, após A, após B). Nós com múltiplas arestas de saída + disparam todos os destinos em paralelo no super-step seguinte. +

    +

    Graph API vs Functional API

    +
    + + + + + + + + +
    AspectoFunctional APIGraph API
    Controle de fluxoPython padrão (if, for, chamadas)Estrutura explícita de grafo/DAG
    EstadoEscopo da função; sem state explícitoRequer State + reducers
    CheckpointingSalva resultados de @task no checkpoint atualNovo checkpoint após cada super-step
    VisualizaçãoNão suportada (dinâmico em runtime)Suportada; útil para debug
    +
    + +
    + +
    +

    4. StateGraph

    +

    + StateGraph é o construtor de grafo. Recebe o schema de estado e, + opcionalmente, schemas de contexto, input e output. +

    +
    from langgraph.graph import StateGraph, START, END
    +from typing_extensions import TypedDict
    +
    +class State(TypedDict):
    +    foo: int
    +    bar: list[str]
    +
    +builder = StateGraph(State)
    +# ... add_node / add_edge ...
    +graph = builder.compile()
    +

    Schemas de entrada, saída e privados

    +

    + O schema principal define o overall state. Schemas opcionais permitem + expor um contrato mais estrito para o cliente: +

    +
    class InputState(TypedDict):
    +    user_input: str
    +
    +class OutputState(TypedDict):
    +    graph_output: str
    +
    +class OverallState(TypedDict):
    +    foo: str
    +    user_input: str
    +    graph_output: str
    +
    +class PrivateState(TypedDict):
    +    bar: str
    +
    +def node_1(state: InputState) -> OverallState:
    +    return {"foo": state["user_input"] + " name"}
    +
    +def node_2(state: OverallState) -> PrivateState:
    +    return {"bar": state["foo"] + " is"}
    +
    +def node_3(state: PrivateState) -> OutputState:
    +    return {"graph_output": state["bar"] + " Lance"}
    +
    +builder = StateGraph(OverallState, input_schema=InputState, output_schema=OutputState)
    +builder.add_node("node_1", node_1)
    +builder.add_node("node_2", node_2)
    +builder.add_node("node_3", node_3)
    +builder.add_edge(START, "node_1")
    +builder.add_edge("node_1", "node_2")
    +builder.add_edge("node_2", "node_3")
    +builder.add_edge("node_3", END)
    +
    +graph = builder.compile()
    +graph.invoke({"user_input": "My"})
    +# {'graph_output': 'My name is Lance'}
    +
    + Um nó pode escrever em qualquer chave do estado — não apenas + nas que estão no seu schema de entrada. PrivateState é registrado + automaticamente quando referenciado em assinaturas de nó. +
    + +
    + +
    +

    5. Schemas de estado

    +

    + O estado pode ser declarado de três formas: TypedDict (recomendado + por performance), dataclass ou Pydantic BaseModel (com + validação recursiva, mas mais lento). +

    +
    from typing_extensions import TypedDict
    +
    +class State(TypedDict):
    +    foo: int
    +    bar: list[str]
    +
    + Limitações conhecidas do Pydantic como state schema: +
      +
    • A saída não é uma instância Pydantic.
    • +
    • Validação roda apenas nos inputs do primeiro nó.
    • +
    • O traceback não identifica o nó que falhou.
    • +
    +
    + +
    + +
    +

    6. Reducers

    +

    + Cada chave do estado tem um reducer independente. Sem reducer, atualizações + sobrescrevem a chave. Para acumular, use Annotated: +

    +
    from typing import Annotated
    +from operator import add
    +from typing_extensions import TypedDict
    +
    +class State(TypedDict):
    +    foo: int                        # overwrite
    +    bar: Annotated[list[str], add]  # concat
    +

    Bypass de reducer com Overwrite

    +
    from langgraph.types import Overwrite
    +
    +def replace_messages(state: State):
    +    return {"messages": Overwrite(["replacement message"])}
    +# Forma JSON-compatível:
    +# return {"messages": {"__overwrite__": ["replacement message"]}}
    +
    + Receber múltiplos Overwrite para a mesma chave em + um único super-step levanta InvalidUpdateError. +
    + +

    Canais do Pregel (camada de baixo nível)

    +

    + Por baixo de reducers e Annotated, cada chave do estado é um + canal do Pregel. O tipo do canal define a semântica de escrita ao + longo dos super-steps. A maioria dos grafos nunca instancia canais + diretamente — eles são inferidos do schema —, mas conhecê-los ajuda a + entender o comportamento de acumulação e a API Pregel crua. +

    +
    + + + + + + + + + +
    CanalImportSemântica
    LastValuelanggraph.channelsDefault; guarda apenas o último valor escrito (sobrescreve).
    Topiclanggraph.channelsPubSub; Topic(str, accumulate=True) acumula todos os valores escritos no run.
    BinaryOperatorAggregatelanggraph.channelsAgregado corrente via operador binário (ex.: operator.add).
    EphemeralValuelanggraph.channelsValor transitório: existe só durante o super-step; não é persistido entre steps.
    DeltaChannel betalanggraph.channelsReducer em bulk com snapshots periódicos (requer langgraph >= 1.2).
    +
    +
    from langgraph.channels import (
    +    LastValue, Topic, BinaryOperatorAggregate, EphemeralValue, DeltaChannel,
    +)
    +import operator
    +
    +ch: LastValue[int] = LastValue(int)                 # default; sobrescreve valor anterior
    +topic: Topic[str] = Topic(str, accumulate=True)     # PubSub; acumula valores no run
    +total = BinaryOperatorAggregate(int, operator.add)  # agregado corrente via operador binário
    + +

    DeltaChannel — reducer em bulk com snapshots beta · langgraph >= 1.2

    +

    + O DeltaChannel usa um bulk reducer: em vez de ser + chamado pairwise (estado atual + uma write por vez), recebe o estado atual mais + uma sequência com todas as writes do super-step numa + única chamada — útil quando o reducer é associativo e se beneficia de processar + o lote inteiro de uma vez. +

    +
    from typing import Annotated
    +from typing_extensions import TypedDict
    +from langgraph.channels import DeltaChannel
    +
    +class State(TypedDict):
    +    messages: Annotated[list[str], DeltaChannel(my_reducer, snapshot_frequency=5)]
    +
      +
    • snapshot_frequency=K grava um snapshot completo a cada K steps, limitando a latência de leitura a O(K); None (default) = sem snapshots.
    • +
    • API ainda beta — pode mudar entre versões.
    • +
    + +

    API Pregel crua

    +

    + Para construir grafos sem o açúcar de StateGraph, há a API de + baixo nível com Pregel e NodeBuilder: +

    +
    from langgraph.channels import EphemeralValue
    +from langgraph.pregel import Pregel, NodeBuilder
    + +
    + +
    +

    7. MessagesState e add_messages

    +

    + add_messages é o reducer canônico para listas de mensagens. Por + padrão concatena; quando uma mensagem nova tem o mesmo + id de uma existente, sobrescreve; ainda + desserializa dicts em objetos de mensagem do LangChain. +

    +
    from langchain.messages import AnyMessage
    +from langgraph.graph.message import add_messages
    +from typing import Annotated
    +from typing_extensions import TypedDict
    +
    +class GraphState(TypedDict):
    +    messages: Annotated[list[AnyMessage], add_messages]
    +

    Atalho MessagesState

    +
    from langgraph.graph import MessagesState
    +
    +class State(MessagesState):
    +    documents: list[str]   # estende com campos extras
    +

    Formato OpenAI

    +

    + add_messages(format="langchain-openai") reformata o conteúdo em + blocos text/image_url e converte respostas de + ferramenta em ToolMessage. Requer + langchain-core >= 0.3.11 (piso mínimo do recurso). Atenção: a linha atual de + langchain-core é a 1.x (último 1.4.9) — a virada 0.3.x→1.0 trouxe + mudanças incompatíveis (ex.: AIMessage como tipo concreto de retorno, .text() virou + property, Python 3.9 removido); o 0.3.x está em maintenance mode até dez/2026. Pacotes + relacionados na 1.x: langchain 1.3.13, langchain-anthropic 1.4.8, + langchain-google-genai 4.2.7 (requer langchain-core>=1.4.7). +

    +
    + +
    +

    8. Nodes

    +

    + Um nó é uma função Python cujo primeiro argumento é o estado. Argumentos + opcionais (por nome+tipo): config: RunnableConfig e + runtime: Runtime[ContextT]. +

    +
    from langgraph.runtime import Runtime
    +from dataclasses import dataclass
    +from typing_extensions import TypedDict
    +from langgraph.graph import StateGraph
    +
    +class State(TypedDict):
    +    input: str
    +    results: str
    +
    +@dataclass
    +class Context:
    +    user_id: str
    +
    +builder = StateGraph(State)
    +
    +def plain_node(state: State):
    +    return state
    +
    +def node_with_runtime(state: State, runtime: Runtime[Context]):
    +    print("In node: ", runtime.context.user_id)
    +    return {"results": f"Hello, {state['input']}!"}
    +
    +def node_with_execution_info(state: State, runtime: Runtime):
    +    print("Thread:", runtime.execution_info.thread_id)
    +    return {"results": f"Hello, {state['input']}!"}
    +
    +builder.add_node("plain_node", plain_node)
    +builder.add_node("node_with_runtime", node_with_runtime)
    +builder.add_node("node_with_execution_info", node_with_execution_info)
    +

    + Auto-naming: builder.add_node(my_node) registra como + "my_node". +

    +
    + +
    +

    9. Edges

    +

    Edges normais e condicionais

    +
    graph.add_edge("node_a", "node_b")
    +graph.add_conditional_edges("node_a", routing_function)
    +graph.add_conditional_edges("node_a", routing_function, {True: "node_b", False: "node_c"})
    +graph.add_edge(START, "node_a")
    +graph.add_conditional_edges(START, routing_function)
    +graph.add_conditional_edges(START, routing_function, {True: "node_b", False: "node_c"})
    +
    + Para cada nó, escolha um mecanismo de roteamento: edges + estáticos para roteamento fixo, ou edges condicionais / Command + para roteamento dinâmico. Nós com múltiplas saídas executam todos os + destinos em paralelo. +
    +

    Atalho de sequência (langgraph >= 0.2.46)

    +
    builder = StateGraph(State).add_sequence([step_1, step_2, step_3])
    +builder.add_edge(START, "step_1")
    +

    Fan-out / fan-in, defer

    +
    builder.add_edge(START, "a")
    +builder.add_edge("a", "b")
    +builder.add_edge("a", "c")
    +builder.add_edge("b", "d")
    +builder.add_edge("c", "d")
    +builder.add_edge("d", END)
    +

    + Quando ramos têm comprimentos diferentes, marque o nó de junção como + deferred: +

    +
    builder.add_node(d, defer=True)
    +
    + +
    +

    10. Send (map-reduce)

    +

    + Send(node_name, state_dict) despacha uma cópia distinta do estado + para o nó nomeado. O uso principal é map-reduce com fan-out paralelo. +

    +
    from langgraph.types import Send
    +
    +def continue_to_jokes(state: OverallState):
    +    return [Send("generate_joke", {"subject": s}) for s in state['subjects']]
    +
    +graph.add_conditional_edges("node_a", continue_to_jokes)
    +
    + +
    +

    11. Command (roteamento + atualização de estado)

    +

    + Command permite que um nó atualize estado e roteie + dinamicamente, tudo no retorno: +

    +
    from langgraph.types import Command
    +from typing_extensions import Literal
    +
    +def my_node(state: State) -> Command[Literal["my_other_node"]]:
    +    return Command(update={"foo": "bar"}, goto="my_other_node")
    +
    + A anotação de retorno Command[Literal[...]] é necessária para que + o LangGraph renderize e valide o grafo. Edges estáticos continuam executando + em paralelo com o roteamento dinâmico do Command. +
    +

    Command.PARENT — sair de um subgraph

    +
    def my_node(state: State) -> Command[Literal["my_other_node"]]:
    +    return Command(update={"foo": "bar"}, goto="other_subgraph", graph=Command.PARENT)
    +

    + O state key do pai deve ter um reducer para que o + update seja aceito. +

    +

    Resume após interrupt — única forma válida como input

    +
    result = graph.invoke(Command(resume="yes"), config, version="v2")
    +
    + +
    +

    12. Runtime e context

    +

    + context_schema declara o contexto imutável por chamada (ex.: + user_id, conexão de DB). O contexto é injetado em runtime via + Runtime[ContextT]. +

    +
    from dataclasses import dataclass
    +from langgraph.runtime import Runtime
    +
    +@dataclass
    +class ContextSchema:
    +    llm_provider: str = "openai"
    +
    +graph = StateGraph(State, context_schema=ContextSchema)
    +graph.invoke(inputs, context={"llm_provider": "anthropic"})
    +
    +def node_a(state: State, runtime: Runtime[ContextSchema]):
    +    llm = get_llm(runtime.context.llm_provider)
    +

    + config_schema está depreciado desde a v0.6.0 — use + context_schema. +

    +

    Acessar metadados do runtime

    +

    + runtime.execution_info expõe thread_id, + run_id, checkpoint_id, checkpoint_ns, + task_id, node_attempt, + node_first_attempt_time. Em LangGraph Server, + runtime.server_info traz assistant_id, + graph_id e user. +

    +
    + +
    +

    13. Subgraphs

    +

    Duas estratégias de comunicação

    +
    + + + + + + +
    PadrãoQuando usarComo
    Schemas diferentesNenhuma chave em comumFunção wrapper dentro de um nó chama subgraph.invoke({...}), traduz entrada/saída
    Schema compartilhadoPai e subgraph compartilham chavesPasse o subgraph compilado diretamente para add_node
    +
    +

    Matriz de capacidades por modo de compilação

    +
    + + + + + + + + + +
    FeaturePer-invocation
    checkpointer=None (default)
    Per-thread
    checkpointer=True
    Stateless
    checkpointer=False
    Interrupts (HITL)SimSimNão
    Multi-turn memoryNãoSimNão
    Múltiplos subgraphs diferentesSimLimitadoSim
    Múltiplas calls do mesmo subgraphSimNãoSim
    Inspeção de estadoApenas atualSimNão
    +
    +
    + Subgraphs per-thread não suportam chamadas paralelas (conflito de + namespace de checkpoint). Para múltiplos subagents do mesmo tipo, embrulhe + cada um em um StateGraph com nome único: +
    +
    def create_sub_agent(model, *, name, **kwargs):
    +    agent = create_agent(model=model, name=name, **kwargs)
    +    return (
    +        StateGraph(MessagesState)
    +        .add_node(name, agent)
    +        .add_edge("__start__", name)
    +        .compile()
    +    )
    +

    Streaming dentro de subgraphs

    +
    for chunk in graph.stream(
    +    {"foo": "foo"}, subgraphs=True, stream_mode="updates", version="v2"
    +):
    +    # chunk["ns"] == () para o grafo raiz;
    +    # chunk["ns"] == ("node_2:<uuid>",) para um subgraph
    +    print(chunk["ns"], chunk["data"])
    +
    + +
    +

    14. Recursion limit e RemainingSteps

    +

    + O limite padrão é 1000 supersteps (default desde a v1.0.6). + Ultrapassá-lo levanta GraphRecursionError. + recursion_limit é uma chave de topo em + config (não dentro de configurable): +

    +
    graph.invoke(inputs, config={"recursion_limit": 5}, context={"llm": "anthropic"})
    +

    Metadados do passo

    +
    from langchain_core.runnables import RunnableConfig
    +
    +def my_node(state: dict, config: RunnableConfig) -> dict:
    +    current_step = config["metadata"]["langgraph_step"]
    +    return state
    +

    + Campos disponíveis: langgraph_step, langgraph_node, + langgraph_triggers, langgraph_path, + langgraph_checkpoint_ns. +

    +

    Alternativa proativa — RemainingSteps

    +
    from langgraph.managed import RemainingSteps
    +from typing import Annotated, Literal
    +
    +class State(TypedDict):
    +    messages: Annotated[list, lambda x, y: x + y]
    +    remaining_steps: RemainingSteps
    +
    +def reasoning_node(state: State) -> dict:
    +    if state["remaining_steps"] <= 2:
    +        return {"messages": ["Approaching limit, wrapping up..."]}
    +    return {"messages": ["thinking..."]}
    +
    + + + + + + +
    AbordagemQuando detectaOnde tratarFluxo
    Proativa (RemainingSteps)Antes do limiteDentro do grafo, via roteamentoGrafo termina normalmente
    Reativa (GraphRecursionError)Depois do limiteFora do grafo, em try/exceptExecução abortada
    +
    +
    + +
    +

    15. Cache · Retry · Timeout · Error handlers

    +

    Caching de nó

    +
    import time
    +from langgraph.cache.memory import InMemoryCache
    +from langgraph.types import CachePolicy
    +
    +def expensive_node(state: State) -> dict[str, int]:
    +    time.sleep(2)
    +    return {"result": state["x"] * 2}
    +
    +builder.add_node("expensive_node", expensive_node, cache_policy=CachePolicy(ttl=3))
    +graph = builder.compile(cache=InMemoryCache())
    +

    + Parâmetros de CachePolicy: key_func (default: pickle + hash do input) e ttl (segundos; sem TTL = nunca expira). Hits + aparecem em streaming com '__metadata__': {'cached': True}. +

    +

    Retry policy

    +
    from langgraph.types import RetryPolicy
    +import sqlite3
    +
    +builder.add_node(
    +    "query_database",
    +    query_database,
    +    retry_policy=RetryPolicy(retry_on=sqlite3.OperationalError),
    +)
    +builder.add_node("model", call_model, retry_policy=RetryPolicy(max_attempts=5))
    +

    + O retry_on padrão exclui ValueError, + TypeError, ArithmeticError, + ImportError, LookupError, NameError, + SyntaxError, RuntimeError, + ReferenceError, StopIteration, + StopAsyncIteration, OSError. Para HTTP libs, só 5xx. +

    +

    Timeouts (langgraph >= 1.2)

    +
    from langgraph.types import TimeoutPolicy
    +
    +builder.add_node("call_model", call_model, timeout=1.0)
    +builder.add_node(
    +    "call_model_complex",
    +    call_model,
    +    timeout=TimeoutPolicy(run_timeout=120, idle_timeout=30),
    +)
    +

    + Exceder timeout levanta NodeTimeoutError (subclass de + TimeoutError). Apenas async. +

    +

    Error handlers

    +
    from langgraph.errors import NodeError
    +from langgraph.types import Command, RetryPolicy
    +
    +def payment_error_handler(state: State, error: NodeError) -> Command:
    +    return Command(
    +        update={"status": f"compensated: {error.error}"},
    +        goto="finalize",
    +    )
    +
    +builder.add_node(
    +    "charge_payment",
    +    charge_payment,
    +    retry_policy=RetryPolicy(max_attempts=3, retry_on=ConnectionError),
    +    error_handler=payment_error_handler,
    +)
    + +

    Defaults graph-wide com set_node_defaults()

    +

    + Em vez de repetir retry_policy/timeout/cache_policy/error_handler + em cada add_node(), aplique-os ao grafo inteiro com + builder.set_node_defaults(...): +

    +
    from langgraph.types import RetryPolicy, TimeoutPolicy
    +
    +builder.set_node_defaults(
    +    retry_policy=RetryPolicy(max_attempts=3),
    +    error_handler=default_error_handler,
    +    timeout=TimeoutPolicy(run_timeout=30),
    +)
    +
    + Precedência: valores passados diretamente em + add_node() sempre vencem os defaults de + set_node_defaults(). Os defaults resolvem em compile-time, + então a ordem das chamadas não importa. +
    +
    + O error_handler e o cache_policy default não + se aplicam aos próprios nós error-handler; já retry_policy e + timeout aplicam-se a ambos. +
    + +

    Idle timeout, refresh_on e heartbeat

    +

    + Além de run_timeout (limite total), o TimeoutPolicy + suporta idle_timeout (limite sem atividade). O campo + refresh_on controla o que reseta o relógio idle: +

    +
    from langgraph.types import TimeoutPolicy
    +
    +# "auto" (default): writes de estado, stream output, agendamento de child-task,
    +#   chamadas do stream-writer e qualquer callback LangChain resetam o relógio idle.
    +timeout = TimeoutPolicy(idle_timeout=30, refresh_on="heartbeat")
    +
    +# Dentro do nó — só "heartbeat" depende de chamada explícita:
    +def long_node(state, runtime):
    +    runtime.heartbeat()   # reseta o relógio idle; seguro chamar incondicionalmente
    +    ...
    +
    + + + + + + +
    refresh_onReseta o relógio idle quando…
    "auto" (default)Há writes de estado, stream output, agendamento de child-task, chamadas do stream-writer ou qualquer callback LangChain.
    "heartbeat"Apenas via runtime.heartbeat() explícito (no-op fora de um attempt idle-timed).
    +
    +

    + Estourar o limite levanta NodeTimeoutError (subclass de + TimeoutError), com os campos: node: str, + elapsed: float, kind: Literal["idle", "run"], + idle_timeout: float | None, run_timeout: float | None. +

    + +

    default_retry_on extensível

    +

    + Para construir um retry_on= que estende a lógica padrão (em vez de + substituí-la), importe e reutilize default_retry_on dentro do seu + callable: +

    +
    from langgraph.types import RetryPolicy, default_retry_on
    +
    +def retry_on(exc: Exception) -> bool:
    +    # mantém o comportamento default e adiciona um caso próprio
    +    return default_retry_on(exc) or isinstance(exc, MyTransientError)
    +
    +builder.add_node("call_api", call_api, retry_policy=RetryPolicy(retry_on=retry_on))
    + +
    + +
    +

    16. Visualização

    +
    from IPython.display import Image, display
    +
    +# PNG via Mermaid.Ink (default)
    +display(Image(graph.get_graph().draw_mermaid_png()))
    +
    +# Mermaid syntax (texto)
    +print(app.get_graph().draw_mermaid())
    +
    +# Customizado via Pyppeteer
    +from langchain_core.runnables.graph import CurveStyle, MermaidDrawMethod, NodeStyles
    +
    +display(Image(app.get_graph().draw_mermaid_png(
    +    curve_style=CurveStyle.LINEAR,
    +    node_colors=NodeStyles(first="#ffdfba", last="#baffc9", default="#fad7de"),
    +    wrap_label_n_words=9,
    +    output_file_path=None,
    +    draw_method=MermaidDrawMethod.PYPPETEER,
    +    background_color="white",
    +    padding=10,
    +)))
    +
    +# Graphviz
    +display(Image(app.get_graph().draw_png()))
    +

    + ASCII também está disponível via graph.get_graph().draw_ascii(). +

    +
    + +
    +

    17. Streaming

    +

    + O LangGraph oferece graph.stream(input, stream_mode=..., version="v2", + subgraphs=False, config=None) e .astream(...). No + v2, todo chunk tem o shape: +

    +
    StreamPart = {"type": str, "ns": tuple, "data": Any}
    +

    Modos disponíveis

    +
    + + + + + + + + + + + +
    ModoEmitePayload (chunk["data"])Requer checkpointer
    valuesSnapshot completo após cada stepdict (ou modelo tipado)Não
    updatesDelta retornado por nó{"node_name": {...}}Não
    messagesTokens de LLM(LLM_token_chunk, metadata)Não
    customDados emitidos via get_stream_writer ou writerQualquer JSONNão
    checkpointsEventos de checkpointShape de get_state()Sim
    tasksStart/finish/erro de tasksTask dictSim
    debugcheckpoints + tasks + extraComboSim
    +
    +

    Multi-mode

    +
    for chunk in graph.stream(inputs, stream_mode=["updates", "custom"], version="v2"):
    +    if chunk["type"] == "updates": ...
    +    elif chunk["type"] == "custom": ...
    +

    Emitir custom de dentro de um nó

    +
    from langgraph.config import get_stream_writer
    +
    +def node(state):
    +    writer = get_stream_writer()
    +    writer({"status": "thinking..."})
    +    return {"answer": "x"}
    +

    Injeção de StreamWriter (necessário em Python < 3.11 async)

    +
    from langgraph.types import StreamWriter
    +
    +async def generate_joke(state: State, writer: StreamWriter):
    +    writer({"custom_key": "..."})
    +

    Filtrar tokens por nó / tag

    +
      +
    • metadata["langgraph_node"] — qual nó emitiu.
    • +
    • metadata["tags"] — tags do modelo (via init_chat_model(..., tags=[...])).
    • +
    • Tag ["nostream"] em um modelo exclui seus tokens do modo messages.
    • +
    • init_chat_model(..., streaming=False) ou model.disable_streaming = True.
    • +
    +

    v1 vs v2 — diferenças de retorno

    +
    + + + + + + + +
    Itemv1 (default)v2 (>= 1.1)
    invoke() retornadictGraphOutput com .value, .interrupts
    Payload de interruptresult["__interrupt__"]result.interrupts (tuple)
    Eventos de subgraphtuplas (ns, data)StreamPart unificado
    +
    + +

    Event streaming (stream_events / version="v3") recomendado

    +
    + API recomendada para código novo. + graph.stream_events(...) / graph.astream_events(..., version="v3") + substitui o antigo astream_events(..., version="v2") com + projeções tipadas sobre o fluxo de eventos, em vez de um dict + cru por evento. +
    +
    + Não confunda esta version="v3" (específica de + stream_events/astream_events) com o version="v2" + de graph.invoke(...)/graph.stream(...), que continua + válido para GraphOutput, interrupts tipados e + resume_map (ver §19 e §18). +
    +

    + O objeto retornado expõe o stream cru e várias projeções tipadas + que você itera conforme a necessidade: +

    +
    # Streaming de mensagens (canônico)
    +stream = graph.stream_events(
    +    {"messages": [{"role": "user", "content": "What is 42 * 17?"}]},
    +    version="v3",
    +)
    +for message in stream.messages:
    +    for token in message.text:
    +        print(token, end="", flush=True)
    +
    +final_state = stream.output       # saída final (awaitable no modo async)
    +
    + + + + + + + + + + + + + +
    ProjeçãoEmite
    streamEventos crus (iterável base).
    stream.messagesMensagens/tokens do LLM (com .text, .node).
    stream.valuesSnapshots completos de estado após cada step.
    stream.outputSaída final do grafo (awaitable em async).
    stream.subgraphsEventos originados de subgraphs.
    stream.interruptsInterrupts emitidos durante o run.
    stream.interruptedbool — se o run pausou em um interrupt.
    stream.extensionsProjeções de transformers customizados (stream.extensions["<name>"]).
    stream.tool_callsTool calls (quando um ToolCallTransformer está registrado).
    +
    +

    Consumir múltiplas projeções em ordem de chegada

    +
    for name, item in stream.interleave("values", "messages", "subgraphs"):
    +    if name == "values":
    +        print(f"[state] keys={list(item)}")
    +    elif name == "messages":
    +        print(f"[llm] node={item.node}")
    +

    Transformers customizados (StreamTransformer)

    +

    + Transformers implementam o protocolo StreamTransformer com + init(), process(event), finalize() e + fail(err), e declaram os modos Pregel de que precisam via + required_stream_modes (tupla, ex.: ("custom",)). + Projeções customizadas aparecem em stream.extensions["<name>"]. +

    +
    from langgraph.stream import ProtocolEvent, StreamTransformer
    +
    +# StreamTransformer é o protocolo (init/process/finalize/fail) implementado
    +# por transformers customizados; subclasse-o ou implemente a mesma interface.
    +
    +class MyTransformer(StreamTransformer):
    +    required_stream_modes = ("custom",)
    +
    +    def init(self):
    +        ...
    +
    +    def process(self, event: ProtocolEvent) -> bool:  # retorne False só p/ suprimir o evento
    +        ...
    +
    +    def finalize(self):
    +        ...
    +
    +    def fail(self, err):
    +        ...
    +
    +# Registro em call-time…
    +stream = graph.stream_events(inputs, version="v3", transformers=[MyTransformer()])
    +
    +# …ou no compile:
    +graph = builder.compile(transformers=[MyTransformer()])
    + +
    + +
    +

    18. Persistência (checkpointers)

    +

    + Cada execução persistente é indexada por um thread_id passado em + {"configurable": {"thread_id": "<id>"}}. Mesmo + thread_id ⇒ retoma; novo ⇒ estado fresco. +

    +

    Catálogo de checkpointers

    +
    + + + + + + + + + + + +
    ClassePacoteUso
    InMemorySaver / MemorySaverlanggraph-checkpoint (bundled)Dev/test; tem variante async
    SqliteSaverlanggraph-checkpoint-sqliteLocal sync
    AsyncSqliteSaverlanggraph-checkpoint-sqliteLocal async
    PostgresSaverlanggraph-checkpoint-postgresProdução sync
    AsyncPostgresSaverlanggraph-checkpoint-postgresProdução async
    RedisSaver / AsyncRedisSaverlanggraph-checkpoint-redisProdução, opcional vector
    CosmosDBSaver(Sync)langchain-azure-cosmosdbAzure
    +
    +

    StateSnapshot — campos

    +
    + + + + + + + + + + + +
    CampoTipoSignificado
    valuesdictValores dos canais
    nexttuple[str, ...]Próximos nós; () = completo
    configdictTem thread_id, checkpoint_ns, checkpoint_id
    metadatadictsource (input/loop/update), writes, step
    created_atstrISO 8601
    parent_configdict\|NoneConfig do checkpoint anterior
    taskstuple[PregelTask, ...]id, name, error, interrupts, state
    +
    +

    Setup de produção com Postgres

    +
    from langgraph.checkpoint.postgres import PostgresSaver
    +from langgraph.store.postgres import PostgresStore
    +
    +DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"
    +
    +with (
    +    PostgresStore.from_conn_string(DB_URI) as store,
    +    PostgresSaver.from_conn_string(DB_URI) as checkpointer,
    +):
    +    checkpointer.setup()       # idempotente; cria tabelas/índices
    +    store.setup()
    +    graph = builder.compile(checkpointer=checkpointer, store=store)
    +    graph.invoke(inputs, {"configurable": {"thread_id": "1"}})
    +

    Async Postgres

    +
    from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
    +
    +DB_URI = "postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable"
    +async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
    +    await checkpointer.setup()
    +    graph = builder.compile(checkpointer=checkpointer)
    +    async for chunk in graph.astream(
    +        inputs, {"configurable": {"thread_id": "1"}}, stream_mode="values"
    +    ):
    +        chunk["messages"][-1].pretty_print()
    +

    Serialização e criptografia

    +

    + O serializador padrão é JsonPlusSerializer (ormsgpack + JSON). + Pickle fallback é opt-in: +

    +
    from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
    +
    +graph.compile(
    +    checkpointer=InMemorySaver(serde=JsonPlusSerializer(pickle_fallback=True))
    +)
    +

    Criptografia AES (lê LANGGRAPH_AES_KEY):

    +
    from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
    +from langgraph.checkpoint.postgres import PostgresSaver
    +
    +serde = EncryptedSerializer.from_pycryptodome_aes()
    +checkpointer = PostgresSaver.from_conn_string("postgresql://...", serde=serde)
    +checkpointer.setup()
    +

    Custom: implemente CipherProtocol em langgraph.checkpoint.serde.base.

    +

    Pending writes — recuperação parcial de super-step

    +

    + Quando vários nós executam no mesmo super-step e um deles falha, o + checkpointer guarda as writes intermediárias dos nós que já + concluíram (via .put_writes). No resume, esses nós + não reexecutam — apenas o que faltou roda de novo. Essas + writes aparecem como pending_writes no snapshot, permitindo + inspecionar o progresso parcial antes da retomada. +

    +
    snapshot = graph.get_state(config)
    +print(snapshot.tasks)            # tasks pendentes do super-step
    +# writes intermediárias persistidas ficam disponíveis como pending_writes
    +# e são reaplicadas no resume sem reexecutar os nós já concluídos.
    + +
    + +
    +

    19. Human-in-the-loop

    +

    + interrupt(value) (de langgraph.types) pausa a + execução, persiste o estado, surface o value ao chamador e + aguarda indefinidamente o Command(resume=...). Requer + checkpointer e thread_id. +

    +
    from langgraph.types import Command, interrupt
    +from langgraph.checkpoint.memory import InMemorySaver
    +

    Gotchas críticos

    +
      +
    1. Não envelope interrupt() em try/except Exception + — ele levanta uma exceção especial usada para pausar.
    2. +
    3. A reentrada é indexada por posição: nunca reordene ou + pule condicionalmente chamadas a interrupt() dentro de um nó.
    4. +
    5. Passe apenas valores JSON-serializáveis para interrupt() — + funções e instâncias de classes não.
    6. +
    7. Side effects antes de interrupt() reexecutam no resume — + torne-os idempotentes (upserts, não inserts).
    8. +
    9. Subgraphs chamados como funções: o nó pai e o nó do subgraph reiniciam + do começo no resume.
    10. +
    +

    Receita 1 — aprovar antes de chamar

    +
    from typing import Literal, Optional, TypedDict
    +from langgraph.checkpoint.memory import InMemorySaver
    +from langgraph.graph import END, START, StateGraph
    +from langgraph.types import Command, interrupt
    +
    +class ApprovalState(TypedDict):
    +    action_details: str
    +    status: Optional[Literal["pending", "approved", "rejected"]]
    +
    +def approval_node(state: ApprovalState) -> Command[Literal["proceed", "cancel"]]:
    +    decision = interrupt({"question": "Approve this action?", "details": state["action_details"]})
    +    return Command(goto="proceed" if decision else "cancel")
    +
    +def proceed_node(state): return {"status": "approved"}
    +def cancel_node(state):  return {"status": "rejected"}
    +
    +builder = StateGraph(ApprovalState)
    +builder.add_node("approval", approval_node)
    +builder.add_node("proceed", proceed_node)
    +builder.add_node("cancel", cancel_node)
    +builder.add_edge(START, "approval")
    +builder.add_edge("proceed", END)
    +builder.add_edge("cancel", END)
    +graph = builder.compile(checkpointer=InMemorySaver())
    +
    +config = {"configurable": {"thread_id": "approval-123"}}
    +initial = graph.invoke({"action_details": "Transfer $500", "status": "pending"},
    +                       config=config, version="v2")
    +print(initial.interrupts)
    +resumed = graph.invoke(Command(resume=True), config=config, version="v2")
    +print(resumed.value["status"])
    +

    Receita 2 — editar estado

    +
    def review_node(state):
    +    edited = interrupt({"instruction": "Review and edit", "content": state["generated_text"]})
    +    return {"generated_text": edited}
    +
    +graph.invoke(Command(resume="Improved draft"), config=config, version="v2")
    +

    Receita 3 — revisar tool call

    +
    from langchain.tools import tool
    +from langgraph.types import interrupt
    +
    +@tool
    +def send_email(to: str, subject: str, body: str):
    +    """Send an email to a recipient."""
    +    response = interrupt({
    +        "action": "send_email", "to": to, "subject": subject, "body": body,
    +        "message": "Approve sending this email?",
    +    })
    +    if response.get("action") == "approve":
    +        return f"Email sent to {response.get('to', to)} subj '{response.get('subject', subject)}'"
    +    return "Email cancelled by user"
    +
    +graph.invoke(
    +    Command(resume={"action": "approve", "subject": "Updated"}),
    +    config=config, version="v2"
    +)
    +

    Receita 4 — validar input humano (loop)

    +
    def get_age_node(state):
    +    prompt = "What is your age?"
    +    while True:
    +        answer = interrupt(prompt)
    +        if isinstance(answer, int) and answer > 0:
    +            return {"age": answer}
    +        prompt = f"'{answer}' is not a valid age. Please enter a positive number."
    +

    Static interrupts (apenas debug)

    +
    graph = builder.compile(interrupt_before=["node_a"], interrupt_after=["node_b"],
    +                        checkpointer=cp)
    +# ou em runtime
    +graph.invoke(inputs, interrupt_before=["node_a"], interrupt_after=["node_b"], config=cfg)
    +graph.invoke(None, config=cfg)  # resume até o próximo breakpoint
    +

    Resumir múltiplos interrupts paralelos com resume_map

    +

    + Quando vários nós em paralelo (ex.: fan-out via Send) chamam + interrupt() no mesmo super-step, o resume precisa endereçar cada um + pelo seu id. Em vez de um único Command(resume=valor), + passe um mapa {interrupt_id: valor}. Isto exige o + fluxo tipado de version="v2" (ver §17 e §18): +

    +
    from langgraph.types import Command
    +
    +interrupted = graph.invoke({"vals": []}, config, version="v2")
    +resume_map = {i.id: f"answer for {i.value}" for i in interrupted.interrupts}
    +result = graph.invoke(Command(resume=resume_map), config, version="v2")
    + +
    + +
    +

    20. Memória curta e longa (Store)

    +

    + Curta (short-term) = escopo de thread, persistida pelo + checkpointer (histórico de conversa, arquivos enviados, docs recuperados, + artefatos gerados). Longa (long-term) = cross-thread, com + escopo de namespace, acessada via BaseStore. +

    +

    Taxonomia de memória

    +
    + + + + + + + +
    TipoArmazenaPadrão
    SemânticaFatosProfile (1 JSON único, regenerado) ou Collection (muitos docs estreitos)
    EpisódicaExperiências passadasFew-shot examples no Store ou em LangSmith Dataset
    ProceduralRegras/instruçõesSystem prompt versionado persistido no Store
    +
    +

    CRUD do Store

    +
    from langgraph.store.memory import InMemoryStore
    +from langgraph.store.postgres import PostgresStore
    +
    +store = InMemoryStore()
    +store.put(namespace, key, value)
    +store.get(namespace, key)            # retorna Item ou None
    +store.search(namespace, filter=..., query=..., limit=..., offset=...)
    +store.delete(namespace, key)
    +store.list_namespaces(prefix=..., max_depth=...)
    +
    + Ordenação: PostgresStore / + AsyncPostgresStore ordenam por updated_at desc; + InMemoryStore respeita a ordem de inserção. Ordene no cliente + quando precisar de garantia. +
    +

    Busca semântica

    +
    from langchain.embeddings import init_embeddings
    +from langgraph.store.memory import InMemoryStore
    +
    +store = InMemoryStore(index={
    +    "embed": init_embeddings("openai:text-embedding-3-small"),
    +    "dims": 1536,
    +    "fields": ["food_preference", "$"],  # "$" = doc inteiro
    +})
    +store.put(ns, key,  {"food_preference": "I love Italian"}, index=["food_preference"])
    +store.put(ns, key2, {"system_info": "..."},                index=False)
    +memories = store.search(ns, query="What does the user like?", limit=3)
    +

    Acessar Store de dentro de um nó

    +
    from langgraph.runtime import Runtime
    +from dataclasses import dataclass
    +import uuid
    +
    +@dataclass
    +class Context:
    +    user_id: str
    +
    +async def update_memory(state, runtime: Runtime[Context]):
    +    namespace = (runtime.context.user_id, "memories")
    +    await runtime.store.aput(
    +        namespace, str(uuid.uuid4()),
    +        {"memory": "User prefers concise replies"}
    +    )
    +

    Stores de produção

    +

    + Além do PostgresStore / AsyncPostgresStore, há backends + de produção mantidos para MongoDB e Redis. Todos estendem BaseStore; + o InMemoryStore serve apenas para dev/teste. +

    +
    + + + + + + + + +
    StoreImportUso
    PostgresStore / AsyncPostgresStorefrom langgraph.store.postgres import PostgresStoreProdução; ordena search por updated_at desc.
    MongoDBStorefrom langgraph.store.mongodb import MongoDBStoreProdução sobre MongoDB.
    RedisStore / AsyncRedisStorefrom langgraph.store.redis import RedisStoreProdução sobre Redis (RedisStack para vetor).
    InMemoryStorefrom langgraph.store.memory import InMemoryStoreApenas dev/teste.
    +
    +
    + +
    +

    21. Time travel — replay e fork

    +
    + + + + + + + +
    APIO que faz
    graph.get_state(config, subgraphs=False)Último StateSnapshot (ou específico via checkpoint_id no config)
    graph.get_state_history(config)Iterador reverso de StateSnapshot
    graph.update_state(config, values, as_node=None)Cria um novo checkpoint partindo de config
    +
    +

    Replay

    +
    history = list(graph.get_state_history(config))
    +before_joke = next(s for s in history if s.next == ("write_joke",))
    +replay_result = graph.invoke(None, before_joke.config)
    +

    + No replay, apenas nós após o checkpoint reexecutam. Chamadas a LLM, + APIs e interrupt() disparam de novo. +

    +

    Fork

    +
    fork_config = graph.update_state(
    +    before_joke.config,
    +    values={"topic": "chickens"},
    +    as_node="generate_topic",
    +)
    +fork_result = graph.invoke(None, fork_config)
    +

    + as_node é explícito quando: há ramos paralelos, em thread sem + histórico, ou quando você quer que o grafo "ache" que um nó posterior já + rodou. +

    +

    Subgraphs e time travel

    +
      +
    • Default (checkpointer herdado): subgraph é um único super-step do ponto + de vista do pai; não dá pra viajar entre nós internos.
    • +
    • compile(checkpointer=True) no subgraph: checkpoints por step + internamente; acesso via + graph.get_state(config, subgraphs=True).tasks[0].state.config.
    • +
    +
    + +
    +

    22. Durable execution & drain

    +

    + Durable execution requer: (a) checkpointer, (b) thread_id, (c) + side effects envolvidos em @task. Modos: +

    +
    + + + + + + + +
    Modo (durability=)PersisteTrade-off
    "exit"Apenas no exit (sucesso, erro, interrupt)Melhor performance; sem recovery no meio
    "async"Assíncrono enquanto o próximo step rodaBalanceado; pequena janela de risco
    "sync"Síncrono antes do próximo step começarMáxima durabilidade; overhead
    +
    +

    Onde o resume começa

    +
    + + + + + + + +
    APIResume retoma em
    Nó de StateGraphInício do nó onde parou
    Subgraph chamado dentro de um nóInício do nó pai + início do nó do subgraph
    Functional APIInício do entrypoint (resultados de @task são recarregados, não reexecutados)
    +
    +

    Graceful shutdown (langgraph >= 1.2)

    +
    import signal
    +from langgraph.runtime import RunControl
    +from langgraph.errors import GraphDrained
    +
    +control = RunControl()
    +signal.signal(signal.SIGTERM, lambda *_: control.request_drain("sigterm"))
    +
    +try:
    +    result = graph.invoke(inputs, config, control=control)
    +except GraphDrained as e:
    +    log.info("drained: %s", e.reason)
    +
    +# Reiniciar em outro processo:
    +result = graph.invoke(None, config)
    +

    Dentro de um nó:

    +
    from langgraph.runtime import Runtime
    +
    +async def my_node(state, runtime: Runtime):
    +    if runtime.drain_requested:
    +        return {"status": "skipped", "reason": runtime.drain_reason}
    +    return {"status": await do_work()}
    +

    + request_drain() não cancela tasks assíncronas nem mata threads — + deixa o nó atual terminar; políticas de retry rodam até esgotar; se há mais + supersteps, levanta GraphDrained e o checkpoint é salvo. +

    +
    + +
    +

    23. Functional API

    +
    from langgraph.func import entrypoint, task
    +

    + @entrypoint(checkpointer=..., store=...) decora uma função com + UM argumento posicional (use um dict para vários). Retorna um + Pregel com .invoke/.ainvoke/ + .stream/.astream. Inputs e outputs devem ser + JSON-serializáveis. +

    +

    Parâmetros injetáveis (por nome+tipo)

    +
    + + + + + + + + +
    NomeTipoPropósito
    previousAnyValor de retorno do checkpoint anterior (ou entrypoint.final.save)
    storeBaseStoreStore de longo prazo
    writerStreamWriterStreaming custom (necessário em Python < 3.11 async)
    configRunnableConfigConfig de runtime
    +
    +

    Memória curta via previous

    +
    @entrypoint(checkpointer=cp)
    +def workflow(number: int, *, previous=None) -> int:
    +    previous = previous or 0
    +    return number + previous
    +

    entrypoint.final — desacoplar retorno do que persiste

    +
    @entrypoint(checkpointer=cp)
    +def workflow(number, *, previous=None) -> entrypoint.final[int, int]:
    +    previous = previous or 0
    +    return entrypoint.final(value=previous, save=2 * number)
    +

    @task — unidade de trabalho com checkpoint

    +
    from typing import NotRequired
    +from typing_extensions import TypedDict
    +from langchain_core.utils.uuid import uuid7
    +from langgraph.checkpoint.memory import InMemorySaver
    +from langgraph.func import task
    +from langgraph.graph import StateGraph, START, END
    +import requests
    +
    +class State(TypedDict):
    +    urls: list[str]
    +    result: NotRequired[list[str]]
    +
    +@task
    +def _make_request(url: str):
    +    return requests.get(url).text[:100]
    +
    +def call_api(state: State):
    +    futures = [_make_request(url) for url in state['urls']]
    +    results = [f.result() for f in futures]
    +    return {"results": results}
    +
    +builder = StateGraph(State)
    +builder.add_node("call_api", call_api)
    +builder.add_edge(START, "call_api")
    +builder.add_edge("call_api", END)
    +
    +checkpointer = InMemorySaver()
    +graph = builder.compile(checkpointer=checkpointer)
    +
    +thread_id = str(uuid7())
    +config = {"configurable": {"thread_id": thread_id}}
    +graph.invoke({"urls": ["https://www.example.com"]}, config)
    +

    + @task só pode ser chamada de dentro de + @entrypoint, de outra @task, ou de um nó de grafo. + Outputs precisam ser JSON-serializáveis. No resume, o resultado persistido é + recarregado — não recomputado. +

    +
    + +
    +

    24. Multi-agent (supervisor & swarm)

    +

    + LangGraph oferece dois pacotes prebuilt — langgraph-supervisor e + langgraph-swarm — além do primitivo + Command(goto=..., graph=Command.PARENT, update=...) que viabiliza + qualquer padrão custom. +

    +

    Padrões

    +
    + + + + + + + + + +
    PadrãoResumo
    SupervisorLLM central roteia para subagents especializados via tool calls
    SwarmPeer-to-peer; agents transferem controle entre si; sistema lembra o último active agent
    NetworkComunicação many-to-many
    HierarchicalSupervisores aninhados (multi-team)
    Custom workflowStateGraph manual com handoffs via Command
    +
    +

    Handoff tool via Command (padrão canônico)

    +
    from typing import Annotated
    +from langchain_core.tools import tool, InjectedToolCallId
    +from langchain_core.messages import ToolMessage
    +from langgraph.types import Command
    +from langgraph.prebuilt import InjectedState
    +
    +@tool("transfer_to_bob", description="Hand off to Bob")
    +def transfer_to_bob(
    +    task_description: Annotated[str, "What Bob should do"],
    +    state: Annotated[dict, InjectedState],
    +    tool_call_id: Annotated[str, InjectedToolCallId],
    +):
    +    msg = ToolMessage(content="Transferred to Bob", name="transfer_to_bob",
    +                      tool_call_id=tool_call_id)
    +    return Command(
    +        goto="Bob",
    +        graph=Command.PARENT,
    +        update={"messages": state["messages"] + [msg], "active_agent": "Bob"},
    +    )
    +

    Supervisor

    +
    pip install langgraph-supervisor
    +
    from langchain_openai import ChatOpenAI
    +from langgraph_supervisor import create_supervisor, create_handoff_tool
    +from langgraph.prebuilt import create_react_agent
    +from langgraph.checkpoint.memory import InMemorySaver
    +
    +model = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    +
    +def add(a: float, b: float) -> float: return a + b
    +def web_search(q: str) -> str: return "..."
    +
    +math_agent = create_react_agent(model=model, tools=[add],
    +                                name="math_expert", prompt="You are a math expert.")
    +research_agent = create_react_agent(model=model, tools=[web_search],
    +                                    name="research_expert",
    +                                    prompt="You are a world-class researcher.")
    +
    +workflow = create_supervisor(
    +    [research_agent, math_agent],
    +    model=model,
    +    prompt="You are a team supervisor managing a research expert and a math expert.",
    +    tools=[
    +        create_handoff_tool(agent_name="math_expert",
    +                            name="assign_to_math_expert",
    +                            description="Assign task to math expert"),
    +        create_handoff_tool(agent_name="research_expert",
    +                            name="assign_to_research_expert",
    +                            description="Assign task to research expert"),
    +    ],
    +    output_mode="last_message",
    +)
    +
    +app = workflow.compile(checkpointer=InMemorySaver())
    +result = app.invoke({"messages": [{"role": "user", "content": "..."}]},
    +                    config={"configurable": {"thread_id": "1"}})
    +

    + output_mode: + "full_history" (anexa todas as mensagens do subagent) ou + "last_message" (anexa apenas a resposta final). + Helpers extras: create_forward_message_tool, + METADATA_KEY_HANDOFF_DESTINATION em + langgraph_supervisor.handoff. +

    +

    Swarm

    +
    pip install langgraph-swarm
    +
    from langchain_openai import ChatOpenAI
    +from langgraph.checkpoint.memory import InMemorySaver
    +from langgraph_swarm import create_handoff_tool, create_swarm
    +from langgraph.prebuilt import create_react_agent
    +
    +model = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    +def add(a: int, b: int) -> int: return a + b
    +
    +alice = create_react_agent(
    +    model,
    +    tools=[add, create_handoff_tool(agent_name="Bob", description="Transfer to Bob")],
    +    prompt="You are Alice, an addition expert.",
    +    name="Alice",
    +)
    +bob = create_react_agent(
    +    model,
    +    tools=[create_handoff_tool(agent_name="Alice", description="Transfer to Alice for math")],
    +    prompt="You are Bob, you speak like a pirate.",
    +    name="Bob",
    +)
    +
    +workflow = create_swarm([alice, bob], default_active_agent="Alice")
    +app = workflow.compile(checkpointer=InMemorySaver())
    +
    +config = {"configurable": {"thread_id": "1"}}
    +app.invoke({"messages": [{"role": "user", "content": "I want to talk to Bob"}]}, config)
    +app.invoke({"messages": [{"role": "user", "content": "What's 2+2?"}]}, config)
    +# Bob devolve para Alice via handoff tool
    +
    + Sem checkpointer, o swarm esquece o agent ativo entre invocações — sempre + passe checkpointer= no compile(). +
    +
    + +
    +

    25. Padrões de workflow

    +

    + A página workflows-agents documenta seis arquiteturas canônicas + construídas em LangGraph puro. +

    +

    1. Prompt chaining

    +
    from typing_extensions import TypedDict
    +from langgraph.graph import StateGraph, START, END
    +
    +class State(TypedDict):
    +    topic: str
    +    joke: str
    +    improved_joke: str
    +    final_joke: str
    +
    +def generate_joke(state: State):
    +    msg = llm.invoke(f"Write a short joke about {state['topic']}")
    +    return {"joke": msg.content}
    +
    +def check_punchline(state: State):
    +    return "Pass" if "?" in state["joke"] or "!" in state["joke"] else "Fail"
    +
    +def improve_joke(state: State):
    +    msg = llm.invoke(f"Make this joke funnier by adding wordplay: {state['joke']}")
    +    return {"improved_joke": msg.content}
    +
    +def polish_joke(state: State):
    +    msg = llm.invoke(f"Add a surprising twist to this joke: {state['improved_joke']}")
    +    return {"final_joke": msg.content}
    +
    +workflow = StateGraph(State)
    +workflow.add_node("generate_joke", generate_joke)
    +workflow.add_node("improve_joke", improve_joke)
    +workflow.add_node("polish_joke", polish_joke)
    +workflow.add_edge(START, "generate_joke")
    +workflow.add_conditional_edges("generate_joke", check_punchline,
    +                               {"Fail": "improve_joke", "Pass": END})
    +workflow.add_edge("improve_joke", "polish_joke")
    +workflow.add_edge("polish_joke", END)
    +chain = workflow.compile()
    +state = chain.invoke({"topic": "cats"})
    +

    2. Parallelization

    +
    parallel_builder = StateGraph(State)
    +parallel_builder.add_node("call_llm_1", call_llm_1)
    +parallel_builder.add_node("call_llm_2", call_llm_2)
    +parallel_builder.add_node("call_llm_3", call_llm_3)
    +parallel_builder.add_node("aggregator", aggregator)
    +parallel_builder.add_edge(START, "call_llm_1")
    +parallel_builder.add_edge(START, "call_llm_2")
    +parallel_builder.add_edge(START, "call_llm_3")
    +parallel_builder.add_edge("call_llm_1", "aggregator")
    +parallel_builder.add_edge("call_llm_2", "aggregator")
    +parallel_builder.add_edge("call_llm_3", "aggregator")
    +parallel_builder.add_edge("aggregator", END)
    +

    3. Routing (com structured output)

    +
    from typing_extensions import Literal
    +from langchain.messages import HumanMessage, SystemMessage
    +from pydantic import BaseModel, Field
    +
    +class Route(BaseModel):
    +    step: Literal["poem", "story", "joke"] = Field(None,
    +        description="The next step in the routing process")
    +
    +router = llm.with_structured_output(Route)
    +
    +def llm_call_router(state: State):
    +    decision = router.invoke([
    +        SystemMessage(content="Route the input to story, joke, or poem based on the user's request."),
    +        HumanMessage(content=state["input"]),
    +    ])
    +    return {"decision": decision.step}
    +
    +def route_decision(state: State):
    +    return {"story": "llm_call_1", "joke": "llm_call_2", "poem": "llm_call_3"}[state["decision"]]
    +
    +router_builder = StateGraph(State)
    +router_builder.add_node("llm_call_1", llm_call_1)
    +router_builder.add_node("llm_call_2", llm_call_2)
    +router_builder.add_node("llm_call_3", llm_call_3)
    +router_builder.add_node("llm_call_router", llm_call_router)
    +router_builder.add_edge(START, "llm_call_router")
    +router_builder.add_conditional_edges("llm_call_router", route_decision,
    +    {"llm_call_1": "llm_call_1", "llm_call_2": "llm_call_2", "llm_call_3": "llm_call_3"})
    +router_builder.add_edge("llm_call_1", END)
    +router_builder.add_edge("llm_call_2", END)
    +router_builder.add_edge("llm_call_3", END)
    +

    4. Orchestrator-worker (Send)

    +
    from typing import Annotated, List
    +import operator
    +from langgraph.types import Send
    +
    +class Section(BaseModel):
    +    name: str = Field(description="Name for this section of the report.")
    +    description: str = Field(description="Brief overview of the section.")
    +
    +class Sections(BaseModel):
    +    sections: List[Section] = Field(description="Sections of the report.")
    +
    +planner = llm.with_structured_output(Sections)
    +
    +class State(TypedDict):
    +    topic: str
    +    sections: list[Section]
    +    completed_sections: Annotated[list, operator.add]
    +    final_report: str
    +
    +class WorkerState(TypedDict):
    +    section: Section
    +    completed_sections: Annotated[list, operator.add]
    +
    +def orchestrator(state: State):
    +    report_sections = planner.invoke([
    +        SystemMessage(content="Generate a plan for the report."),
    +        HumanMessage(content=f"Here is the report topic: {state['topic']}"),
    +    ])
    +    return {"sections": report_sections.sections}
    +
    +def llm_call(state: WorkerState):
    +    section = llm.invoke([
    +        SystemMessage(content="Write a report section..."),
    +        HumanMessage(content=f"name: {state['section'].name}, description: {state['section'].description}"),
    +    ])
    +    return {"completed_sections": [section.content]}
    +
    +def synthesizer(state: State):
    +    return {"final_report": "\n\n---\n\n".join(state["completed_sections"])}
    +
    +def assign_workers(state: State):
    +    return [Send("llm_call", {"section": s}) for s in state["sections"]]
    +
    +builder = StateGraph(State)
    +builder.add_node("orchestrator", orchestrator)
    +builder.add_node("llm_call", llm_call)
    +builder.add_node("synthesizer", synthesizer)
    +builder.add_edge(START, "orchestrator")
    +builder.add_conditional_edges("orchestrator", assign_workers, ["llm_call"])
    +builder.add_edge("llm_call", "synthesizer")
    +builder.add_edge("synthesizer", END)
    +orchestrator_worker = builder.compile()
    +

    5. Evaluator-optimizer (loop com feedback)

    +
    class Feedback(BaseModel):
    +    grade: Literal["funny", "not funny"] = Field(description="Decide if the joke is funny.")
    +    feedback: str = Field(description="Feedback on how to improve.")
    +
    +evaluator = llm.with_structured_output(Feedback)
    +
    +def llm_call_generator(state: State):
    +    if state.get("feedback"):
    +        msg = llm.invoke(f"Write a joke about {state['topic']} considering feedback: {state['feedback']}")
    +    else:
    +        msg = llm.invoke(f"Write a joke about {state['topic']}")
    +    return {"joke": msg.content}
    +
    +def llm_call_evaluator(state: State):
    +    grade = evaluator.invoke(f"Grade the joke {state['joke']}")
    +    return {"funny_or_not": grade.grade, "feedback": grade.feedback}
    +
    +def route_joke(state: State):
    +    return "Accepted" if state["funny_or_not"] == "funny" else "Rejected + Feedback"
    +
    +builder = StateGraph(State)
    +builder.add_node("llm_call_generator", llm_call_generator)
    +builder.add_node("llm_call_evaluator", llm_call_evaluator)
    +builder.add_edge(START, "llm_call_generator")
    +builder.add_edge("llm_call_generator", "llm_call_evaluator")
    +builder.add_conditional_edges("llm_call_evaluator", route_joke,
    +    {"Accepted": END, "Rejected + Feedback": "llm_call_generator"})
    +optimizer_workflow = builder.compile()
    +

    6. Agente ReAct manual

    +
    from langgraph.graph import MessagesState
    +from langchain.messages import SystemMessage, HumanMessage, ToolMessage
    +
    +def llm_call(state: MessagesState):
    +    return {"messages": [llm_with_tools.invoke(
    +        [SystemMessage(content="You are a helpful assistant for arithmetic.")]
    +        + state["messages"]
    +    )]}
    +
    +def tool_node(state: dict):
    +    result = []
    +    for tool_call in state["messages"][-1].tool_calls:
    +        tool = tools_by_name[tool_call["name"]]
    +        observation = tool.invoke(tool_call["args"])
    +        result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
    +    return {"messages": result}
    +
    +def should_continue(state: MessagesState) -> Literal["tool_node", END]:
    +    last_message = state["messages"][-1]
    +    return "tool_node" if last_message.tool_calls else END
    +
    +agent_builder = StateGraph(MessagesState)
    +agent_builder.add_node("llm_call", llm_call)
    +agent_builder.add_node("tool_node", tool_node)
    +agent_builder.add_edge(START, "llm_call")
    +agent_builder.add_conditional_edges("llm_call", should_continue, ["tool_node", END])
    +agent_builder.add_edge("tool_node", "llm_call")
    +agent = agent_builder.compile()
    + +
    + +
    +

    26. Migrações de grafo (com checkpointer)

    +
    + + + + + + + + + + +
    CenárioSuportado
    Threads no fim do grafo — mudanças totais de topologiaSim
    Threads interrompidas — adicionar/modificar nósSim
    Threads interrompidas — renomear/remover nósContate o time
    Adicionar/remover chaves de estadoSim (forwards/backwards compat)
    Renomear chavesNão (perde estado salvo)
    Mudanças incompatíveis de tipoPode causar problemas
    +
    + +

    Deprecations do LangGraph v1

    +

    + O LangGraph v1 deprecou os prebuilts agênticos em favor de + langchain.agents. Os símbolos abaixo continuam funcionando (com + aviso @deprecated), mas código novo deve usar as alternativas: +

    +
    + + + + + + + + + + + + + +
    DeprecadoAlternativa
    create_react_agent (langgraph.prebuilt)from langchain.agents import create_agent — use system_prompt=, não prompt=
    MessageGraphStateGraph com a chave messages (como create_agent provê)
    ValidationNodeRemovido — tools validam o input automaticamente com create_agent
    AgentStatelangchain.agents.AgentState
    AgentStatePydanticlangchain.agents.AgentState (sem estado Pydantic)
    AgentStateWithStructuredResponselangchain.agents.AgentState
    HumanInterruptlangchain.agents.middleware.human_in_the_loop.HITLRequest
    HumanInterruptConfiglangchain.agents.middleware.human_in_the_loop.InterruptOnConfig
    ActionRequestlangchain.agents.middleware.human_in_the_loop.InterruptOnConfig
    +
    +
    # v1 (novo)
    +from langchain.agents import create_agent
    +agent = create_agent(model, tools, system_prompt="You are a helpful assistant.")
    +
    +# v0 (antigo, deprecado)
    +from langgraph.prebuilt import create_react_agent
    +agent = create_react_agent(model, tools, prompt="You are a helpful assistant.")
    +
    + Breaking change: o suporte a Python 3.9 foi removido — todos os + pacotes LangChain agora exigem Python 3.10+ (Python 3.9 chegou + ao fim de vida em out/2025). +
    +
    + create_supervisor / create_swarm vêm dos pacotes + separados langgraph-supervisor / + langgraph-swarm e ainda podem usar create_react_agent + internamente. Verifique a versão do pacote antes de trocar cegamente — a + deprecação v1 acima é especificamente sobre + langgraph.prebuilt.create_react_agent. +
    + +
    + +
    +

    Parte B — Referência de API

    +

    Referência das classes públicas relevantes do LangGraph e dos pacotes prebuilt. Cada entrada inclui import, assinatura e atributos principais.

    +
    + +
    +

    StateGraph

    +
    from langgraph.graph import StateGraph
    +
    +StateGraph(
    +    state_schema: type[StateT],
    +    context_schema: type[ContextT] | None = None,
    +    *,
    +    input_schema: type[InputT] | None = None,
    +    output_schema: type[OutputT] | None = None,
    +)
    +
    + + + + + + + + +
    ParâmetroTipoDefaultDescrição
    state_schematype[StateT]obrigatórioSchema do estado (TypedDict/dataclass/Pydantic)
    context_schematype[ContextT] \| NoneNoneSchema de runtime context (substitui o depreciado config_schema)
    input_schematype[InputT] \| NoneNoneSchema de entrada
    output_schematype[OutputT] \| NoneNoneSchema de saída
    +
    +

    Métodos principais

    +
    add_node(node, name=None, *, retry_policy=None, cache_policy=None, timeout=None, defer=False, error_handler=None, metadata=None) +
    +

    Registra um nó. Sem name, usa o nome da função. retry_policy, cache_policy, timeout, defer e error_handler são opcionais e independentes.

    +
    +
    add_edge(start_key, end_key) +

    Edge estático.

    +
    add_conditional_edges(source, path, path_map=None) +

    Roteamento dinâmico. path é uma função que recebe o estado e devolve um nome de nó, lista, ou lista de Send; path_map traduz retornos para nomes.

    +
    add_sequence(nodes) >= 0.2.46 +

    Atalho que registra os nós e conecta sequencialmente.

    +
    set_entry_point(node) · set_finish_point(node) · set_conditional_entry_point(path, path_map=None) +

    Açúcar para add_edge(START, node) / add_edge(node, END).

    +
    compile(checkpointer=None, store=None, cache=None, interrupt_before=None, interrupt_after=None, debug=False, name=None) +
    +

    Retorna um CompiledStateGraph com invoke, ainvoke, stream, astream, get_state, get_state_history, update_state, get_graph.

    +

    checkpointer=None usa o do pai (em subgraph) ou nenhum; checkpointer=True habilita per-thread state em subgraph; checkpointer=False torna o subgraph stateless.

    +
    +
    + +
    +

    START · END

    +
    from langgraph.graph import START, END
    +

    Sentinelas usados em add_edge(START, "node") e add_edge("node", END) ou em maps de edges condicionais.

    +
    + +
    +

    MessagesState

    +
    from langgraph.graph import MessagesState
    +
    +class MessagesState(TypedDict):
    +    messages: Annotated[list[AnyMessage], add_messages]
    +

    Extenda subclassando — campos extras coexistem com messages.

    +
    + +
    +

    add_messages

    +
    from langgraph.graph.message import add_messages
    +
    +add_messages(
    +    left: Messages,
    +    right: Messages,
    +    *,
    +    format: Literal['langchain-openai'] | None = None,
    +) -> Messages
    +

    Reducer canônico para listas de mensagens: append-only com overwrite por id. format="langchain-openai" reescreve content em blocos text/image_url (requer langchain-core >= 0.3.11).

    +
    + +
    +

    Send

    +
    from langgraph.types import Send
    +
    +Send(node: str, arg: Any, *, timeout: float | timedelta | TimeoutPolicy | None = None)
    +

    Retornada (em lista) por uma função de edge condicional para fan-out paralelo com estado distinto por destino.

    +
    + +
    +

    Command

    +
    from langgraph.types import Command
    +
    +Command(
    +    *,
    +    graph: str | None = None,
    +    update: Any | None = None,
    +    resume: dict | Any | None = None,
    +    goto: Send | Sequence[Send | str] | str = (),
    +)
    +
    + + + + + + + + +
    ParamTipoDefaultDescrição
    graphstr \| NoneNoneGrafo alvo; None = atual, Command.PARENT = pai mais próximo
    updateAny \| NoneNoneAtualização de estado
    resumedict \| Any \| NoneNoneValor para retomar após interrupt()
    gotostr \| Send \| Sequence()Próximo(s) nó(s)
    +
    +

    Constante: Command.PARENT — referência para o grafo pai imediato.

    +
    + +
    +

    Overwrite

    +
    from langgraph.types import Overwrite
    +
    +Overwrite(value: Any)
    +

    Bypassa o reducer e escreve o valor literalmente. Forma JSON: {"__overwrite__": value}. Múltiplos Overwrite para a mesma chave em um super-step ⇒ InvalidUpdateError.

    +
    + +
    +

    Runtime

    +
    from langgraph.runtime import Runtime
    +
    +Runtime(
    +    *,
    +    context: ContextT = None,
    +    store: BaseStore | None = None,
    +    stream_writer: StreamWriter = _no_op_stream_writer,
    +    heartbeat: Callable[[], None] = _no_op_heartbeat,
    +    previous: Any = None,
    +    execution_info: ExecutionInfo | None = None,
    +    server_info: ServerInfo | None = None,
    +    control: RunControl | None = None,
    +)
    +

    Atributos

    +
    + + + + + + + + + + + + + +
    AtributoDescrição
    contextInstância de context_schema
    storeBaseStore long-term
    stream_writerFunção para emitir custom events
    previousRetorno do checkpoint anterior (Functional API)
    execution_infoExecutionInfo: thread_id, run_id, checkpoint_id, checkpoint_ns, task_id, node_attempt, node_first_attempt_time
    server_infoServerInfo: assistant_id, graph_id, user (None fora do LangGraph Server)
    controlRunControl da invocação atual
    drain_requestedbool — true quando request_drain foi chamado
    drain_reasonstr — motivo
    +
    +

    Adicionado em v0.6.0. ToolRuntime (em langgraph.prebuilt) é subclasse que adiciona config, state, tool_call_id.

    +
    + +
    +

    RunControl

    +
    from langgraph.runtime import RunControl
    +

    Métodos: request_drain(reason: str) dispara drenagem cooperativa no próximo boundary de super-step. Não cancela tasks assíncronas. Adicionado em langgraph >= 1.2.

    +
    + +
    +

    RetryPolicy · TimeoutPolicy · CachePolicy

    +
    from langgraph.types import RetryPolicy, TimeoutPolicy, CachePolicy
    +
    RetryPolicy(initial_interval=0.5, backoff_factor=2.0, max_interval=128.0, max_attempts=3, jitter=True, retry_on=...) +
    +

    retry_on: callable ou tupla de tipos. Defaults excluem ValueError, TypeError, ArithmeticError, ImportError, LookupError, NameError, SyntaxError, RuntimeError, ReferenceError, StopIteration, StopAsyncIteration, OSError. HTTP libs só retentam 5xx.

    +
    +
    TimeoutPolicy(run_timeout=..., idle_timeout=...) >= 1.2 +
    +

    run_timeout = limite total; idle_timeout = limite sem atividade. Apenas em runtime async. Estourar levanta NodeTimeoutError.

    +
    +
    CachePolicy(key_func=None, ttl=None) +

    key_func: callable que produz a chave (default: pickle hash do input). ttl em segundos; sem TTL = nunca expira. Combinada com cache=InMemoryCache() ou SqliteCache em compile.

    +
    + +
    +

    RemainingSteps

    +
    from langgraph.managed import RemainingSteps
    +

    Managed value type para uma chave do estado. O runtime injeta automaticamente o orçamento restante de supersteps, permitindo encerrar antes de bater no recursion_limit.

    +
    + +
    +

    interrupt

    +
    from langgraph.types import interrupt
    +
    +interrupt(value: JSONLike) -> Any
    +

    Pausa o nó, persiste o estado e devolve o valor passado em Command(resume=...) no resume. Requer checkpointer + thread_id. Payload precisa ser JSON-serializável.

    +
    + +
    +

    entrypoint · task

    +
    from langgraph.func import entrypoint, task
    +
    +@entrypoint(checkpointer=..., store=...)
    +def workflow(input, *, previous=None, store=None, writer=None, config=None):
    +    ...
    +
    +@task
    +def my_task(...):
    +    ...
    +
    +# entrypoint.final[ReturnT, SaveT]
    +def workflow(...) -> entrypoint.final[int, int]:
    +    return entrypoint.final(value=..., save=...)
    +

    Decoradores da Functional API. @entrypoint retorna um Pregel; @task retorna future via .result() ou await; resultados são checkpointed e recarregados no resume.

    +
    + +
    +

    Stream parts

    +
    from langgraph.types import (
    +    StreamPart, ValuesStreamPart, UpdatesStreamPart, MessagesStreamPart,
    +    CustomStreamPart, CheckpointStreamPart, TasksStreamPart, DebugStreamPart,
    +)
    +

    Tipos do payload v2 — todos no formato {"type": str, "ns": tuple, "data": Any}.

    +
    + +
    +

    StreamWriter · get_stream_writer

    +
    from langgraph.types import StreamWriter
    +from langgraph.config import get_stream_writer
    +
    +def node(state):
    +    writer = get_stream_writer()
    +    writer({"phase": "starting"})
    +
    +async def node_async(state, writer: StreamWriter):  # < Python 3.11
    +    writer({"phase": "starting"})
    +
    + +
    +

    BaseCheckpointSaver

    +
    from langgraph.checkpoint.base import BaseCheckpointSaver
    +

    Classe-base para checkpointers customizados.

    +

    Métodos obrigatórios

    +
    + + + + + + + + + +
    MétodoPropósito
    put(config, checkpoint, metadata, new_versions)Armazena um checkpoint
    put_writes(config, writes, task_id)Armazena writes pendentes do super-step atual
    get_tuple(config) -> CheckpointTupleBusca por thread_id/checkpoint_id
    list(config, filter=..., before=..., limit=...)Itera checkpoints
    aput, aput_writes, aget_tuple, alistContrapartes async
    +
    +
    + +
    +

    InMemorySaver

    +
    from langgraph.checkpoint.memory import InMemorySaver, MemorySaver
    +
    +InMemorySaver(serde=None)
    +

    Para dev/test. serde opcional permite trocar o serializador (ex.: JsonPlusSerializer(pickle_fallback=True)). MemorySaver é alias comum.

    +
    + +
    +

    SqliteSaver · AsyncSqliteSaver

    +
    from langgraph.checkpoint.sqlite import SqliteSaver
    +from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
    +
    +SqliteSaver.from_conn_string(":memory:")
    +# ou
    +import sqlite3
    +SqliteSaver(sqlite3.connect("file.db"))
    +
    +# Async
    +async with AsyncSqliteSaver.from_conn_string("file.db") as cp:
    +    ...
    +
    + +
    +

    PostgresSaver · AsyncPostgresSaver

    +
    from langgraph.checkpoint.postgres import PostgresSaver
    +from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
    +
    +with PostgresSaver.from_conn_string(uri) as cp:
    +    cp.setup()
    +    graph = builder.compile(checkpointer=cp)
    +
    +async with AsyncPostgresSaver.from_conn_string(uri) as cp:
    +    await cp.setup()
    +    graph = builder.compile(checkpointer=cp)
    +

    .setup() é idempotente — cria tabelas e índices.

    +
    + +
    +

    RedisSaver · AsyncRedisSaver

    +
    from langgraph.checkpoint.redis import RedisSaver
    +from langgraph.checkpoint.redis.aio import AsyncRedisSaver
    +
    +cp = RedisSaver.from_conn_string("redis://localhost:6379")
    +cp.setup()
    +
    +async_cp = AsyncRedisSaver.from_conn_string("redis://localhost:6379")
    +await async_cp.asetup()
    +

    Mantido pela community (redis-developer/langgraph-redis). Opcional: indexação vetorial via RedisStack.

    +
    + +
    +

    Serializadores

    +
    from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
    +from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
    +from langgraph.checkpoint.serde.base import CipherProtocol
    +
    +# Pickle fallback opt-in
    +JsonPlusSerializer(pickle_fallback=True)
    +
    +# AES via pycryptodome (lê LANGGRAPH_AES_KEY)
    +serde = EncryptedSerializer.from_pycryptodome_aes()
    +

    O serializador padrão é JsonPlusSerializer (ormsgpack + JSON).

    +
    + +
    +

    BaseStore

    +
    from langgraph.store.base import BaseStore
    +

    Interface abstrata. Item tem value, key, namespace, created_at, updated_at.

    +

    CRUD

    +
    put(namespace, key, value, *, index=None) +

    Cria/atualiza item. index=False desliga embedding; index=["campo"] aplica apenas a campos selecionados.

    +
    get(namespace, key) -> Item | None

    Recupera por chave exata.

    +
    search(namespace, *, filter=None, query=None, limit=10, offset=0) +

    Filtros estruturados e/ou busca semântica. query exige índice de embeddings configurado.

    +
    delete(namespace, key)

    Remove o item.

    +
    list_namespaces(prefix=None, max_depth=None)

    Itera namespaces conhecidos.

    +

    Versões async: aput, aget, asearch, adelete, alist_namespaces.

    +
    + +
    +

    InMemoryStore

    +
    from langgraph.store.memory import InMemoryStore
    +from langgraph.store.base import IndexConfig
    +
    +InMemoryStore(index=IndexConfig(embed=embed_fn, dims=1536, fields=["$"]))
    +

    Para dev/test e cenários em que a memória do processo é suficiente. Não há ordenação implícita por updated_at.

    +
    + +
    +

    PostgresStore

    +
    from langgraph.store.postgres import PostgresStore
    +
    +with PostgresStore.from_conn_string(uri) as store:
    +    store.setup()
    +    # store.put(...), store.search(..., query="...", limit=3)
    +

    Ordena search por updated_at desc. Há também AsyncPostgresStore em langgraph.store.postgres.aio.

    +
    + +
    +

    create_react_agent (legado) deprecated

    +
    from langgraph.prebuilt import create_react_agent
    +
    +def create_react_agent(
    +    model: str | LanguageModelLike | Callable[..., BaseChatModel],
    +    tools: Sequence[BaseTool | Callable | dict[str, Any]] | ToolNode,
    +    *,
    +    prompt: Prompt | None = None,
    +    response_format: StructuredResponseSchema | tuple[str, StructuredResponseSchema] | None = None,
    +    pre_model_hook: RunnableLike | None = None,
    +    post_model_hook: RunnableLike | None = None,
    +    state_schema: StateSchemaType | None = None,
    +    context_schema: type[Any] | None = None,
    +    checkpointer: Checkpointer | None = None,
    +    store: BaseStore | None = None,
    +    interrupt_before: list[str] | None = None,
    +    interrupt_after: list[str] | None = None,
    +    debug: bool = False,
    +    version: Literal["v1", "v2"] = "v2",
    +    name: str | None = None,
    +) -> CompiledStateGraph
    +

    + Função decorada como @deprecated — direciona usuários a + langchain.agents.create_agent (que delega para o LangGraph). + Constrói um agente que chama tools em loop até atingir o stopping condition. +

    +
    + Note a mudança de assinatura: create_agent usa + system_prompt= em vez de prompt=. Veja a + tabela completa de deprecations v1 (§26). +
    +

    + Quando remaining_steps < 2 e há tool calls, devolve + "Sorry, need more steps to process this request." em vez de + levantar GraphRecursionError. +

    +

    Versões v1 vs v2

    +
    + + + + + + +
    VersãoDiferença
    v1Processa uma mensagem por vez
    v2 (default)Distribui tool calls via Send API (paralelo)
    +
    +
    + +
    +

    ToolNode · tools_condition

    +
    from langchain.tools import tool
    +from langgraph.prebuilt import ToolNode, tools_condition
    +from langgraph.graph import MessagesState, StateGraph
    +
    +@tool
    +def search(query: str) -> str:
    +    """Search for information."""
    +    return f"Results for: {query}"
    +
    +@tool
    +def calculator(expression: str) -> str:
    +    """Evaluate a math expression."""
    +    return str(eval(expression))
    +
    +builder = StateGraph(MessagesState)
    +builder.add_node("tools", ToolNode([search, calculator]))
    +# ... tools_condition decide entre "tools" e END
    +graph = builder.compile()
    +

    + ToolNode executa tool calls em paralelo, lida com erros e + injeção de estado (InjectedState, InjectedToolCallId, + InjectedStore). Atributo público: tools_by_name. +

    +

    + tools_condition(state) inspeciona a última mensagem; se tem + tool_calls, retorna "tools"; caso contrário, + END. +

    +
    + +
    +

    langgraph-supervisor

    +
    from langgraph_supervisor import (
    +    create_supervisor, create_handoff_tool,
    +)
    +from langgraph_supervisor.handoff import (
    +    create_forward_message_tool, METADATA_KEY_HANDOFF_DESTINATION,
    +)
    +

    create_supervisor

    +
    create_supervisor(
    +    agents: list,
    +    model: BaseChatModel,
    +    prompt: str = None,
    +    output_mode: Literal["full_history", "last_message"] = "full_history",
    +    tools: list = None,
    +    add_handoff_messages: bool = True,
    +    handoff_tool_prefix: str = "transfer_to",
    +    supervisor_name: str = "supervisor",
    +) -> StateGraph
    +

    create_handoff_tool

    +
    create_handoff_tool(agent_name: str, name: str | None = None, description: str | None = None)
    +
    + +
    +

    langgraph-swarm

    +
    from langgraph_swarm import (
    +    create_swarm, create_handoff_tool, add_active_agent_router,
    +)
    +

    create_swarm

    +
    create_swarm(
    +    agents: list,
    +    default_active_agent: str,
    +) -> StateGraph
    +

    add_active_agent_router

    +
    add_active_agent_router(builder, route_to: list[str], default_active_agent: str)
    +

    Para builds manuais que querem a mesma semântica de "último agent" do swarm.

    +
    + +
    +

    Exceções

    +
    from langgraph.errors import (
    +    GraphRecursionError, InvalidUpdateError, NodeInterrupt,
    +    GraphInterrupt, NodeError, NodeTimeoutError, GraphDrained,
    +    GraphBubbleUp, ParentCommand, EmptyInputError, TaskNotFound, ErrorCode,
    +)
    +
    + + + + + + + + + + + + + +
    ExceçãoHerdaSignificado
    GraphRecursionErrorRecursionErrorExcedeu recursion_limit (default 1000)
    InvalidUpdateErrorExceptionUpdate inválido em um canal (ex.: múltiplos Overwrite)
    NodeInterrupt(value, id=None)GraphInterruptDepreciado — use langgraph.types.interrupt
    GraphInterrupt—Base de exceções de interrupt
    NodeError—Passado ao error_handler após retries esgotarem
    NodeTimeoutErrorTimeoutErrorEstourou timeout/TimeoutPolicy (1.2+)
    GraphDrained—Levantada após RunControl.request_drain() (1.2+). Tem .reason
    EmptyInputError—Input vazio quando não permitido
    TaskNotFound—Functional API: task referenciada não existe
    +
    +
    + +
    +

    Parte C — Plataforma LangGraph

    +

    A camada Platform entrega tudo o que está fora do runtime in-process: servidor HTTP com REST + SSE, persistência durável em Postgres, fila por thread, autenticação plugável, Studio, CLI de build/deploy, SDK Python/JS, e integrações (A2A, MCP, RemoteGraph). Esta parte cobre a superfície completa.

    +
    + Quando usar a plataforma. O StateGraph compilado roda bem em qualquer processo Python. A camada Platform é necessária quando você precisa de: 1) execução background com retomada após desconexão, 2) threads persistentes acessíveis por múltiplos clientes, 3) Crons, 4) Auth multi-tenant centralizada, 5) Studio (debug/replay/fork), 6) deploy gerenciado. +
    +
    + +
    +

    27. Visão geral e arquitetura

    +

    O Agent Server é uma aplicação ASGI (FastAPI/Starlette) que expõe seus grafos via REST + SSE. Ele orquestra runs com a garantia de "no máximo 1 run ativo por thread", persiste estado em Postgres via PostgresSaver, faz fan-out de streaming via Redis pubsub e enfileira tarefas para os workers.

    +
    ┌───────────────────────────────────────────────────────────────┐
    +│  Clientes (langgraph_sdk, REST, Studio, browser SSE)          │
    +└──────────────────┬────────────────────────────────────────────┘
    +                   │ HTTPS  (X-Api-Key  /  custom auth)
    +┌──────────────────▼────────────────────────────────────────────┐
    +│  API Server  (FastAPI/Starlette ASGI)                          │
    +│   • REST: /threads /runs /assistants /crons /store             │
    +│   • SSE streaming  /stream                                     │
    +│   • Auth hooks  (@auth.authenticate, @auth.on...)              │
    +└──────────────────┬───────────────────────────┬─────────────────┘
    +                   │ enqueue                   │ pubsub
    +                   ▼                           ▼
    +            ┌─────────────┐            ┌────────────────┐
    +            │ Postgres    │            │ Redis pubsub   │
    +            │ checkpoints,│◀──ckpt─────│ event bus,     │
    +            │ assistants, │            │ stream fanout  │
    +            │ threads,    │            └────────────────┘
    +            │ runs, crons,│
    +            │ store       │
    +            └─────▲───────┘
    +                  │ lease
    +        ┌─────────┴────────────┐
    +        │ Queue Workers        │  1 run/thread, N_JOBS_PER_WORKER concorrentes
    +        │ (graph executors)    │
    +        └──────────────────────┘
    +
    + + + + + + + + +
    ComponentePapelSubstituível?
    API ServerHTTP+SSE, auth, validação de payloadNão (parte do pacote langgraph-api)
    PostgresCheckpoints, assistants, threads, runs, crons, storeSim (qualquer Postgres ≥ 14)
    RedisPubsub para fan-out de streaming; sem persistênciaSim (qualquer Redis ≥ 6)
    WorkersExecutam grafos; cada thread vira 1 worker dedicadoSim (escala horizontal independente)
    +
    +

    Variáveis-chave (self-hosted Standalone): DATABASE_URI, REDIS_URI, LANGGRAPH_CLOUD_LICENSE_KEY (Enterprise). Em modos avançados, queue.enabled: true separa workers dedicados, e o distributed runtime ainda divide API e execução em frota distinta.

    +
    + +
    +

    28. CLI langgraph

    +

    Instale com:

    +
    pip install -U "langgraph-cli[inmem]"
    +

    Todos os comandos leem ./langgraph.json por padrão. Cinco subcomandos cobrem o ciclo completo: dev, build, up, deploy, dockerfile.

    + +

    28.1 langgraph dev — servidor local in-memory

    +

    Dev server leve com hot-reload e estado pickleado em disco — sem Docker.

    +
    + + + + + + + + + + + + + + +
    FlagDefaultFunção
    -c, --config FILElanggraph.jsonCaminho do config
    --host TEXT127.0.0.1Bind host
    --port INTEGER2024Porta
    --no-reloadoffDesliga auto-reload
    --n-jobs-per-worker10Runs concorrentes por worker
    --debug-port INTEGER—Porta do depurador DAP
    --wait-for-clientoffPausa até o depurador conectar
    --no-browseroffNão abre Studio automaticamente
    --studio-url TEXThttps://smith.langchain.comURL do Studio
    --allow-blockingoffSuprime warnings de I/O síncrono
    --tunneloffExpõe via Cloudflare tunnel público
    +
    langgraph dev --port 2024 --no-browser --debug-port 5678
    + +

    28.2 langgraph build — imagem Docker

    +
    langgraph build -t myorg/my-agent:1.0 --platform linux/amd64,linux/arm64
    +
    + + + + + + + + +
    FlagDefaultFunção
    -t, --tag TEXTobrigatórioTag da imagem
    --platform TEXThostLista de plataformas alvo
    --pull / --no-pull--pullPull da base
    --build-command TEXT—JS: comando de build (ex.: yarn run turbo build)
    --install-command TEXT—JS: comando de install
    + +

    28.3 langgraph up — stack Docker local

    +

    Sobe API + Postgres + Redis localmente. Compose-style.

    +
    langgraph up -p 8123 --watch --postgres-uri "postgres://..." --debugger-port 5678
    +
    + + + + + + + + + + + + + + + +
    FlagDefaultFunção
    -p, --port INTEGER8123Porta de host para API
    --waitoffEspera healthy (implica --detach)
    --watchoffRestart on file change
    --base-image TEXTlangchain/langgraph-apiImagem base
    --image TEXT—Pré-built; pula o build
    --postgres-uri TEXTcontainer internoPostgres externo
    -d, --docker-compose FILE—Compose extra para serviços auxiliares
    --debugger-port INTEGER—Porta do depurador
    --debugger-base-url TEXThttp://127.0.0.1:[PORT]URL pública do depurador
    --recreate / --no-recreate--no-recreateForça recriação
    --pull / --no-pull--pullPull de imagens
    --verboseoffLog estendido
    + +

    28.4 langgraph deploy — push para LangSmith

    +
    langgraph deploy --name my-agent --deployment-type prod --api-key $LANGSMITH_API_KEY
    +
    + + + + + + + + + + +
    FlagDefaultFunção
    --api-key TEXTenvLangSmith API key
    --name TEXTcwdNome do deployment
    --deployment-id TEXT—Atualiza deployment existente
    --deployment-type TEXTdevdev ou prod
    --remote / --no-remoteautoForçar build remoto/local
    --no-waitoffPula polling pós-push
    --verboseoffMostra build/Docker
    +

    Subcomandos: langgraph deploy list, ... revisions list ID, ... delete ID, ... logs [-f] [-q TEXT] [--type deploy|build] [--deployment-id ID | --name NAME].

    + +

    28.5 langgraph dockerfile — gera Dockerfile

    +
    langgraph dockerfile ./Dockerfile -c langgraph.json
    +

    Re-execute sempre que langgraph.json mudar — o arquivo não é regenerado automaticamente.

    + +
    + JS/TS: npm create langgraph config escaneia createAgent(), StateGraph.compile() e workflow.compile() e gera langgraph.json. O CLI também expõe langgraph new para scaffold de projetos. +
    +
    + +
    +

    29. langgraph.json — schema completo

    +

    Schema JSON em https://langgra.ph/schema.json. Use no header:

    +
    {
    +  "$schema": "https://langgra.ph/schema.json",
    +  ...
    +}
    +
    + + + + + + + + + + + + + + + + + + +
    CampoTipoDefaultFunção
    dependenciesstring[]obrigatórioCaminhos locais (".", "./pkg") + pacotes PyPI/npm
    graphs{ name: "path:variable" }obrigatórioMap de IDs de grafo → grafo compilado ou factory function
    envstring | object—Caminho do .env ou {KEY: value} inline
    python_versionstring"3.11"3.11/3.12/3.13
    node_versionstring"20"Versão de Node para projetos JS
    pip_config_filestring—Caminho de pip.conf
    dockerfile_linesstring[][]Linhas extras anexadas ao Dockerfile
    image_distro"debian" | "wolfi" | "bookworm" | "bullseye""debian"Wolfi = menor e mais seguro · CLI ≥ 0.2.11
    auth{ path, openapi?, disable_studio_auth? }—Módulo de auth
    httpobject (abaixo)—Liga/desliga grupos de rotas built-in
    store{ index?, ttl? }—Configura store; index ativa busca semântica
    checkpointer{ ttl? }—TTL/retenção dos checkpoints
    ui{ name: "path" }—Componentes Generative UI
    webhooks{ headers?, url?, env_prefix? }—Política de webhooks de saída
    keep_pkg_toolsbool | string[]falseMantém build tools na imagem (deps nativas em runtime)
    + +

    Sub-schema http

    +

    Booleanos para desabilitar grupos: disable_meta, disable_assistants, disable_runs, disable_threads, disable_store, disable_ui, disable_webhooks. /ok liveness fica disponível mesmo com disable_meta: true.

    + +

    Sub-schema store.index — busca semântica

    +
    "store": {
    +  "index": {
    +    "embed": "openai:text-embedding-3-small",
    +    "dims": 1536,
    +    "fields": ["$"]
    +  }
    +}
    + +

    Exemplo completo

    +
    {
    +  "$schema": "https://langgra.ph/schema.json",
    +  "python_version": "3.12",
    +  "image_distro": "wolfi",
    +  "dependencies": [".", "langchain_openai", "tavily-python"],
    +  "graphs": {
    +    "agent": "./src/agent.py:graph",
    +    "research": "./src/research.py:make_graph"
    +  },
    +  "env": "./.env",
    +  "auth": {
    +    "path": "./src/auth.py:auth",
    +    "disable_studio_auth": false
    +  },
    +  "store": {
    +    "index": {
    +      "embed": "openai:text-embedding-3-small",
    +      "dims": 1536,
    +      "fields": ["$"]
    +    },
    +    "ttl": { "default_ttl": 60, "refresh_on_read": true }
    +  },
    +  "checkpointer": { "ttl": { "default_ttl": 30, "strategy": "delete" } },
    +  "http": { "disable_ui": false, "disable_webhooks": false },
    +  "webhooks": {
    +    "url": { "allowed_domains": ["*.mycompany.com"], "require_https": true },
    +    "headers": { "Authorization": "Bearer ${{ env.LG_WEBHOOK_TOKEN }}" }
    +  },
    +  "dockerfile_lines": ["RUN apt-get update && apt-get install -y libpq-dev"]
    +}
    +
    + +
    +

    30. Threads · Assistants · Runs · Crons

    +
    + + + + + + + + + +
    ConceitoIdentidadeSignificado
    Graphnome em langgraph.jsonBlueprint de código (ex.: ./agent.py:graph)
    AssistantUUIDGraph + snapshot de configuração (modelo, prompt, tools); versionado a cada update
    ThreadUUIDContainer persistente que segura os checkpoints (estado)
    RunUUIDExecução de (assistant_id, thread_id, input); 1 ativo por thread
    CronUUIDRun agendado (5-field cron em UTC)
    StorenamespaceMemória longa BaseStore-backed, opcional busca semântica
    + +

    30.1 Thread — schema

    +
    + + + + + + + + + +
    CampoTipoNotas
    thread_idUUIDPK
    created_at / updated_atISO timestamp—
    metadataobjectFiltrável: graph_id, assistant_id, langgraph_auth_user_id, cron_id...
    statusenumidle | busy | interrupted | error
    configobject{ configurable: {...} }
    valuesobjectSnapshot atual do estado
    + +

    30.2 Status de Run

    +

    pending · running · success · error · interrupted · timeout. multitask_strategy default em uma thread é "reject" (background) ou "enqueue" dependendo do path do SDK.

    + +

    30.3 Grupos de endpoints REST

    +
    + Assistants +
      +
    • POST /assistants · GET /assistants/{id} · PATCH /assistants/{id} · DELETE /assistants/{id}
    • +
    • POST /assistants/search · GET /assistants/{id}/versions
    • +
    +
    +
    + Threads +
      +
    • POST /threads · GET /threads/{id} · PATCH /threads/{id} · DELETE /threads/{id}
    • +
    • POST /threads/search · POST /threads/{id}/copy
    • +
    • GET /threads/{id}/state · POST /threads/{id}/state (update_state) · GET /threads/{id}/history
    • +
    +
    +
    + Runs em uma thread +
      +
    • POST /threads/{tid}/runs · POST /threads/{tid}/runs/stream · POST /threads/{tid}/runs/wait
    • +
    • GET /threads/{tid}/runs · GET /threads/{tid}/runs/{rid}
    • +
    • POST /threads/{tid}/runs/{rid}/cancel
    • +
    • GET /threads/{tid}/runs/{rid}/join · GET /threads/{tid}/runs/{rid}/stream (join_stream)
    • +
    • GET /threads/{tid}/stream (stream da thread inteira, atravessa runs)
    • +
    +
    +
    + Stateless runs +
    • POST /runs · POST /runs/stream · POST /runs/wait
    +
    +
    + Crons +
      +
    • POST /runs/crons · POST /threads/{tid}/runs/crons
    • +
    • POST /runs/crons/search · DELETE /runs/crons/{cid}
    • +
    +
    +
    + Store +
      +
    • PUT /store/items · GET /store/items · DELETE /store/items
    • +
    • POST /store/items/search · POST /store/namespaces
    • +
    +
    + +

    30.4 Cron expressions

    +

    5-field POSIX cron m h dom mon dow, sempre em UTC.

    +
    + + + + + + +
    ExpressãoSignificado
    "*/5 * * * *"A cada 5 minutos
    "0 9 * * 1-5"Dias úteis, 09:00 UTC
    "27 15 * * *"Diariamente, 15:27 UTC
    +

    on_run_completed="delete" (default) deleta a thread após cada run stateless do cron; "keep" retém.

    +
    + +
    +

    31. SDK Python (langgraph_sdk)

    +

    Cliente HTTP+SSE oficial; síncrono ou assíncrono.

    +
    from langgraph_sdk import get_client, get_sync_client
    +
    +client = get_client(url="https://my-deployment.langgraph.app", api_key=API_KEY)
    + +

    31.1 Threads

    +
    await client.threads.create(metadata={"user_id": "u1"}, if_exists="raise")
    +await client.threads.get(thread_id)
    +await client.threads.update(thread_id, metadata={...})
    +await client.threads.delete(thread_id)
    +await client.threads.search(metadata={"graph_id": "agent"}, limit=20, offset=0)
    +await client.threads.copy(thread_id)
    +
    +# Time travel
    +await client.threads.get_state(thread_id, checkpoint={"checkpoint_id": "..."})
    +await client.threads.update_state(thread_id, values={...}, as_node="my_node")
    +await client.threads.get_history(thread_id, limit=10, before=...)
    + +

    31.2 Runs

    +
    await client.runs.create(
    +    thread_id, assistant_id, input=...,
    +    config=..., metadata=...,
    +    multitask_strategy="enqueue",        # reject | interrupt | rollback
    +    webhook="https://...",
    +    on_disconnect="cancel",              # ou "continue" (default)
    +    after_seconds=0,
    +)
    +
    +async for chunk in client.runs.stream(
    +    thread_id, assistant_id, input=...,
    +    stream_mode="updates",               # ou ["updates","messages-tuple"] ...
    +    stream_subgraphs=False,
    +):
    +    print(chunk.event, chunk.data)
    +
    +await client.runs.wait(thread_id, assistant_id, input=...)   # bloqueante
    +await client.runs.get(thread_id, run_id)
    +await client.runs.list(thread_id)
    +await client.runs.cancel(thread_id, run_id, wait=False, action="interrupt")  # ou "rollback"
    +await client.runs.join(thread_id, run_id)
    +async for c in client.runs.join_stream(thread_id, run_id): ...
    + +

    31.3 Assistants

    +
    await client.assistants.create(
    +    graph_id="agent",
    +    config={"configurable": {"model_name": "openai"}},
    +    metadata={"team": "support"},
    +    if_exists="raise",
    +)
    +await client.assistants.get(assistant_id)
    +await client.assistants.update(assistant_id, config=..., metadata=...)
    +await client.assistants.delete(assistant_id)
    +await client.assistants.search(metadata={"team": "support"}, limit=20)
    +await client.assistants.get_versions(assistant_id)
    + +

    31.4 Crons

    +
    await client.crons.create(
    +    assistant_id,
    +    schedule="27 15 * * *",
    +    input=...,
    +    on_run_completed="delete",           # ou "keep"
    +)
    +await client.crons.create_for_thread(thread_id, assistant_id, schedule="0 9 * * 1", input=...)
    +await client.crons.search(assistant_id=..., limit=20)
    +await client.crons.delete(cron_id)
    + +

    31.5 Store (memória longa)

    +
    await client.store.put_item(namespace=("users", user_id), key="profile", value={...})
    +await client.store.get_item(namespace=("users", user_id), key="profile")
    +await client.store.search_items(
    +    namespace_prefix=("users", user_id),
    +    query="prefers vegetarian",
    +    limit=10,
    +)
    +await client.store.delete_item(namespace=("users", user_id), key="profile")
    +await client.store.list_namespaces(prefix=("users",), limit=100)
    + +

    31.6 Dois assistants em uma thread

    +
    thread = await client.threads.create()
    +
    +# Pergunta para o OpenAI
    +async for ev in client.runs.stream(
    +    thread["thread_id"], openai_assistant["assistant_id"],
    +    input={"messages":[{"role":"user","content":"who made you?"}]},
    +    stream_mode="updates",
    +):
    +    print(ev.data)
    +
    +# Continua a conversa, agora com o Anthropic — mesma thread, contexto preservado
    +async for ev in client.runs.stream(
    +    thread["thread_id"], anthropic_assistant["assistant_id"],
    +    input={"messages":[{"role":"user","content":"and you?"}]},
    +    stream_mode="updates",
    +):
    +    print(ev.data)
    +
    + +
    +

    32. Streaming, join e retomada (Platform)

    +

    Além dos modos do runtime (values, updates, messages-tuple, debug, custom, events), a Platform adiciona thread streams de longa duração e retomada via SSE Last-Event-ID.

    + +

    32.1 Stream em background — join_stream

    +

    Conecta-se a um run que já está executando. Eventos antes do join não são reproduzidos.

    +
    async for chunk in client.runs.join_stream(thread_id, run_id):
    +    print(chunk)
    + +

    32.2 Thread stream — atravessa runs

    +

    Canal de eventos por thread, persiste enquanto a thread existir.

    +
    async for chunk in client.threads.join_stream(
    +    thread_id,
    +    stream_mode=["run_modes", "lifecycle", "state_update"],
    +):
    +    print(chunk.event, chunk.data)
    + +

    32.3 Retomada com last_event_id

    +
    async for chunk in client.threads.join_stream(
    +    thread_id,
    +    last_event_id="<id do último chunk recebido>",
    +):
    +    ...
    +

    last_event_id="-" reproduz do começo. Em HTTP cru, o mesmo é feito via header Last-Event-ID.

    + +

    32.4 Política on_disconnect

    +
    + + + + + +
    ValorComportamento
    "continue" (default)Run continua mesmo se o cliente SSE desconectar
    "cancel"Run termina se o cliente SSE sair
    +
    + +
    +

    33. Autenticação personalizada (@auth)

    +

    Duas fases em cada request: 1) Autenticação (@auth.authenticate devolve o usuário), 2) Autorização (handler mais específico decide; retorna None/True = permite, False = 403, ou um dict filtro restringindo metadata).

    + +
    "auth": { "path": "./auth.py:auth", "disable_studio_auth": false }
    + +

    33.1 @auth.authenticate

    +

    Aceita qualquer subconjunto de: request, body, path, method, path_params, query_params, headers, authorization.

    +
    from langgraph_sdk import Auth
    +auth = Auth()
    +
    +@auth.authenticate
    +async def authenticate(authorization: str | None, headers: dict) -> Auth.types.MinimalUserDict:
    +    if not authorization or not authorization.startswith("Bearer "):
    +        raise Auth.exceptions.HTTPException(status_code=401, detail="Missing token")
    +    token = authorization.removeprefix("Bearer ")
    +    user = await verify_jwt(token)
    +    return {
    +        "identity": user["sub"],                       # obrigatório
    +        "is_authenticated": True,
    +        "permissions": user.get("permissions", []),
    +        "display_name": user.get("name"),
    +        "org_id": user.get("org_id"),                  # campo custom
    +    }
    + +

    33.2 Hierarquia de autorização

    +

    Recursos: threads · assistants · crons · store. Verbos: create · read · update · delete · search (e threads.create_run). Fallback global: @auth.on.

    +
    @auth.on
    +async def reject_unmatched(ctx, value):
    +    raise Auth.exceptions.HTTPException(403, detail="Forbidden")
    +
    +@auth.on.threads.create
    +async def on_thread_create(ctx, value: Auth.types.ThreadsCreate):
    +    md = value.setdefault("metadata", {})
    +    md["owner"] = ctx.user.identity
    +    return {"owner": ctx.user.identity}            # filtra leituras futuras
    +
    +@auth.on.threads.read
    +async def on_thread_read(ctx, value):
    +    return {"owner": ctx.user.identity}
    +
    +@auth.on.threads.create_run
    +async def on_run_create(ctx, value):
    +    value.setdefault("metadata", {})["owner"] = ctx.user.identity
    +    return {"owner": ctx.user.identity}
    +
    +@auth.on.assistants.create
    +async def on_assistant_create(ctx, value):
    +    if "assistants:create" not in ctx.permissions:
    +        raise Auth.exceptions.HTTPException(403, "Missing assistants:create")
    +    value.setdefault("metadata", {})["owner"] = ctx.user.identity
    +    return {"owner": ctx.user.identity}
    +
    +@auth.on.store
    +async def on_store(ctx, value):
    +    # Namespace do store deve começar com o próprio identity
    +    if value["namespace"][0] != ctx.user.identity:
    +        raise Auth.exceptions.HTTPException(403, "Cross-user store access denied")
    +    return True
    + +

    33.3 Dialeto de filtros

    +
    {"owner": user_id}                              # match exato
    +{"owner": {"$eq": user_id}}
    +{"allowed_users": {"$contains": user_id}}       # lista contém
    +{"owner": org_id, "allowed_users": {"$contains": user_id}}   # AND
    + +

    AuthContext expõe ctx.user.identity, ctx.user.is_authenticated, ctx.permissions, ctx.path, além de campos custom retornados em authenticate. Dentro de um nó, o usuário aparece em config["configurable"]["langgraph_auth_user"].

    + +
    + Bypass do Studio. Requests do Studio carregam um header especial — handlers podem deixar desenvolvedores passarem irrestritamente. Para forçar auth também no Studio, ative "disable_studio_auth": true. +
    +
    + +
    +

    34. Double-texting (4 estratégias)

    +

    Quando uma nova mensagem chega numa thread cujo run anterior ainda está rodando, a estratégia multitask_strategy decide o destino do novo run.

    +
    + + + + + + + +
    EstratégiaComportamentoQuando usar
    enqueueNovo run entra na fila, executa após o atualChat onde ordem importa
    rejectNovo run rejeitado com HTTP 409Operações caras e não-duplicáveis
    interruptRun atual interrompe; novo começa do checkpoint construído até aquiAgente em tempo real — trabalho intermediário é descartável
    rollbackRun atual é cancelado e suas escritas são revertidas; novo run começa do estado pré-runReinício totalmente limpo
    + +
    # Enqueue
    +await client.runs.create(thread_id, aid, input=msg1, multitask_strategy="enqueue")
    +await client.runs.create(thread_id, aid, input=msg2, multitask_strategy="enqueue")
    +
    +# Reject (409 se há run em andamento)
    +await client.runs.create(thread_id, aid, input=msg, multitask_strategy="reject")
    +
    +# Interrupt (preserva progresso parcial; cuidado com tool calls em andamento)
    +await client.runs.create(thread_id, aid, input=msg, multitask_strategy="interrupt")
    +
    +# Rollback (descarta progresso do run atual)
    +await client.runs.create(thread_id, aid, input=msg, multitask_strategy="rollback")
    + +
    + Em interrupt, o estado refletirá tudo que foi checkpointado até a interrupção — seus nós devem ser projetados para serem retomáveis em qualquer ponto, inclusive no meio de tool calls. +
    +
    + +
    +

    35. Webhooks

    +

    Webhooks disparam quando um run alcança status terminal. São aceitos como parâmetro webhook em runs.create, runs.stream, runs.wait e crons.create.

    +
    await client.runs.stream(
    +    thread_id, assistant_id, input=msg,
    +    stream_mode="events",
    +    webhook="https://my-server.app/hook?token=SECRET",
    +)
    + +

    35.1 Payload (objeto Run)

    +
    {
    +  "run_id": "1ef6a5b8-...",
    +  "thread_id": "5d7a-...",
    +  "assistant_id": "agent",
    +  "status": "success",
    +  "values": { "messages": [{"role":"assistant","content":"Hi"}] },
    +  "kwargs": { "input": {...}, "config": {...} },
    +  "webhook_sent_at": "2026-05-24T15:01:23Z",
    +  "error": null
    +}
    +

    Em falha, error = {"error": "TimeoutError", "message": "Run exceeded max time"}.

    + +

    35.2 Segurança

    +

    Não há HMAC nativo. Duas opções suportadas:

    +
      +
    1. Token na query string: https://my-server/hook?token=$SECRET e validação no servidor.
    2. +
    3. Headers estáticos (requer langgraph-api ≥ 0.5.36) declarados em langgraph.json:
    4. +
    +
    "webhooks": {
    +  "headers": { "Authorization": "Bearer ${{ env.LG_WEBHOOK_TOKEN }}" },
    +  "url": { "allowed_domains": ["*.mycompany.com"], "require_https": true },
    +  "env_prefix": "LG_WEBHOOK_"
    +}
    +

    Só variáveis de ambiente que casam com env_prefix são interpoláveis (default LG_WEBHOOK_). Para desligar webhooks: "http": { "disable_webhooks": true } (langgraph-api ≥ 0.2.78).

    + +
    + Não há política documentada de retry. Trate a entrega como at-most-once; se precisar de garantia, reconcilie via client.runs.get(thread_id, run_id). +
    +
    + +
    +

    36. LangGraph Studio

    +

    Studio é a aplicação web em smith.langchain.com que conecta a um servidor LangGraph (local ou deployment) para visualizar grafos, percorrer threads, editar estado, refazer steps e iterar prompts.

    + +

    36.1 Dois modos de execução

    +
    + + + + + +
    ModoComo conectarAuth
    Locallanggraph dev em :2024; Studio aponta para localhostHandlers recebem contexto Studio-tagged (a menos que disable_studio_auth: true)
    CloudLangSmith Deployment publicado via langgraph deployAuth normal; 1-click deploy a partir do Studio é suportado
    + +

    36.2 Dois modos de UI

    +
      +
    • Graph mode — grafo completo, inspeção de estado, tool calls, datasets, playground.
    • +
    • Chat mode — UI simplificada; exige estado compatível com MessagesState.
    • +
    + +

    36.3 Capacidades-chave

    +
      +
    • Time travel: slider através do histórico de checkpoints da thread; inspecione qualquer um.
    • +
    • Editar estado em um nó (ícone de lápis) → Fork cria nova branch a partir do checkpoint com a edição.
    • +
    • Re-run from here: repete sem editar estado (útil para trocar assistant ou versão de modelo).
    • +
    • Interrupt coloca breakpoint pré/pós-nó; Continue retoma.
    • +
    • Experiments: roda eval contra datasets direto na UI.
    • +
    • Long-term memory: navega/edita namespaces do Store.
    • +
    +
    + +
    +

    37. Opções de deployment

    +
    + + + + + + + +
    OpçãoControl planeData planeInfraPlano
    CloudLangChainLangChain (AWS/GCP)GerenciadoPlus+
    HybridLangChainCliente (K8s)K8s + listenerEnterprise
    Self-Hosted Full PlatformClienteClienteK8s + LangSmith self-hosted + CRD langgraphPlatformEnterprise
    Self-Hosted Standalone Server—ClienteDocker / Compose / K8sEnterprise
    +

    Para Standalone, as 3 variáveis decisivas são DATABASE_URI (Postgres), REDIS_URI (Redis) e LANGGRAPH_CLOUD_LICENSE_KEY. Tiers opcionais: queue.enabled: true dedica hosts para workers; o distributed runtime separa orquestração da execução.

    +
    + +
    +

    Parte D — Receituário de padrões

    +

    Catorze padrões canônicos da documentação oficial LangGraph, condensados em ~30 linhas cada. Os nomes de classes/funções batem com os notebooks oficiais em github.com/langchain-ai/langgraph/tree/main/examples.

    +
    + A tabela abaixo resume quando aplicar cada padrão. +
    +
    + + + + + + + + + + + + + + + + + +
    PadrãoBom paraCusto (calls LLM)
    ReAct estruturadoOutput schema garantidobaixo
    Plan-and-executeTarefas longas com passos discretosmédio
    ReflectionQualidade de escrita/código2–4× ReAct
    ReflexionLoops de auto-crítica estruturada3–5× ReAct
    Self-DiscoverTarefas novas exigindo "como pensar"3–4 calls extras
    ReWOOReduzir LLM calls (planner-once)baixo
    SupervisorEspecialistas dedicados, controle centralmédio
    NetworkColaboração peer-to-peermédio
    HierárquicoTimes de timesalto
    CRAGRAG quando retrieval falha às vezes+1 call (grader)
    Self-RAGGrounding e utilidade garantidos+3 calls (graders)
    Adaptive RAGRoteia entre vectorstore e web+1 call (router)
    LATSRaciocínio difícil com busca em árvore5–20× ReAct
    STORMArtigos longos com fontesalto
    +
    + +
    +

    R1. ReAct com saída estruturada

    +

    Ideia. Loop ReAct padrão, mas a resposta final passa por um schema Pydantic via uma tool dedicada WeatherResponse que termina a execução.

    +

    URL canônica: examples/react-agent-structured-output.ipynb

    +
    from typing import Literal
    +from pydantic import BaseModel
    +from langchain_openai import ChatOpenAI
    +from langgraph.graph import StateGraph, MessagesState, END
    +from langgraph.prebuilt import ToolNode
    +
    +class WeatherResponse(BaseModel):
    +    temperature: float
    +    conditions: str
    +
    +@tool
    +def search(query: str) -> str: ...
    +def respond(state: MessagesState):
    +    return {"final": state["messages"][-1].tool_calls[0]["args"]}
    +
    +llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([search, WeatherResponse])
    +
    +def call_model(state: MessagesState):
    +    return {"messages": [llm.invoke(state["messages"])]}
    +
    +def route(state) -> Literal["tools", "respond", END]:
    +    last = state["messages"][-1]
    +    if not last.tool_calls: return END
    +    if last.tool_calls[0]["name"] == "WeatherResponse": return "respond"
    +    return "tools"
    +
    +g = StateGraph(MessagesState)
    +g.add_node("agent", call_model); g.add_node("tools", ToolNode([search]))
    +g.add_node("respond", respond)
    +g.set_entry_point("agent"); g.add_conditional_edges("agent", route)
    +g.add_edge("tools", "agent"); g.add_edge("respond", END)
    +app = g.compile()
    +
    + +
    +

    R2. Plan-and-execute

    +

    Ideia. Gera plano completo upfront, executa step-a-step e replaneja quando necessário.

    +

    URL: examples/plan-and-execute

    +
    from pydantic import BaseModel
    +from langgraph.graph import StateGraph, END
    +
    +class Plan(BaseModel):
    +    steps: list[str]
    +
    +class PlanExecute(TypedDict):
    +    input: str
    +    plan: list[str]
    +    past_steps: list[tuple[str, str]]
    +    response: str
    +
    +planner   = planner_prompt   | ChatOpenAI(model="gpt-5.5", use_responses_api=True).with_structured_output(Plan)
    +executor  = create_react_agent("openai:gpt-5.4-mini", tools=[search])
    +replanner = replanner_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True).with_structured_output(Plan)
    +
    +async def plan_step(s):    return {"plan": (await planner.ainvoke({"input": s["input"]})).steps}
    +async def execute_step(s):
    +    step = s["plan"][0]
    +    out  = await executor.ainvoke({"messages":[("user", step)]})
    +    return {"past_steps": [(step, out["messages"][-1].content)]}
    +async def replan_step(s):  return {"plan": (await replanner.ainvoke(s)).steps}
    +def should_end(s):         return END if not s["plan"] else "agent"
    +
    +g = StateGraph(PlanExecute)
    +g.add_node("planner", plan_step); g.add_node("agent", execute_step); g.add_node("replan", replan_step)
    +g.set_entry_point("planner"); g.add_edge("planner", "agent")
    +g.add_edge("agent", "replan"); g.add_conditional_edges("replan", should_end)
    +app = g.compile()
    +
    + +
    +

    R3. Reflection

    +

    Ideia. Generator escreve, reflector critica, loop até crítico satisfeito ou N rodadas.

    +

    URL: examples/reflection · blog

    +
    from langgraph.graph import StateGraph, MessagesState, END
    +
    +generate = generator_prompt  | ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    +reflect  = reflection_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    +
    +async def generation_node(state: MessagesState):
    +    return {"messages": [await generate.ainvoke(state["messages"])]}
    +
    +async def reflection_node(state: MessagesState):
    +    # Flip roles para que o LLM veja o draft do assistente como input do usuário
    +    flipped = [HumanMessage(m.content) if isinstance(m, AIMessage) else AIMessage(m.content)
    +               for m in state["messages"][1:]]
    +    crit = await reflect.ainvoke([state["messages"][0]] + flipped)
    +    return {"messages": [HumanMessage(content=crit.content)]}
    +
    +def should_continue(state):
    +    return END if len(state["messages"]) > 6 else "reflect"
    +
    +g = StateGraph(MessagesState)
    +g.add_node("generate", generation_node); g.add_node("reflect", reflection_node)
    +g.set_entry_point("generate")
    +g.add_conditional_edges("generate", should_continue)
    +g.add_edge("reflect", "generate")
    +app = g.compile()
    +
    + +
    +

    R4. Reflexion

    +

    Ideia. Após cada trial, o agente produz auto-feedback verbal estruturado (missing/superfluous/search_queries) que entra em memória persistente consultada no próximo trial.

    +

    URL: examples/reflexion

    +
    from pydantic import BaseModel, Field
    +from langgraph.graph import StateGraph, MessagesState, END
    +
    +class Reflection(BaseModel):
    +    missing: str = Field(description="What's missing.")
    +    superfluous: str = Field(description="What's unnecessary.")
    +
    +class AnswerQuestion(BaseModel):
    +    answer: str
    +    reflection: Reflection
    +    search_queries: list[str] = Field(description="1-3 queries to address gaps.")
    +
    +responder = responder_prompt | ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([AnswerQuestion])
    +revisor   = revisor_prompt   | ChatOpenAI(model="gpt-5.5", use_responses_api=True).bind_tools([AnswerQuestion])
    +
    +def run_tools(state):
    +    queries = state["messages"][-1].tool_calls[0]["args"]["search_queries"]
    +    results = [tavily.invoke(q) for q in queries]
    +    return {"messages": [ToolMessage(content=str(results), tool_call_id="t")]}
    +
    +def event_loop(state):
    +    return END if state["messages"][-1].additional_kwargs.get("trial", 0) >= 3 else "execute_tools"
    +
    +g = StateGraph(MessagesState)
    +g.add_node("draft", lambda s: {"messages":[responder.invoke(s["messages"])]})
    +g.add_node("execute_tools", run_tools)
    +g.add_node("revise", lambda s: {"messages":[revisor.invoke(s["messages"])]})
    +g.set_entry_point("draft")
    +g.add_edge("draft","execute_tools"); g.add_edge("execute_tools","revise")
    +g.add_conditional_edges("revise", event_loop, {"execute_tools":"execute_tools", END:END})
    +app = g.compile()
    +
    + +
    +

    R5. Self-Discover

    +

    Ideia. Três passos: SELECT (módulos de raciocínio relevantes) → ADAPT (adapta ao problema) → IMPLEMENT (plano JSON) → solve. A estrutura de raciocínio é composta em runtime em vez de hardcoded.

    +

    URL: examples/self-discover

    +
    from langgraph.graph import StateGraph, END
    +
    +class State(TypedDict):
    +    task: str; modules: list[str]
    +    selected: str; adapted: str; plan: str; answer: str
    +
    +llm = ChatOpenAI(model="gpt-5.5", use_responses_api=True)
    +
    +def select(s):    return {"selected": llm.invoke(f"Select modules for: {s['task']}\nFrom: {s['modules']}").content}
    +def adapt(s):     return {"adapted":  llm.invoke(f"Adapt these to the task '{s['task']}': {s['selected']}").content}
    +def implement(s): return {"plan":     llm.invoke(f"Produce a JSON reasoning plan from: {s['adapted']}").content}
    +def solve(s):     return {"answer":   llm.invoke(f"Follow the plan to solve.\nTask: {s['task']}\nPlan: {s['plan']}").content}
    +
    +g = StateGraph(State)
    +g.add_node("select", select); g.add_node("adapt", adapt)
    +g.add_node("implement", implement); g.add_node("solve", solve)
    +g.set_entry_point("select")
    +g.add_edge("select", "adapt"); g.add_edge("adapt", "implement")
    +g.add_edge("implement", "solve"); g.add_edge("solve", END)
    +app = g.compile()
    +
    + +
    +

    R6. ReWOO (Reasoning WithOut Observation)

    +

    Ideia. Planner emite plano completo com placeholders de evidência (#E1, #E2); workers rodam tools para preencher; solver sintetiza. Sem diálogo intercalado LLM↔tool → menos tokens que ReAct.

    +

    URL: examples/rewoo

    +
    import re
    +from langgraph.graph import StateGraph, END
    +
    +PLAN_RE = re.compile(r"Plan:\s*(.*?)\n#E(\d+)\s*=\s*(\w+)\[(.*?)\]")
    +
    +class S(TypedDict):
    +    task: str; steps: list; results: dict; result: str
    +
    +def plan(s):
    +    raw = llm.invoke(planner_prompt.format(task=s["task"])).content
    +    return {"steps": PLAN_RE.findall(raw)}
    +
    +def tool_execution(s):
    +    _, n, tool, args = s["steps"][len(s["results"])]
    +    args = re.sub(r"#E(\d+)", lambda m: s["results"][f"#E{m.group(1)}"], args)
    +    return {"results": {**s["results"], f"#E{n}": tools[tool].invoke(args)}}
    +
    +def solve(s):
    +    plan = "\n".join(f"Plan: {p}\n#E{n} = {t}[{a}] = {s['results'][f'#E{n}']}"
    +                     for p,n,t,a in s["steps"])
    +    return {"result": llm.invoke(solver_prompt.format(task=s["task"], plan=plan)).content}
    +
    +def route(s): return END if len(s["results"]) == len(s["steps"]) else "tool"
    +
    +g = StateGraph(S)
    +g.add_node("plan", plan); g.add_node("tool", tool_execution); g.add_node("solve", solve)
    +g.set_entry_point("plan"); g.add_edge("plan", "tool")
    +g.add_conditional_edges("tool", route, {"tool":"tool","solve":"solve"}); g.add_edge("solve", END)
    +app = g.compile()
    +
    + +
    +

    R7. Multi-agent supervisor

    +

    Ideia. Um LLM supervisor escolhe qual especialista chamar próximo; cada chamada retorna controle ao supervisor.

    +

    URL: langgraph-supervisor-py

    +
    from langgraph_supervisor import create_supervisor
    +from langgraph.prebuilt import create_react_agent
    +from langgraph.checkpoint.memory import InMemorySaver
    +
    +def add(a: float, b: float) -> float: return a + b
    +def web_search(q: str) -> str: return tavily.invoke(q)
    +
    +math_agent     = create_react_agent(model="openai:gpt-5.5", tools=[add], name="math_expert")
    +research_agent = create_react_agent(model="openai:gpt-5.5", tools=[web_search], name="research_expert")
    +
    +workflow = create_supervisor(
    +    [research_agent, math_agent],
    +    model=ChatOpenAI(model="gpt-5.5", use_responses_api=True),
    +    prompt="You manage a research expert and a math expert. Route accordingly.",
    +)
    +app = workflow.compile(checkpointer=InMemorySaver())
    +result = app.invoke({"messages":[{"role":"user",
    +    "content":"What's the combined FAANG headcount in 2024?"}]})
    +
    + Note o contraste: os subagents acima usam a string "openai:gpt-5.5" + (que cai em Chat Completions), enquanto o supervisor recebe um + ChatOpenAI(..., use_responses_api=True) explícito. Para forçar a + Responses API nos subagents, instancie o modelo e passe o objeto em vez da + string — ver a política de integração (§2). +
    +
    + +
    +

    R8. Multi-agent network (colaboração)

    +

    Ideia. Cada agent pode passar trabalho para qualquer peer; roteamento decidido por tool calls. FINAL ANSWER termina.

    +

    URL: multi-agent-collaboration.ipynb

    +
    from langgraph.graph import StateGraph, MessagesState, END
    +
    +def make_node(agent, name):
    +    def node(state):
    +        result = agent.invoke(state)
    +        result["messages"][-1].name = name
    +        return {"messages": result["messages"]}
    +    return node
    +
    +def route(state):
    +    last = state["messages"][-1]
    +    if "FINAL ANSWER" in last.content: return END
    +    return "Chart Generator" if last.name == "Researcher" else "Researcher"
    +
    +researcher = create_react_agent(llm, tools=[search],     prompt=research_prompt)
    +charter    = create_react_agent(llm, tools=[python_repl], prompt=chart_prompt)
    +
    +g = StateGraph(MessagesState)
    +g.add_node("Researcher",      make_node(researcher, "Researcher"))
    +g.add_node("Chart Generator", make_node(charter,    "Chart Generator"))
    +g.set_entry_point("Researcher")
    +g.add_conditional_edges("Researcher",      route, {"Chart Generator":"Chart Generator", END:END})
    +g.add_conditional_edges("Chart Generator", route, {"Researcher":"Researcher", END:END})
    +app = g.compile()
    +
    + +
    +

    R9. Times hierárquicos

    +

    Ideia. Cada sub-time é um subgrafo com seu próprio supervisor; um supervisor de topo roteia entre times.

    +

    URL: hierarchical_agent_teams.ipynb

    +
    from langgraph.graph import StateGraph, MessagesState, END
    +
    +def call_research(state): return research_team.invoke({"messages": state["messages"]})
    +def call_writing(state):  return writing_team.invoke({"messages":  state["messages"]})
    +
    +def top_supervisor(state):
    +    return llm.with_structured_output(Route).invoke(supervisor_prompt + state["messages"])
    +
    +def route(state):
    +    decision = state["next"]   # "research_team" | "writing_team" | "FINISH"
    +    return END if decision == "FINISH" else decision
    +
    +g = StateGraph(MessagesState)
    +g.add_node("supervisor",    lambda s: {"next": top_supervisor(s).destination})
    +g.add_node("research_team", call_research)
    +g.add_node("writing_team",  call_writing)
    +g.set_entry_point("supervisor")
    +g.add_conditional_edges("supervisor", route)
    +g.add_edge("research_team", "supervisor"); g.add_edge("writing_team", "supervisor")
    +app = g.compile()
    +
    + +
    +

    R10. Corrective RAG (CRAG)

    +

    Ideia. Grader avalia docs recuperados; se relevância baixa, reescreve a query e cai em web search antes de gerar.

    +

    URL: examples/rag/langgraph_crag.ipynb

    +
    from langgraph.graph import StateGraph, END
    +
    +class S(TypedDict):
    +    question: str; documents: list; web_search: str; generation: str
    +
    +def retrieve(s):
    +    return {"documents": retriever.invoke(s["question"])}
    +
    +def grade(s):
    +    kept = [d for d in s["documents"]
    +            if "yes" in grader.invoke({"q": s["question"], "d": d.page_content}).binary_score]
    +    return {"documents": kept, "web_search": "Yes" if not kept else "No"}
    +
    +def transform_query(s):
    +    return {"question": rewriter.invoke({"question": s["question"]}).content}
    +
    +def web_search_node(s):
    +    docs = tavily.invoke(s["question"])
    +    return {"documents": s["documents"] + [Document(page_content=d["content"]) for d in docs]}
    +
    +def generate(s):
    +    return {"generation": rag_chain.invoke({"q": s["question"], "docs": s["documents"]})}
    +
    +def decide(s): return "transform_query" if s["web_search"]=="Yes" else "generate"
    +
    +g = StateGraph(S)
    +for n, f in [("retrieve",retrieve),("grade",grade),("transform_query",transform_query),
    +             ("web_search",web_search_node),("generate",generate)]:
    +    g.add_node(n, f)
    +g.set_entry_point("retrieve"); g.add_edge("retrieve","grade")
    +g.add_conditional_edges("grade", decide); g.add_edge("transform_query","web_search")
    +g.add_edge("web_search","generate"); g.add_edge("generate", END)
    +app = g.compile()
    +
    + +
    +

    R11. Self-RAG

    +

    Ideia. Três graders independentes: relevância por doc, grounding (alucinação) e utilidade da resposta. Retry de retrieval ou geração até passar nos três.

    +

    URL: examples/rag/langgraph_self_rag.ipynb

    +
    from langgraph.graph import StateGraph, END
    +
    +class S(TypedDict): question: str; documents: list; generation: str
    +
    +def retrieve(s):  return {"documents": retriever.invoke(s["question"])}
    +def grade_docs(s):
    +    kept = [d for d in s["documents"]
    +            if doc_grader.invoke({"q": s["question"], "d": d.page_content}).score == "yes"]
    +    return {"documents": kept}
    +def generate(s):  return {"generation": rag.invoke({"q": s["question"], "docs": s["documents"]})}
    +def transform(s): return {"question": rewriter.invoke({"q": s["question"]}).content}
    +
    +def decide_after_grade(s):    return "generate" if s["documents"] else "transform_query"
    +def decide_after_generate(s):
    +    grounded = halluc_grader.invoke({"docs": s["documents"], "gen": s["generation"]}).score == "yes"
    +    if not grounded: return "generate"
    +    useful = answer_grader.invoke({"q": s["question"], "gen": s["generation"]}).score == "yes"
    +    return END if useful else "transform_query"
    +
    +g = StateGraph(S)
    +for n, f in [("retrieve",retrieve),("grade",grade_docs),
    +             ("generate",generate),("transform_query",transform)]:
    +    g.add_node(n, f)
    +g.set_entry_point("retrieve"); g.add_edge("retrieve","grade")
    +g.add_conditional_edges("grade",    decide_after_grade)
    +g.add_edge("transform_query","retrieve")
    +g.add_conditional_edges("generate", decide_after_generate)
    +app = g.compile()
    +
    + +
    +

    R12. Adaptive RAG

    +

    Ideia. Router escolhe vectorstore vs. web search por query, depois roda um loop Self-RAG. Adapta a estratégia de retrieval à classe da pergunta.

    +

    URL: examples/rag/langgraph_adaptive_rag.ipynb

    +
    from pydantic import BaseModel, Field
    +from langgraph.graph import StateGraph, END
    +
    +class Route(BaseModel):
    +    datasource: Literal["vectorstore","web_search"] = Field(description="Pick one")
    +
    +router = (router_prompt | ChatOpenAI(model="gpt-5.4-mini", temperature=0, use_responses_api=True)
    +                          .with_structured_output(Route))
    +
    +def route_query(s):
    +    return "web_search" if router.invoke({"question": s["question"]}).datasource == "web_search" \
    +                        else "retrieve"
    +
    +g = StateGraph(S)
    +g.add_node("retrieve", retrieve); g.add_node("web_search", web_search_node)
    +g.add_node("grade", grade_docs); g.add_node("generate", generate)
    +g.add_node("transform_query", transform)
    +g.set_conditional_entry_point(route_query, {"retrieve":"retrieve", "web_search":"web_search"})
    +g.add_edge("retrieve","grade"); g.add_edge("web_search","generate")
    +g.add_conditional_edges("grade", lambda s: "generate" if s["documents"] else "transform_query")
    +g.add_edge("transform_query","retrieve")
    +g.add_conditional_edges("generate", decide_after_generate)
    +app = g.compile()
    +
    + +
    +

    R13. LATS — Language Agent Tree Search

    +

    Ideia. MCTS sobre trajetórias de raciocínio LLM com seleção UCB, avaliação por reflexão e backpropagation. Troca 5–20× LLM calls por taxa de solução maior em raciocínio difícil.

    +

    URL: examples/lats/lats.ipynb

    +
    import math
    +from dataclasses import dataclass, field
    +
    +@dataclass
    +class Node:
    +    messages: list
    +    parent: "Node | None" = None
    +    children: list = field(default_factory=list)
    +    value: float = 0.0
    +    visits: int = 0
    +    reflection: str | None = None
    +
    +    def uct(self, c=1.4):
    +        if self.visits == 0: return float("inf")
    +        return self.value/self.visits + c*math.sqrt(math.log(self.parent.visits)/self.visits)
    +
    +    def best_child(self): return max(self.children, key=lambda n: n.uct())
    +    def is_solved(self):  return self.reflection and "SOLVED" in self.reflection
    +
    +def expand(node):
    +    candidates = generator.batch([node.messages]*5)
    +    node.children = [Node(node.messages+[c], parent=node) for c in candidates]
    +
    +def evaluate(node):
    +    node.reflection = reflector.invoke(node.messages).content
    +    score = float(reflector_score(node.reflection))
    +    while node:
    +        node.visits += 1; node.value += score
    +        node = node.parent
    +
    +def lats(root, max_rollouts=10):
    +    for _ in range(max_rollouts):
    +        leaf = root
    +        while leaf.children: leaf = leaf.best_child()
    +        expand(leaf)
    +        for child in leaf.children:
    +            evaluate(child)
    +            if child.is_solved(): return child
    +    return root.best_child()
    +
    + +
    +

    R14. STORM — pesquisa + escrita

    +

    Ideia. Gera outline, simula entrevistas com múltiplos experts (cada um busca e responde em paralelo via Send), refina outline, escreve seções, monta artigo.

    +

    URL: examples/storm/storm.ipynb

    +
    from langgraph.graph import StateGraph, END
    +from langgraph.constants import Send
    +
    +def outline(s):      return {"outline":  outline_llm.invoke({"topic": s["topic"]})}
    +def perspectives(s): return {"experts":  expert_llm.invoke({"outline": s["outline"]}).experts}
    +
    +def dispatch(s):  # fan-out paralelo
    +    return [Send("interview", {"expert": e, "topic": s["topic"]}) for e in s["experts"]]
    +
    +def interview(s):
    +    qa = []
    +    for _ in range(3):
    +        q    = question_llm.invoke({"expert": s["expert"], "qa": qa})
    +        docs = search.invoke(q)
    +        a    = answer_llm.invoke({"q": q, "docs": docs})
    +        qa.append({"q": q, "a": a})
    +    return {"interviews": [{"expert": s["expert"], "qa": qa}]}
    +
    +def refine(s):  return {"outline_v2": refine_llm.invoke({"out": s["outline"], "int": s["interviews"]})}
    +def write(s):   return {"article":    writer_llm.invoke({"outline": s["outline_v2"], "int": s["interviews"]})}
    +
    +g = StateGraph(STORMState)
    +for n, f in [("outline",outline),("perspectives",perspectives),
    +             ("interview",interview),("refine",refine),("write",write)]:
    +    g.add_node(n, f)
    +g.set_entry_point("outline"); g.add_edge("outline","perspectives")
    +g.add_conditional_edges("perspectives", dispatch, ["interview"])
    +g.add_edge("interview","refine"); g.add_edge("refine","write"); g.add_edge("write", END)
    +app = g.compile()
    +
    + +
    +

    Apêndice — endpoints REST e variáveis-chave

    +

    HTTP cheat-sheet

    +
    # Threads
    +POST   /threads
    +POST   /threads/search
    +GET    /threads/{id}
    +PATCH  /threads/{id}
    +DELETE /threads/{id}
    +POST   /threads/{id}/copy
    +GET    /threads/{id}/state
    +POST   /threads/{id}/state           # update_state
    +GET    /threads/{id}/history
    +GET    /threads/{id}/stream          # thread-wide SSE (atravessa runs)
    +
    +# Runs (em uma thread)
    +POST   /threads/{tid}/runs
    +POST   /threads/{tid}/runs/stream
    +POST   /threads/{tid}/runs/wait
    +GET    /threads/{tid}/runs
    +GET    /threads/{tid}/runs/{rid}
    +POST   /threads/{tid}/runs/{rid}/cancel
    +GET    /threads/{tid}/runs/{rid}/join
    +GET    /threads/{tid}/runs/{rid}/stream  # join_stream
    +
    +# Stateless runs
    +POST   /runs
    +POST   /runs/stream
    +POST   /runs/wait
    +
    +# Assistants
    +POST   /assistants
    +POST   /assistants/search
    +GET    /assistants/{id}
    +PATCH  /assistants/{id}
    +DELETE /assistants/{id}
    +GET    /assistants/{id}/versions
    +
    +# Crons
    +POST   /runs/crons
    +POST   /threads/{tid}/runs/crons
    +POST   /runs/crons/search
    +DELETE /runs/crons/{cid}
    +
    +# Store
    +PUT    /store/items
    +GET    /store/items
    +DELETE /store/items
    +POST   /store/items/search
    +POST   /store/namespaces
    +
    +# Health
    +GET    /ok
    + +

    Variáveis-chave Standalone Server

    +
    + + + + + + + + +
    VariávelFunção
    DATABASE_URIPostgres ≥ 14 (checkpoints, assistants, threads, runs, crons, store)
    REDIS_URIRedis ≥ 6 (pubsub para fan-out de streaming)
    LANGGRAPH_CLOUD_LICENSE_KEYLicença Enterprise
    LANGSMITH_API_KEYPush para LangSmith / tracing
    LG_WEBHOOK_*Variáveis seguras interpoláveis em headers de webhook
    +
    + +
    +
    + + + + + diff --git a/references/agents_tools_best_guides/guia_langgraph_orquestracao.html b/references/agents_tools_best_guides/guia_langgraph_orquestracao.html index ffeda7d..9e281a4 100644 --- a/references/agents_tools_best_guides/guia_langgraph_orquestracao.html +++ b/references/agents_tools_best_guides/guia_langgraph_orquestracao.html @@ -1,911 +1,911 @@ - - - - - -Orquestração com LangGraph — Guia complementar - - - - - - - - -
    -
    -
    Orquestração com LangGraph guia complementar de orquestração
    -
    - Verificado em 2026-07-09 - langgraph 1.2.8 - Python - -
    -
    -
    - -
    - - -
    - -
    -

    Orquestração com LangGraph

    -

    - Este guia mostra como aplicar os padrões de orquestração do núcleo — ledger - canônico, estado durável, HITL, fan-out e multi-agente — usando LangGraph - (langgraph 1.x GA). O StateGraph tipado é o ledger; os - checkpointers são a persistência durável; interrupt()/Command - são o HITL. Complementa o guia de referência da API; aqui o foco é o mapeamento - arquitetural. Prosa em PT-BR; código e identificadores em inglês. -

    -
    - langgraph 1.2.8 - Python - SOTA · verificado 2026-06-29 -
    -
    - -
    -

    Sobre este guia

    -

    - LangGraph modela um agente como um grafo de estado: nós que leem e escrevem um - estado tipado, arestas que decidem o próximo nó, e um runtime que persiste tudo a cada passo. Se - o Agents SDK esconde o loop, o LangGraph o expõe — o que o torna a base certa quando - você precisa de controle explícito, durabilidade e replay. -

    -
    - Como ler: os fundamentos de cada primitiva (StateGraph, reducers, Send, - Command, checkpointers, interrupt, Store, supervisor/swarm, time-travel, durable execution e o - receituário R1–R14) estão em guia_langgraph.html. Para o - harness Deep Agents sobre LangGraph, ver guia_deepagents.html. - Aqui assumimos os fundamentos e mostramos como mapear os padrões agnósticos. -
    -
    - Onde os conceitos vivem: padrões agnósticos em - guia_arquitetura_orquestracao.html; contrato de - estado durável e compaction em - guia_estado_contexto_memoria.html; HITL como - operação em guia_operacao_seguranca_evals.html. -
    -
    - -
    -

    Fontes & verificação

    -

    - APIs conferidas contra a referência oficial (reference.langchain.com / docs.langchain.com) e a - folha de fatos do projeto, re-conferida em 2026-07-05. Versões: langgraph 1.2.7 (PyPI, 2026-06-30), - langgraph-checkpoint-postgres 3.1.0 (PyPI). -

    -
    - - - - - - - -
    Recurso oficialURLUso aqui
    LangGraph (docs)docs.langchain.com/oss/python/langgraphStateGraph, persistência, HITL, streaming
    API reference (Python)reference.langchain.com/python/langgraphget_store, InMemoryStore, interrupt
    langgraph-supervisor.../langgraph-supervisorcreate_supervisor
    langgraph-swarm.../langgraph-swarmcreate_swarm, create_handoff_tool
    -

    - Legenda dos selos: Verificado confirmado na doc oficial · - Novo recente · - Atenção ressalva · - N/D não documentado. -

    -
    - -
    -

    1. Quando LangGraph é a base

    -

    - LangGraph é uma base recomendada — não a única. Escolha-o quando o problema pede - um grafo de estado explícito, persistência durável com checkpoints versionados, time-travel e - HITL nativo por interrupção. Para um loop leve no ecossistema OpenAI, o Agents SDK é mais direto; - para runtime poliglota com A2A nativo, o Google ADK. O blueprint do núcleo é o mesmo nas três. -

    -
    - - - - - - -
    Se você precisa de…Base recomendadaPor quê
    Grafo de estado explícito, checkpoints duráveis, time-travel, HITL por interrupção, durable executionLangGraph este guiaEstado tipado de primeira classe; persistência e replay nativos.
    Loop leve no ecossistema OpenAI, handoffs + guardrails embutidosOpenAI Agents SDKVer guia_agents_sdk_orquestracao.html.
    Runtime poliglota, workflow de grafo do provider, A2A nativo, deploy gerenciado no GCPGoogle ADKVer guia_google_adk_orquestracao.html.
    -
    - Vantagem-chave do LangGraph: como o estado é explícito e persistido, você ganha - de graça três coisas que o núcleo pede — ledger reidratável, replay/time-travel e durabilidade - contra falhas. Ver padrões - por maturidade. -
    -
    - -
    -

    2. StateGraph + reducers como ledger canônico

    -

    - No núcleo, o ledger canônico é a fonte da verdade: itens tipados que são - reduzidos e projetados. No LangGraph, o estado do grafo é esse ledger. Você - declara um schema tipado (TypedDict) e, para campos que acumulam em vez de - sobrescrever, anexa um reducer via Annotated[tipo, reducer]. Cada - nó retorna um delta; o reducer decide como ele se funde ao estado — exatamente o ciclo - "registrar → reduzir" do núcleo. -

    - -
    import operator
    -from typing import Annotated, TypedDict
    -from langgraph.graph import StateGraph, START, END
    -from langgraph.graph.message import add_messages
    -
    -class AgentState(TypedDict):
    -    # 'messages' acumula (reducer add_messages); 'step' sobrescreve (sem reducer).
    -    messages: Annotated[list, add_messages]
    -    findings: Annotated[list[str], operator.add]   # cada nó faz append, não overwrite
    -    step: int
    -
    -def plan(state: AgentState) -> dict:
    -    # Retorna apenas o DELTA — o reducer funde ao ledger.
    -    return {"findings": ["planned 3 subtasks"], "step": state["step"] + 1}
    -
    -builder = StateGraph(AgentState)
    -builder.add_node("plan", plan)
    -builder.add_edge(START, "plan")
    -builder.add_edge("plan", END)
    -graph = builder.compile()
    -
    -result = graph.invoke({"messages": [], "findings": [], "step": 0})
    - - -
    - Reducer = regra de fusão do ledger. add_messages para histórico de - mensagens; operator.add para listas que acumulam; sem reducer = overwrite. Esta é a - materialização direta de "registrar e reduzir" — ver - ledger canônico. -
    -
    - -
    -

    3. Checkpointers como estado durável

    -

    - O núcleo separa estado durável de payload volátil. No LangGraph, o checkpointer - é a persistência durável: a cada super-passo do grafo, o estado completo é salvo sob um - thread_id. Isso dá reidratação, retomada após falha e time-travel sem código extra. - Para produção, use PostgresSaver; para dev/teste, InMemorySaver ou - SqliteSaver. -

    - -
    -
    - - -
    -
    -
    from langgraph.checkpoint.memory import InMemorySaver
    -
    -graph = builder.compile(checkpointer=InMemorySaver())
    -
    -# thread_id define o "fio" persistente do estado (uma conversa/sessão).
    -config = {"configurable": {"thread_id": "session-42"}}
    -graph.invoke({"messages": [("user", "oi")], "findings": [], "step": 0}, config)
    -graph.invoke({"messages": [("user", "continua")]}, config)  # retoma o mesmo estado
    -
    -
    -
    # Persistência durável em Postgres (verificado: langgraph-checkpoint-postgres 3.1.0)
    -# PostgresSaver exige um driver psycopg utilizável — sem ele, o import levanta ImportError.
    -pip install "langgraph==1.2.7" "langgraph-checkpoint-postgres==3.1.0" "psycopg[binary,pool]"
    -
    -
    -
    # Produção: PostgresSaver (estado sobrevive a reinícios e falhas)
    -from langgraph.checkpoint.postgres import PostgresSaver
    -
    -DB_URI = ...  # vem da config/secret manager — nunca hardcode credenciais
    -with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
    -    checkpointer.setup()                       # cria as tabelas na primeira vez
    -    graph = builder.compile(checkpointer=checkpointer)
    -    graph.invoke(initial_state, {"configurable": {"thread_id": "session-42"}})
    - - -
    - Contrato de estado: o checkpointer é a projeção persistida do ledger; - a teoria de compaction/reidratação (o que pode e o que não pode ser perdido) está em - compaction e - reidratação. Time-travel/replay: ver - tracing, replay e cost - ledger. -
    -
    - -
    -

    Padrões de orquestração no grafo

    -

    - Com estado tipado + checkpointer no lugar, os padrões do núcleo viram construções de grafo: - HITL é uma interrupção; composição é um subgraph; multi-agente é supervisor ou swarm; observar o - loop é streaming; memória entre threads é o Store. -

    -
    - -
    -

    4. HITL: interrupt() & Command(resume=)

    -

    - O fluxo de aprovação humana do núcleo (HITL) é nativo: dentro de um nó, chame - interrupt(payload) para pausar o grafo e devolver o controle. O estado é - persistido pelo checkpointer; quando o humano responde, você retoma com - Command(resume=valor) usando o mesmo thread_id. O valor de resume vira - o retorno do interrupt() — a execução continua exatamente de onde parou. -

    - -
    from langgraph.types import interrupt, Command
    -
    -def approve_refund(state: AgentState) -> dict:
    -    decision = interrupt({                       # PAUSA aqui; estado é persistido
    -        "question": "Approve refund?",
    -        "amount": state.get("amount"),
    -    })
    -    if decision != "approve":
    -        return {"findings": ["refund denied by human"]}
    -    return {"findings": ["refund approved"]}
    -
    -graph = builder.compile(checkpointer=InMemorySaver())
    -config = {"configurable": {"thread_id": "ticket-9"}}
    -
    -# 1) Roda até a interrupção:
    -graph.invoke(initial_state, config)
    -# 2) Detecta o interrupt no stream/estado e mostra ao humano (chave __interrupt__).
    -# 3) Retoma com a decisão humana:
    -graph.invoke(Command(resume="approve"), config)
    - - -
    - Por que isso é robusto: como o estado fica no checkpointer, a pausa pode durar - segundos ou dias — o processo pode até reiniciar. É o contrato HITL do núcleo - (fluxo de aprovação) com - durabilidade real. Em stream, detecte a pausa pela chave __interrupt__ no chunk de - updates. -
    -
    - -
    -

    5. Subgraphs como composição

    -

    - O núcleo recomenda compor capacidades em unidades isoláveis. No LangGraph, um subgraph - é um grafo compilado usado como nó de outro grafo. Se os schemas de estado compartilham as chaves - relevantes, basta adicionar o subgraph compilado como nó; senão, embrulhe-o em uma função que - traduz o estado (o equivalente ao delegation packet do núcleo). -

    - -
    # Subgraph: uma sub-rotina de pesquisa, compilada independentemente.
    -research_graph = research_builder.compile()
    -
    -# Grafo pai: usa o subgraph como um nó (estados compartilham chaves).
    -parent = StateGraph(AgentState)
    -parent.add_node("research", research_graph)        # subgraph como nó
    -parent.add_node("write", write_node)
    -parent.add_edge(START, "research")
    -parent.add_edge("research", "write")
    -parent.add_edge("write", END)
    -app = parent.compile(checkpointer=InMemorySaver())
    - -
    - Fan-out: para disparar a mesma sub-rotina em paralelo sobre N itens - (map-reduce), use Send — ver o detalhe em - guia_langgraph.html (seção Send) e o padrão agnóstico - em fan-out e wind-down. -
    -
    - -
    -

    6. Multi-agente: supervisor & swarm

    -

    - O núcleo distingue handoff (transferir o dono do turno) de - agent-as-tool (delegar e continuar no comando). O LangGraph oferece dois pacotes - prebuilt que materializam topologias multi-agente: -

    -
      -
    • Supervisor (langgraph-supervisor): um agente coordenador - roteia para especialistas via tools de handoff e retoma o controle depois — é o padrão - "manager" do núcleo.
    • -
    • Swarm (langgraph-swarm): agentes transferem controle - diretamente entre si (handoff peer-to-peer); o último agente ativo é lembrado por thread.
    • -
    - -

    Supervisor (coordenador retoma o controle)

    -
    from langgraph_supervisor import create_supervisor
    -from langgraph.prebuilt import create_react_agent
    -
    -# Especialistas (model resolvido por config — não hardcode o slug).
    -math_agent = create_react_agent(model=MODEL, tools=[add], name="math_expert")
    -research_agent = create_react_agent(model=MODEL, tools=[web_search], name="research_expert")
    -
    -workflow = create_supervisor(
    -    [research_agent, math_agent],
    -    model=SUPERVISOR_MODEL,                 # o modelo do coordenador, vindo da config
    -    output_mode="last_message",             # default; ou "full_history"
    -)
    -app = workflow.compile()                     # adicione checkpointer= para durabilidade
    -result = app.invoke({"messages": [{"role": "user", "content": "combined headcount of FAANG 2024?"}]})
    - - -

    Swarm (handoff peer-to-peer)

    -
    from langgraph_swarm import create_swarm, create_handoff_tool
    -from langgraph.prebuilt import create_react_agent
    -
    -alice = create_react_agent(
    -    model=MODEL, name="Alice", tools=[add,
    -        create_handoff_tool(agent_name="Bob", description="Transfer to Bob")],
    -)
    -bob = create_react_agent(
    -    model=MODEL, name="Bob",
    -    tools=[create_handoff_tool(agent_name="Alice", description="Transfer to Alice for math")],
    -)
    -
    -workflow = create_swarm([alice, bob], default_active_agent="Alice")
    -app = workflow.compile(checkpointer=InMemorySaver())
    -# A tool de handoff é nomeada transfer_to_<agent_name> por padrão.
    - - -
    - - - - - - -
    Padrão do núcleoNo LangGraphQuem retoma o turno
    Manager / delegação centralcreate_supervisor(...)O supervisor (volta a ele)
    Handoff peer-to-peercreate_swarm(...) + create_handoff_toolO agente que recebeu o handoff
    Agent-as-tool puroCompilar o subgrafo e expô-lo como toolO chamador
    -
    - Deprecação (LangGraph v1): langgraph.prebuilt.create_react_agent - foi deprecado em favor de from langchain.agents import create_agent. Os exemplos - de create_supervisor/create_swarm acima ainda usam - create_react_agent (continua funcional com aviso @deprecated); código - novo deve usar create_agent(model, tools, system_prompt=…). Ver - guia_langgraph.html para a tabela completa de deprecações v1. -
    -
    - -
    -

    7. Streaming v2

    -

    - Observar o loop enquanto acontece (fan-out/wind-down visível, UX responsiva) é - graph.stream(...). Os modos determinam o que você recebe — combine - vários numa lista: -

    -
    - - - - - - - - -
    stream_modeO que emite
    valuesSnapshot completo do estado a cada passo.
    updatesSó as chaves alteradas por nó (e __interrupt__ em HITL).
    messagesTuplas (chunk, metadata) de tokens do LLM.
    customDados emitidos por você via get_stream_writer().
    tasksEventos de início/fim de tarefas (nós).
    - -
    for mode, chunk in graph.stream(
    -    initial_state,
    -    config={"configurable": {"thread_id": "s-1"}},
    -    stream_mode=["updates", "messages"],     # múltiplos modos
    -):
    -    if mode == "messages":
    -        token, meta = chunk
    -        print(token.content, end="", flush=True)
    -    elif mode == "updates":
    -        if "__interrupt__" in chunk:          # HITL pausou o grafo
    -            handle_human_review(chunk["__interrupt__"])
    - -
    - -
    -

    8. Store: memória cross-thread

    -

    - O checkpointer guarda o estado de um thread. Para memória entre threads - (perfis de usuário, fatos persistentes que sobrevivem a sessões), use o Store — a - materialização da "memória de longo prazo" do núcleo. Você compila o grafo com - store= e, dentro de qualquer nó, acessa-o por get_store(). Itens são - organizados por namespace (tupla) + key. -

    - -
    from langgraph.store.memory import InMemoryStore
    -from langgraph.config import get_store
    -
    -store = InMemoryStore()
    -store.put(("users",), "user_123", {"name": "Alice", "tier": "pro"})
    -
    -def personalize(state: AgentState) -> dict:
    -    my_store = get_store()                                   # acessa o Store de dentro do nó
    -    item = my_store.get(("users",), "user_123")
    -    name = item.value["name"] if item else "unknown"
    -    return {"findings": [f"greeting for {name}"]}
    -
    -graph = (
    -    StateGraph(AgentState)
    -    .add_node("personalize", personalize)
    -    .add_edge(START, "personalize")
    -    .compile(store=store, checkpointer=InMemorySaver())      # store= habilita get_store()
    -)
    - -
    - Para produção: use PostgresStore (busca semântica opcional). O - contrato de memória vs estado de sessão está em - modos de estado. -
    -
    - -
    -

    9. Mapeando o blueprint do núcleo ao grafo

    -

    Tabela-âncora: cada camada do blueprint SOTA e sua materialização no LangGraph.

    -
    - - - - - - - - - - - - - -
    Camada do núcleoNo LangGraphStatus
    Estado durável (ledger canônico)StateGraph tipado + reducers; checkpointer persistenativo
    Router / triagemConditional edges / Command(goto=)nativo
    Manager / multi-agentecreate_supervisor (coordenador retoma)nativo
    Handoff peer-to-peercreate_swarm + create_handoff_toolnativo
    Capability registryTools nos nós/ReAct; MCP via adapternativo
    HITL (aprovação)interrupt() + Command(resume=)nativo
    ComposiçãoSubgraphs (grafo compilado como nó)nativo
    Fan-out / wind-downSend (map-reduce) + streamingnativo
    Observer / replayStreaming v2 + checkpoints (time-travel)nativo
    Memória de longo prazoStore (cross-thread)nativo
    -
    - Resumo: o que no Agents SDK é configuração do Runner, no LangGraph - é topologia do grafo. A vantagem é durabilidade e controle explícitos; o custo é mais cerimônia - de montagem. Escolha pela necessidade de estado durável e replay. -
    -
    - -
    -

    Cheat sheet — imports, classes & decisões

    -

    Imports essenciais

    -
    # Grafo e estado
    -from langgraph.graph import StateGraph, START, END
    -from langgraph.graph.message import add_messages
    -from typing import Annotated, TypedDict
    -# HITL e roteamento
    -from langgraph.types import interrupt, Command
    -# Persistência
    -from langgraph.checkpoint.memory import InMemorySaver
    -from langgraph.checkpoint.postgres import PostgresSaver     # langgraph-checkpoint-postgres
    -# Memória cross-thread
    -from langgraph.store.memory import InMemoryStore
    -from langgraph.config import get_store, get_stream_writer
    -# Multi-agente (pacotes prebuilt)
    -from langgraph_supervisor import create_supervisor
    -from langgraph_swarm import create_swarm, create_handoff_tool
    -from langgraph.prebuilt import create_react_agent
    - -

    Decisão rápida

    -
      -
    • ☐ Estado precisa acumular (não overwrite) → Annotated[tipo, reducer].
    • -
    • ☐ Precisa sobreviver a reinícios/falhas → compile(checkpointer=PostgresSaver(...)).
    • -
    • ☐ Precisa de aprovação humana no meio → interrupt() + Command(resume=).
    • -
    • ☐ Coordenador que delega e retoma → create_supervisor(...).
    • -
    • ☐ Agentes que transferem entre si → create_swarm(...).
    • -
    • ☐ Memória entre sessões/usuários → Store + get_store().
    • -
    • ☐ UX em tempo real → graph.stream(stream_mode=["updates","messages"]).
    • -
    -
    - -
    -

    Notas de verificação

    -

    APIs conferidas contra a referência oficial LangChain/LangGraph e a folha de fatos do projeto em 2026-06-10.

    -
      -
    • Resolvido langgraph 1.2.7 e langgraph-checkpoint-postgres 3.1.0 (PyPI, re-conferidos em 2026-07-05). LangGraph é 1.x GA (não 0.x).
    • -
    • Resolvido StateGraph, START/END, reducers via Annotated, add_messages.
    • -
    • Resolvido interrupt() + Command(resume=) (de langgraph.types); detecção por __interrupt__ no stream de updates.
    • -
    • Resolvido InMemoryStore (de langgraph.store.memory), store.put((ns,), key, value), store.get((ns,), key).value, get_store() (de langgraph.config), compile(store=) — confirmados na ref oficial em 2026-05-25 (resolve o item UNVERIFIED da folha §11).
    • -
    • Resolvido create_supervisor(agents, *, model, prompt=, output_mode='last_message', handoff_tool_prefix=, supervisor_name='supervisor') (de langgraph_supervisor) — assinatura confirmada na ref oficial (resolve UNVERIFIED §11).
    • -
    • Resolvido create_swarm(agents, *, default_active_agent, state_schema=SwarmState) + create_handoff_tool(agent_name=, name=, description=) → tool transfer_to_<agent_name> (de langgraph_swarm) — confirmados na ref oficial (resolve UNVERIFIED §11).
    • -
    • Resolvido Streaming v2: modos values | updates | messages | custom | tasks; get_stream_writer() de langgraph.config.
    • -
    • Atenção Prebuilt: a ref oficial expõe langchain.agents.create_agent como o mais novo; create_react_agent (de langgraph.prebuilt) segue válido e é o usado nos exemplos de supervisor. Use o que casa com a versão pinada do seu projeto (reconferido na ref oficial em 2026-06-10).
    • -
    • Atenção Slugs de modelo NÃO são hardcoded (MODEL/SUPERVISOR_MODEL vêm da config). Para IDs vigentes, ver a folha SOTA do projeto e o portal.
    • -
    -
    - APIs UNVERIFIED neste guia: nenhuma. Os 3 itens que a folha §11 listava como - UNVERIFIED (Store, supervisor, swarm) foram confirmados ao vivo na referência oficial - (reference.langchain.com) em 2026-06-10. -
    -
    - -
    -
    - - - - - - + + + + + +Orquestração com LangGraph — Guia complementar + + + + + + + + +
    +
    +
    Orquestração com LangGraph guia complementar de orquestração
    +
    + Verificado em 2026-07-12 + langgraph 1.2.9 + Python + +
    +
    +
    + +
    + + +
    + +
    +

    Orquestração com LangGraph

    +

    + Este guia mostra como aplicar os padrões de orquestração do núcleo — ledger + canônico, estado durável, HITL, fan-out e multi-agente — usando LangGraph + (langgraph 1.x GA). O StateGraph tipado é o ledger; os + checkpointers são a persistência durável; interrupt()/Command + são o HITL. Complementa o guia de referência da API; aqui o foco é o mapeamento + arquitetural. Prosa em PT-BR; código e identificadores em inglês. +

    +
    + langgraph 1.2.9 + Python + SOTA · verificado 2026-06-29 +
    +
    + +
    +

    Sobre este guia

    +

    + LangGraph modela um agente como um grafo de estado: nós que leem e escrevem um + estado tipado, arestas que decidem o próximo nó, e um runtime que persiste tudo a cada passo. Se + o Agents SDK esconde o loop, o LangGraph o expõe — o que o torna a base certa quando + você precisa de controle explícito, durabilidade e replay. +

    +
    + Como ler: os fundamentos de cada primitiva (StateGraph, reducers, Send, + Command, checkpointers, interrupt, Store, supervisor/swarm, time-travel, durable execution e o + receituário R1–R14) estão em guia_langgraph.html. Para o + harness Deep Agents sobre LangGraph, ver guia_deepagents.html. + Aqui assumimos os fundamentos e mostramos como mapear os padrões agnósticos. +
    +
    + Onde os conceitos vivem: padrões agnósticos em + guia_arquitetura_orquestracao.html; contrato de + estado durável e compaction em + guia_estado_contexto_memoria.html; HITL como + operação em guia_operacao_seguranca_evals.html. +
    +
    + +
    +

    Fontes & verificação

    +

    + APIs conferidas contra a referência oficial (reference.langchain.com / docs.langchain.com) e a + folha de fatos do projeto, re-conferida em 2026-07-12. Versões: langgraph 1.2.9 (PyPI, 2026-07-10), + langgraph-checkpoint-postgres 3.1.0 (PyPI). +

    +
    + + + + + + + +
    Recurso oficialURLUso aqui
    LangGraph (docs)docs.langchain.com/oss/python/langgraphStateGraph, persistência, HITL, streaming
    API reference (Python)reference.langchain.com/python/langgraphget_store, InMemoryStore, interrupt
    langgraph-supervisor.../langgraph-supervisorcreate_supervisor
    langgraph-swarm.../langgraph-swarmcreate_swarm, create_handoff_tool
    +

    + Legenda dos selos: Verificado confirmado na doc oficial · + Novo recente · + Atenção ressalva · + N/D não documentado. +

    +
    + +
    +

    1. Quando LangGraph é a base

    +

    + LangGraph é uma base recomendada — não a única. Escolha-o quando o problema pede + um grafo de estado explícito, persistência durável com checkpoints versionados, time-travel e + HITL nativo por interrupção. Para um loop leve no ecossistema OpenAI, o Agents SDK é mais direto; + para runtime poliglota com A2A nativo, o Google ADK. O blueprint do núcleo é o mesmo nas três. +

    +
    + + + + + + +
    Se você precisa de…Base recomendadaPor quê
    Grafo de estado explícito, checkpoints duráveis, time-travel, HITL por interrupção, durable executionLangGraph este guiaEstado tipado de primeira classe; persistência e replay nativos.
    Loop leve no ecossistema OpenAI, handoffs + guardrails embutidosOpenAI Agents SDKVer guia_agents_sdk_orquestracao.html.
    Runtime poliglota, workflow de grafo do provider, A2A nativo, deploy gerenciado no GCPGoogle ADKVer guia_google_adk_orquestracao.html.
    +
    + Vantagem-chave do LangGraph: como o estado é explícito e persistido, você ganha + de graça três coisas que o núcleo pede — ledger reidratável, replay/time-travel e durabilidade + contra falhas. Ver padrões + por maturidade. +
    +
    + +
    +

    2. StateGraph + reducers como ledger canônico

    +

    + No núcleo, o ledger canônico é a fonte da verdade: itens tipados que são + reduzidos e projetados. No LangGraph, o estado do grafo é esse ledger. Você + declara um schema tipado (TypedDict) e, para campos que acumulam em vez de + sobrescrever, anexa um reducer via Annotated[tipo, reducer]. Cada + nó retorna um delta; o reducer decide como ele se funde ao estado — exatamente o ciclo + "registrar → reduzir" do núcleo. +

    + +
    import operator
    +from typing import Annotated, TypedDict
    +from langgraph.graph import StateGraph, START, END
    +from langgraph.graph.message import add_messages
    +
    +class AgentState(TypedDict):
    +    # 'messages' acumula (reducer add_messages); 'step' sobrescreve (sem reducer).
    +    messages: Annotated[list, add_messages]
    +    findings: Annotated[list[str], operator.add]   # cada nó faz append, não overwrite
    +    step: int
    +
    +def plan(state: AgentState) -> dict:
    +    # Retorna apenas o DELTA — o reducer funde ao ledger.
    +    return {"findings": ["planned 3 subtasks"], "step": state["step"] + 1}
    +
    +builder = StateGraph(AgentState)
    +builder.add_node("plan", plan)
    +builder.add_edge(START, "plan")
    +builder.add_edge("plan", END)
    +graph = builder.compile()
    +
    +result = graph.invoke({"messages": [], "findings": [], "step": 0})
    + + +
    + Reducer = regra de fusão do ledger. add_messages para histórico de + mensagens; operator.add para listas que acumulam; sem reducer = overwrite. Esta é a + materialização direta de "registrar e reduzir" — ver + ledger canônico. +
    +
    + +
    +

    3. Checkpointers como estado durável

    +

    + O núcleo separa estado durável de payload volátil. No LangGraph, o checkpointer + é a persistência durável: a cada super-passo do grafo, o estado completo é salvo sob um + thread_id. Isso dá reidratação, retomada após falha e time-travel sem código extra. + Para produção, use PostgresSaver; para dev/teste, InMemorySaver ou + SqliteSaver. +

    + +
    +
    + + +
    +
    +
    from langgraph.checkpoint.memory import InMemorySaver
    +
    +graph = builder.compile(checkpointer=InMemorySaver())
    +
    +# thread_id define o "fio" persistente do estado (uma conversa/sessão).
    +config = {"configurable": {"thread_id": "session-42"}}
    +graph.invoke({"messages": [("user", "oi")], "findings": [], "step": 0}, config)
    +graph.invoke({"messages": [("user", "continua")]}, config)  # retoma o mesmo estado
    +
    +
    +
    # Persistência durável em Postgres (verificado: langgraph-checkpoint-postgres 3.1.0)
    +# PostgresSaver exige um driver psycopg utilizável — sem ele, o import levanta ImportError.
    +pip install "langgraph==1.2.9" "langgraph-checkpoint-postgres==3.1.0" "psycopg[binary,pool]"
    +
    +
    +
    # Produção: PostgresSaver (estado sobrevive a reinícios e falhas)
    +from langgraph.checkpoint.postgres import PostgresSaver
    +
    +DB_URI = ...  # vem da config/secret manager — nunca hardcode credenciais
    +with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
    +    checkpointer.setup()                       # cria as tabelas na primeira vez
    +    graph = builder.compile(checkpointer=checkpointer)
    +    graph.invoke(initial_state, {"configurable": {"thread_id": "session-42"}})
    + + +
    + Contrato de estado: o checkpointer é a projeção persistida do ledger; + a teoria de compaction/reidratação (o que pode e o que não pode ser perdido) está em + compaction e + reidratação. Time-travel/replay: ver + tracing, replay e cost + ledger. +
    +
    + +
    +

    Padrões de orquestração no grafo

    +

    + Com estado tipado + checkpointer no lugar, os padrões do núcleo viram construções de grafo: + HITL é uma interrupção; composição é um subgraph; multi-agente é supervisor ou swarm; observar o + loop é streaming; memória entre threads é o Store. +

    +
    + +
    +

    4. HITL: interrupt() & Command(resume=)

    +

    + O fluxo de aprovação humana do núcleo (HITL) é nativo: dentro de um nó, chame + interrupt(payload) para pausar o grafo e devolver o controle. O estado é + persistido pelo checkpointer; quando o humano responde, você retoma com + Command(resume=valor) usando o mesmo thread_id. O valor de resume vira + o retorno do interrupt() — a execução continua exatamente de onde parou. +

    + +
    from langgraph.types import interrupt, Command
    +
    +def approve_refund(state: AgentState) -> dict:
    +    decision = interrupt({                       # PAUSA aqui; estado é persistido
    +        "question": "Approve refund?",
    +        "amount": state.get("amount"),
    +    })
    +    if decision != "approve":
    +        return {"findings": ["refund denied by human"]}
    +    return {"findings": ["refund approved"]}
    +
    +graph = builder.compile(checkpointer=InMemorySaver())
    +config = {"configurable": {"thread_id": "ticket-9"}}
    +
    +# 1) Roda até a interrupção:
    +graph.invoke(initial_state, config)
    +# 2) Detecta o interrupt no stream/estado e mostra ao humano (chave __interrupt__).
    +# 3) Retoma com a decisão humana:
    +graph.invoke(Command(resume="approve"), config)
    + + +
    + Por que isso é robusto: como o estado fica no checkpointer, a pausa pode durar + segundos ou dias — o processo pode até reiniciar. É o contrato HITL do núcleo + (fluxo de aprovação) com + durabilidade real. Em stream, detecte a pausa pela chave __interrupt__ no chunk de + updates. +
    +
    + +
    +

    5. Subgraphs como composição

    +

    + O núcleo recomenda compor capacidades em unidades isoláveis. No LangGraph, um subgraph + é um grafo compilado usado como nó de outro grafo. Se os schemas de estado compartilham as chaves + relevantes, basta adicionar o subgraph compilado como nó; senão, embrulhe-o em uma função que + traduz o estado (o equivalente ao delegation packet do núcleo). +

    + +
    # Subgraph: uma sub-rotina de pesquisa, compilada independentemente.
    +research_graph = research_builder.compile()
    +
    +# Grafo pai: usa o subgraph como um nó (estados compartilham chaves).
    +parent = StateGraph(AgentState)
    +parent.add_node("research", research_graph)        # subgraph como nó
    +parent.add_node("write", write_node)
    +parent.add_edge(START, "research")
    +parent.add_edge("research", "write")
    +parent.add_edge("write", END)
    +app = parent.compile(checkpointer=InMemorySaver())
    + +
    + Fan-out: para disparar a mesma sub-rotina em paralelo sobre N itens + (map-reduce), use Send — ver o detalhe em + guia_langgraph.html (seção Send) e o padrão agnóstico + em fan-out e wind-down. +
    +
    + +
    +

    6. Multi-agente: supervisor & swarm

    +

    + O núcleo distingue handoff (transferir o dono do turno) de + agent-as-tool (delegar e continuar no comando). O LangGraph oferece dois pacotes + prebuilt que materializam topologias multi-agente: +

    +
      +
    • Supervisor (langgraph-supervisor): um agente coordenador + roteia para especialistas via tools de handoff e retoma o controle depois — é o padrão + "manager" do núcleo.
    • +
    • Swarm (langgraph-swarm): agentes transferem controle + diretamente entre si (handoff peer-to-peer); o último agente ativo é lembrado por thread.
    • +
    + +

    Supervisor (coordenador retoma o controle)

    +
    from langgraph_supervisor import create_supervisor
    +from langgraph.prebuilt import create_react_agent
    +
    +# Especialistas (model resolvido por config — não hardcode o slug).
    +math_agent = create_react_agent(model=MODEL, tools=[add], name="math_expert")
    +research_agent = create_react_agent(model=MODEL, tools=[web_search], name="research_expert")
    +
    +workflow = create_supervisor(
    +    [research_agent, math_agent],
    +    model=SUPERVISOR_MODEL,                 # o modelo do coordenador, vindo da config
    +    output_mode="last_message",             # default; ou "full_history"
    +)
    +app = workflow.compile()                     # adicione checkpointer= para durabilidade
    +result = app.invoke({"messages": [{"role": "user", "content": "combined headcount of FAANG 2024?"}]})
    + + +

    Swarm (handoff peer-to-peer)

    +
    from langgraph_swarm import create_swarm, create_handoff_tool
    +from langgraph.prebuilt import create_react_agent
    +
    +alice = create_react_agent(
    +    model=MODEL, name="Alice", tools=[add,
    +        create_handoff_tool(agent_name="Bob", description="Transfer to Bob")],
    +)
    +bob = create_react_agent(
    +    model=MODEL, name="Bob",
    +    tools=[create_handoff_tool(agent_name="Alice", description="Transfer to Alice for math")],
    +)
    +
    +workflow = create_swarm([alice, bob], default_active_agent="Alice")
    +app = workflow.compile(checkpointer=InMemorySaver())
    +# A tool de handoff é nomeada transfer_to_<agent_name> por padrão.
    + + +
    + + + + + + +
    Padrão do núcleoNo LangGraphQuem retoma o turno
    Manager / delegação centralcreate_supervisor(...)O supervisor (volta a ele)
    Handoff peer-to-peercreate_swarm(...) + create_handoff_toolO agente que recebeu o handoff
    Agent-as-tool puroCompilar o subgrafo e expô-lo como toolO chamador
    +
    + Deprecação (LangGraph v1): langgraph.prebuilt.create_react_agent + foi deprecado em favor de from langchain.agents import create_agent. Os exemplos + de create_supervisor/create_swarm acima ainda usam + create_react_agent (continua funcional com aviso @deprecated); código + novo deve usar create_agent(model, tools, system_prompt=…). Ver + guia_langgraph.html para a tabela completa de deprecações v1. +
    +
    + +
    +

    7. Streaming v2

    +

    + Observar o loop enquanto acontece (fan-out/wind-down visível, UX responsiva) é + graph.stream(...). Os modos determinam o que você recebe — combine + vários numa lista: +

    +
    + + + + + + + + +
    stream_modeO que emite
    valuesSnapshot completo do estado a cada passo.
    updatesSó as chaves alteradas por nó (e __interrupt__ em HITL).
    messagesTuplas (chunk, metadata) de tokens do LLM.
    customDados emitidos por você via get_stream_writer().
    tasksEventos de início/fim de tarefas (nós).
    + +
    for mode, chunk in graph.stream(
    +    initial_state,
    +    config={"configurable": {"thread_id": "s-1"}},
    +    stream_mode=["updates", "messages"],     # múltiplos modos
    +):
    +    if mode == "messages":
    +        token, meta = chunk
    +        print(token.content, end="", flush=True)
    +    elif mode == "updates":
    +        if "__interrupt__" in chunk:          # HITL pausou o grafo
    +            handle_human_review(chunk["__interrupt__"])
    + +
    + +
    +

    8. Store: memória cross-thread

    +

    + O checkpointer guarda o estado de um thread. Para memória entre threads + (perfis de usuário, fatos persistentes que sobrevivem a sessões), use o Store — a + materialização da "memória de longo prazo" do núcleo. Você compila o grafo com + store= e, dentro de qualquer nó, acessa-o por get_store(). Itens são + organizados por namespace (tupla) + key. +

    + +
    from langgraph.store.memory import InMemoryStore
    +from langgraph.config import get_store
    +
    +store = InMemoryStore()
    +store.put(("users",), "user_123", {"name": "Alice", "tier": "pro"})
    +
    +def personalize(state: AgentState) -> dict:
    +    my_store = get_store()                                   # acessa o Store de dentro do nó
    +    item = my_store.get(("users",), "user_123")
    +    name = item.value["name"] if item else "unknown"
    +    return {"findings": [f"greeting for {name}"]}
    +
    +graph = (
    +    StateGraph(AgentState)
    +    .add_node("personalize", personalize)
    +    .add_edge(START, "personalize")
    +    .compile(store=store, checkpointer=InMemorySaver())      # store= habilita get_store()
    +)
    + +
    + Para produção: use PostgresStore (busca semântica opcional). O + contrato de memória vs estado de sessão está em + modos de estado. +
    +
    + +
    +

    9. Mapeando o blueprint do núcleo ao grafo

    +

    Tabela-âncora: cada camada do blueprint SOTA e sua materialização no LangGraph.

    +
    + + + + + + + + + + + + + +
    Camada do núcleoNo LangGraphStatus
    Estado durável (ledger canônico)StateGraph tipado + reducers; checkpointer persistenativo
    Router / triagemConditional edges / Command(goto=)nativo
    Manager / multi-agentecreate_supervisor (coordenador retoma)nativo
    Handoff peer-to-peercreate_swarm + create_handoff_toolnativo
    Capability registryTools nos nós/ReAct; MCP via adapternativo
    HITL (aprovação)interrupt() + Command(resume=)nativo
    ComposiçãoSubgraphs (grafo compilado como nó)nativo
    Fan-out / wind-downSend (map-reduce) + streamingnativo
    Observer / replayStreaming v2 + checkpoints (time-travel)nativo
    Memória de longo prazoStore (cross-thread)nativo
    +
    + Resumo: o que no Agents SDK é configuração do Runner, no LangGraph + é topologia do grafo. A vantagem é durabilidade e controle explícitos; o custo é mais cerimônia + de montagem. Escolha pela necessidade de estado durável e replay. +
    +
    + +
    +

    Cheat sheet — imports, classes & decisões

    +

    Imports essenciais

    +
    # Grafo e estado
    +from langgraph.graph import StateGraph, START, END
    +from langgraph.graph.message import add_messages
    +from typing import Annotated, TypedDict
    +# HITL e roteamento
    +from langgraph.types import interrupt, Command
    +# Persistência
    +from langgraph.checkpoint.memory import InMemorySaver
    +from langgraph.checkpoint.postgres import PostgresSaver     # langgraph-checkpoint-postgres
    +# Memória cross-thread
    +from langgraph.store.memory import InMemoryStore
    +from langgraph.config import get_store, get_stream_writer
    +# Multi-agente (pacotes prebuilt)
    +from langgraph_supervisor import create_supervisor
    +from langgraph_swarm import create_swarm, create_handoff_tool
    +from langgraph.prebuilt import create_react_agent
    + +

    Decisão rápida

    +
      +
    • ☐ Estado precisa acumular (não overwrite) → Annotated[tipo, reducer].
    • +
    • ☐ Precisa sobreviver a reinícios/falhas → compile(checkpointer=PostgresSaver(...)).
    • +
    • ☐ Precisa de aprovação humana no meio → interrupt() + Command(resume=).
    • +
    • ☐ Coordenador que delega e retoma → create_supervisor(...).
    • +
    • ☐ Agentes que transferem entre si → create_swarm(...).
    • +
    • ☐ Memória entre sessões/usuários → Store + get_store().
    • +
    • ☐ UX em tempo real → graph.stream(stream_mode=["updates","messages"]).
    • +
    +
    + +
    +

    Notas de verificação

    +

    APIs conferidas contra a referência oficial LangChain/LangGraph e a folha de fatos do projeto em 2026-06-10; versões de libs re-conferidas em 2026-07-12.

    +
      +
    • Resolvido langgraph 1.2.9 e langgraph-checkpoint-postgres 3.1.0 (PyPI, re-conferidos em 2026-07-12). LangGraph é 1.x GA (não 0.x).
    • +
    • Resolvido StateGraph, START/END, reducers via Annotated, add_messages.
    • +
    • Resolvido interrupt() + Command(resume=) (de langgraph.types); detecção por __interrupt__ no stream de updates.
    • +
    • Resolvido InMemoryStore (de langgraph.store.memory), store.put((ns,), key, value), store.get((ns,), key).value, get_store() (de langgraph.config), compile(store=) — confirmados na ref oficial em 2026-05-25 (resolve o item UNVERIFIED da folha §11).
    • +
    • Resolvido create_supervisor(agents, *, model, prompt=, output_mode='last_message', handoff_tool_prefix=, supervisor_name='supervisor') (de langgraph_supervisor) — assinatura confirmada na ref oficial (resolve UNVERIFIED §11).
    • +
    • Resolvido create_swarm(agents, *, default_active_agent, state_schema=SwarmState) + create_handoff_tool(agent_name=, name=, description=) → tool transfer_to_<agent_name> (de langgraph_swarm) — confirmados na ref oficial (resolve UNVERIFIED §11).
    • +
    • Resolvido Streaming v2: modos values | updates | messages | custom | tasks; get_stream_writer() de langgraph.config.
    • +
    • Atenção Prebuilt: a ref oficial expõe langchain.agents.create_agent como o mais novo; create_react_agent (de langgraph.prebuilt) segue válido e é o usado nos exemplos de supervisor. Use o que casa com a versão pinada do seu projeto (reconferido na ref oficial em 2026-06-10).
    • +
    • Atenção Slugs de modelo NÃO são hardcoded (MODEL/SUPERVISOR_MODEL vêm da config). Para IDs vigentes, ver a folha SOTA do projeto e o portal.
    • +
    +
    + APIs UNVERIFIED neste guia: nenhuma. Os 3 itens que a folha §11 listava como + UNVERIFIED (Store, supervisor, swarm) foram confirmados ao vivo na referência oficial + (reference.langchain.com) em 2026-06-10. +
    +
    + +
    +
    + + + + + + diff --git a/references/agents_tools_best_guides/guia_multimodal.html b/references/agents_tools_best_guides/guia_multimodal.html index c920dc8..4472e78 100644 --- a/references/agents_tools_best_guides/guia_multimodal.html +++ b/references/agents_tools_best_guides/guia_multimodal.html @@ -5,7 +5,7 @@ Guia Multimodal — OpenAI, Gemini e Anthropic (imagens, PDFs, Office, vídeo, áudio, code interpreter) - + - - - - -
    -
    -
    Guia OpenAI PT-BR · Modelos mais recentes & API
    -
    - Verificado em 2026-07-09 - SDK openai - SOTA - -
    -
    -
    - -
    - - -
    - -
    -

    Guia OpenAI — Modelos mais recentes & API

    -

    - Referência técnica exaustiva, em PT-BR, dos modelos OpenAI mais recentes e de - como usá-los: gpt-5.6 (Sol/Terra/Luna) e gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano (texto e raciocínio pela - Responses API), gpt-image-2 (geração e edição de imagens, visão), - áudio e tempo real (gpt-realtime-2.1, gpt-realtime-translate, - gpt-realtime-whisper, gpt-4o-transcribe, - gpt-4o-mini-tts, gpt-audio-1.5), além de embeddings, - moderation, preços, limites e operação. Feito para leitura por humanos e por IA. -

    -
    - SDK openai · Python & JavaScript - Responses API - SOTA · 2026-06-29 -
    -
    - -
    -

    Sobre este guia

    -

    - Este documento reúne, de forma estruturada e navegável, a documentação dos modelos OpenAI - mais recentes e das APIs usadas para acessá-los. O foco é a - Responses API (a interface recomendada para texto, raciocínio, multimodal e - ferramentas), complementada pelas APIs dedicadas de imagem, áudio/realtime, - embeddings e moderation. -

    -

    - O guia é deliberadamente centrado nos modelos atuais: descreve apenas os modelos - de ponta e como utilizá-los, sem comparativos com versões anteriores. Cada seção termina com a - fonte oficial correspondente — para fatos perecíveis (IDs de modelo, parâmetros, - preços e limites), consulte sempre a documentação oficial, pois mudam com frequência. -

    -
    - Como navegar: a barra lateral é um sumário fixo. A Parte A cobre os - modelos de texto/raciocínio e a Responses API; a Parte B, imagem e visão; a - Parte C, áudio e tempo real; e a Parte D, embeddings, moderation, - preços e operação. O apêndice traz uma referência rápida de endpoints e a tabela de IDs de modelo. -
    -
    - Convenções de código: exemplos em Python e JavaScript - usam o SDK oficial openai; exemplos REST usam curl contra - https://api.openai.com/v1/… com Authorization: Bearer $OPENAI_API_KEY. - Use os botões de aba para alternar a linguagem. -
    -
    - -
    -

    Fontes oficiais

    -

    Todo o conteúdo deste guia é derivado da documentação pública oficial da OpenAI, verificada em 2026-06-10:

    -
    - - - - - - - - - - -
    RecursoOnde
    Documentação de plataformaplatform.openai.com/docs
    Documentação para desenvolvedoresdevelopers.openai.com
    Referência da APIplatform.openai.com/docs/api-reference
    Modelosplatform.openai.com/docs/models
    Preçosplatform.openai.com/docs/pricing
    Cookbookcookbook.openai.com
    -
    - -
    - -

    Parte A — Modelos, Texto & Responses API

    Os modelos de raciocínio gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano e como usá-los pela Responses API: texto, reasoning, ferramentas, streaming, estado e caching.

    - - - -
    -

    2. Seleção de modelo

    -

    O princípio é simples: otimize primeiro a acurácia até bater sua meta de qualidade; só então otimize custo e latência mantendo essa acurácia. Comece com o modelo mais capaz, defina uma meta clara, monte um conjunto de evals e só desça para um modelo menor quando ele preservar a qualidade no ponto de custo/latência que você precisa.

    - -

    2.1 Quando usar cada modelo

    -
    - - - - - - - -
    Se você precisa de…Comece comPor quê
    Qualidade máxima em coding, agentes e raciocínio multi-etapagpt-5.5Linha de base de fronteira; melhor seleção e uso de ferramentas, planejamento e execução.
    Bom equilíbrio com custo menorgpt-5.4-miniMantém raciocínio e ferramentas com latência e custo reduzidos para volume alto.
    Latência/custo mínimos em tarefas simplesgpt-5.4-nanoIdeal para classificação, extração e respostas curtas onde a tarefa é bem definida.
    -
    - -
    Dica: num mesmo fluxo, misture modelos por especialista — um agente de triagem rápido em gpt-5.4-mini e um especialista profundo em gpt-5.5 podem coexistir. Defina o modelo explicitamente em produção em vez de depender do default do SDK.
    - -

    Antes de escalar o reasoning.effort, lembre que o gpt-5.5 raciocina de forma mais eficiente, usando menos tokens de raciocínio no mesmo nível de esforço. Em fluxos sensíveis à latência, reavalie low antes de subir para medium/high.

    - - -
    - -
    -

    3. Quickstart & SDKs

    -

    Instale o SDK oficial openai, defina a variável de ambiente OPENAI_API_KEY e faça a primeira chamada com client.responses.create(...). O SDK lê a chave do ambiente automaticamente.

    - -

    3.1 Instalação

    -
    -
    - - - -
    -
    -
    pip install openai
    -export OPENAI_API_KEY="sk-..."
    -
    -
    -
    npm install openai
    -export OPENAI_API_KEY="sk-..."
    -
    -
    -
    # Nenhum SDK necessário; basta a chave no ambiente:
    -export OPENAI_API_KEY="sk-..."
    -
    -
    - -

    3.2 Primeira chamada

    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    input="Escreva um haicai sobre IA confiável.",
    -)
    -
    -print(response.output_text)
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -
    -const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Escreva um haicai sobre IA confiável.",
    -});
    -
    -console.log(response.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "Escreva um haicai sobre IA confiável."
    -  }'
    -
    -
    - -
    Atenção: o array output costuma ter mais de um item (chamadas de ferramenta, itens de reasoning, etc.). Não assuma que o texto está em output[0].content[0].text. Use o atalho output_text dos SDKs, que agrega todo o texto da resposta.
    - - -
    - -
    -

    4. Anatomia da Responses API

    -

    A Responses API (POST /v1/responses) é a primitiva recomendada para todo projeto novo. Ela é um loop agêntico por padrão: numa única requisição o modelo pode chamar várias ferramentas (web search, file search, code interpreter, MCP, suas funções) antes de responder. Trabalha com itens (cada um — message, function_call, reasoning, etc. — é uma unidade distinta de contexto), em vez de mensagens monolíticas.

    - -

    4.1 Campos principais da requisição

    -
    - - - - - - - - - - - - - - - - - - - - - - - -
    CampoTipoDescrição
    modelstringSlug do modelo, ex.: gpt-5.5. Em produção, fixe um snapshot quando precisar de comportamento estável.
    inputstring | arrayO prompt. Pode ser uma string simples ou um array de itens com role (developer/user/assistant) e conteúdo (texto, imagem, arquivo).
    instructionsstringInstruções de alto nível (tom, metas, regras). Têm prioridade sobre o input e valem só para a geração atual.
    reasoningobject{ "effort": "...", "summary": "..." }. Controla o esforço de raciocínio e o resumo de raciocínio. Ver §6.
    textobject{ "verbosity": "...", "format": {...} }. Controla concisão da saída e o formato (Structured Outputs). Ver §7 e §9.
    toolsarrayFerramentas disponíveis: funções suas, ferramentas integradas (web_search, file_search, code_interpreter, mcp, shell, computer, apply_patch, image_generation) e tool_search. Ver §11.
    tool_choicestring | objectauto (padrão), required, none, função forçada, ou allowed_tools. Ver §10.
    previous_response_idstringEncadeia a resposta anterior para conversa multi-turno com estado preservado. Ver §13.
    conversationstringID de um objeto da Conversations API para persistir estado de forma durável.
    storebooleanSe a resposta é armazenada (padrão true; respostas ficam 30 dias). Defina false para fluxos stateless/ZDR.
    streambooleanSe true, transmite eventos SSE conforme a geração avança. Ver §12.
    backgroundbooleanExecuta a tarefa de forma assíncrona (requer store=true). Ver §14.
    max_output_tokensintegerLimita o total de tokens gerados (visíveis + raciocínio), controlando custo.
    includearrayInclui dados extras na saída, ex.: "reasoning.encrypted_content" para fluxos stateless.
    prompt_cache_keystringMelhora o roteamento de cache para requisições com prefixo comum. Ver §15.
    promptobjectUsa um prompt reutilizável salvo no dashboard (id, version, variables). Ver §5.
    metadataobjectAté 16 pares chave-valor para anotar a resposta (chaves ≤ 64 chars, valores ≤ 512 chars).
    safety_identifierstringIdentificador estável e opaco do seu usuário final (ex.: hash do ID), usado pela OpenAI para monitorar abuso e preservar seu acesso caso um usuário viole políticas. Não envie e-mail/nome em claro. (Equivale ao header OpenAI-Safety-Identifier no Realtime — ver §22.)
    moderationobject{ "model": "omni-moderation-latest" }. Retorna scores de moderação da entrada e da saída na mesma resposta, sem chamada separada (novidade de jun/2026; também em Chat Completions). Ver §30.5.
    -
    - -

    4.2 O objeto de resposta

    -

    A resposta traz um objeto tipado com id, status (completed, incomplete, queued, in_progress, failed), output (array de itens), output_text (atalho dos SDKs) e usage. O bloco usage detalha o consumo:

    -
    {
    -  "usage": {
    -    "input_tokens": 75,
    -    "input_tokens_details": { "cached_tokens": 0 },
    -    "output_tokens": 1186,
    -    "output_tokens_details": { "reasoning_tokens": 1024 },
    -    "total_tokens": 1261
    -  }
    -}
    -

    Quando a resposta excede o limite, status volta incomplete com incomplete_details.reason = "max_output_tokens" — possivelmente antes de qualquer texto visível, já consumindo tokens de entrada e raciocínio.

    - - -
    - -
    -

    5. Geração de texto

    -

    Texto é o caso de uso primário. Você fornece um prompt e o modelo gera a resposta no array output; o atalho output_text agrega todo o texto produzido.

    - -

    5.1 Roles e instructions

    -

    Você dirige o modelo com níveis de autoridade. O parâmetro instructions dá orientação de alto nível (tom, metas, exemplos) e tem prioridade sobre o input. Como alternativa, use mensagens com role:

    -
      -
    • developer — regras e lógica de negócio da aplicação (como a definição de uma função). Prioridade acima de user.
    • -
    • user — instruções/entradas do usuário final (como os argumentos da função).
    • -
    • assistant — mensagens geradas pelo modelo.
    • -
    - -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -client = OpenAI()
    -
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    reasoning={"effort": "low"},
    -    instructions="Você é um assistente técnico. Responda em PT-BR, conciso.",
    -    input="Explique embeddings em duas frases.",
    -)
    -
    -print(response.output_text)
    -
    -
    -
    import OpenAI from "openai";
    -const client = new OpenAI();
    -
    -const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  reasoning: { effort: "low" },
    -  instructions: "Você é um assistente técnico. Responda em PT-BR, conciso.",
    -  input: "Explique embeddings em duas frases.",
    -});
    -
    -console.log(response.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "reasoning": { "effort": "low" },
    -    "instructions": "Você é um assistente técnico. Responda em PT-BR, conciso.",
    -    "input": "Explique embeddings em duas frases."
    -  }'
    -
    -
    - -
    Nota: instructions vale só para a geração atual. Se você gerencia estado com previous_response_id, as instruções de turnos anteriores não ficam no contexto — reenvie quando necessário.
    - -

    5.2 Prompts reutilizáveis

    -

    Em vez de embutir o prompt no código, crie um prompt reutilizável no dashboard com placeholders como {{customer_name}} e referencie-o via parâmetro prompt (id, version opcional, e variables). Isso facilita iterar e versionar prompts sem mudar o código de integração.

    -
    -
    - - - -
    -
    -
    response = client.responses.create(
    -    model="gpt-5.5",
    -    prompt={
    -        "id": "pmpt_abc123",
    -        "version": "2",
    -        "variables": {"customer_name": "Jane Doe", "product": "caixa de suco 1,2L"},
    -    },
    -)
    -print(response.output_text)
    -
    -
    -
    const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  prompt: {
    -    id: "pmpt_abc123",
    -    version: "2",
    -    variables: { customer_name: "Jane Doe", product: "caixa de suco 1,2L" },
    -  },
    -});
    -console.log(response.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "prompt": {
    -      "id": "pmpt_abc123",
    -      "version": "2",
    -      "variables": { "customer_name": "Jane Doe", "product": "caixa de suco 1,2L" }
    -    }
    -  }'
    -
    -
    - - -
    - -
    -

    6. Reasoning (reasoning.effort)

    -

    Modelos de raciocínio usam reasoning tokens para planejar antes de responder. Esses tokens não são visíveis pela API, mas ocupam espaço na janela de contexto e são cobrados como tokens de saída. O gpt-5.5 suporta interleaved thinking: pode gerar saída visível antes, entre e depois de pensar, inclusive entre chamadas de ferramenta.

    - -

    6.1 Níveis de esforço

    -

    O gpt-5.5 aceita none, low, medium, high e xhigh, com padrão medium. Subconjuntos variam por modelo — confira a página de cada modelo.

    -
    - - - - - - - - - -
    EsforçoMelhor para…
    nonePiso de esforço (gera pouco ou nenhum reasoning token; ocupa o lugar do antigo nível mínimo). Mesmo em none as ferramentas hospedadas (web/file search) e o function calling continuam funcionando. Tarefas latency-critical sem benefício de raciocínio: voz, recuperação rápida, classificação. Para casos sensíveis à latência, comece em low e desça para none só se necessário; com none, peça ao modelo para "planejar antes de cada chamada de função" para compensar a ausência de tokens de raciocínio.
    lowRaciocínio eficiente com aumento modesto de latência: análise de dados, drafting, coding de execução, suporte/chat. Ideal quando há uso de ferramentas, planejamento ou decisão multi-etapa, otimizando velocidade e custo.
    mediumPadrão. Quando qualidade e confiabilidade importam e há planejamento/julgamento: coding agêntico, pesquisa, planilhas e slides, trabalho de horizonte longo. Ponto bem equilibrado de latência × performance × custo.
    highRaciocínio difícil, debugging complexo, planejamento profundo e tarefas de alto valor onde qualidade importa mais que latência. Avalie medium e high.
    xhighPesquisa profunda, fluxos assíncronos e tarefas agênticas de rollout muito longo: revisão de segurança/código, produtividade corporativa, coding desafiador. Use só quando os evals justificarem a latência/custo extra.
    -
    - -
    Dica: para melhor time to first token em aplicações sensíveis à latência, peça ao modelo um preâmbulo curto antes de continuar com raciocínio mais profundo. Controle o tamanho da resposta com max_output_tokens — a OpenAI recomenda reservar ao menos ~25.000 tokens para raciocínio + saída ao começar.
    - -

    6.2 Resumos de raciocínio

    -

    Os tokens brutos de raciocínio não são expostos, mas você pode pedir um resumo com reasoning.summary. Use "auto" para o resumidor mais detalhado disponível. O resumo aparece no array summary dentro do item de reasoning na saída.

    -
    -
    - - - -
    -
    -
    response = client.responses.create(
    -    model="gpt-5.5",
    -    input="Qual é a capital da França?",
    -    reasoning={"effort": "low", "summary": "auto"},
    -)
    -print(response.output)
    -
    -
    -
    const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Qual é a capital da França?",
    -  reasoning: { effort: "low", summary: "auto" },
    -});
    -console.log(response.output);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "Qual é a capital da França?",
    -    "reasoning": { "effort": "low", "summary": "auto" }
    -  }'
    -
    -
    -
    Nota: antes de usar resumidores com os modelos de raciocínio mais recentes, pode ser necessário concluir a verificação de organização nas configurações da plataforma.
    - -

    6.3 Manter itens de reasoning no contexto

    -

    Ao fazer function calling com modelo de raciocínio na Responses API, reenvie os itens de reasoning retornados junto com a última chamada de função (além da saída da função). Se o modelo chamou várias funções em sequência, devolva todos os itens de reasoning, function_call e function_call_output desde a última mensagem user. O jeito mais simples é encadear com previous_response_id; o sistema ignora de forma inteligente itens irrelevantes.

    - -

    6.4 Itens de reasoning criptografados (encrypted_content)

    -

    Em modo stateless (store=false) ou sob Zero Data Retention, você ainda precisa manter os itens de reasoning entre turnos. Para isso, adicione "reasoning.encrypted_content" ao parâmetro include. Os itens de reasoning na saída passam a ter encrypted_content, que você devolve intacto nas próximas requisições — sua aplicação não precisa entender o valor.

    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "reasoning": { "effort": "medium" },
    -    "input": "Como está o tempo hoje?",
    -    "tools": [ /* config de função */ ],
    -    "include": [ "reasoning.encrypted_content" ]
    -  }'
    - - -
    - -
    -

    7. Verbosity & phase

    - -

    7.1 text.verbosity

    -

    O text.verbosity é a alavanca principal para equilibrar concisão × completude da resposta. Valores suportados: low, medium (padrão) e high. Verbosidade menor gera menos tokens de saída e responde mais rápido; maior produz explicações mais ricas e estruturadas. No gpt-5.5, defina low quando quiser respostas mais curtas e diretas.

    -
    Dica: trate o tamanho da resposta como separado da qualidade do raciocínio. Combine verbosity com instruções explícitas — orçamento de palavras, número de seções, largura de tabelas ou saída só em JSON — quando precisar de um artefato estável.
    -
    -
    - - - -
    -
    -
    response = client.responses.create(
    -    model="gpt-5.5",
    -    input="Resuma a arquitetura de microsserviços.",
    -    text={"verbosity": "low"},
    -)
    -print(response.output_text)
    -
    -
    -
    const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Resuma a arquitetura de microsserviços.",
    -  text: { verbosity: "low" },
    -});
    -console.log(response.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "Resuma a arquitetura de microsserviços.",
    -    "text": { "verbosity": "low" }
    -  }'
    -
    -
    - -

    7.2 Parâmetro phase

    -

    Em fluxos longos ou tool-heavy, o campo phase nas mensagens assistant distingue atualizações intermediárias da resposta final. É opcional, mas recomendado:

    -
      -
    • phase: "commentary" — atualizações intermediárias, como preâmbulos antes de chamadas de ferramenta.
    • -
    • phase: "final_answer" — a resposta concluída.
    • -
    • Não adicione phase em mensagens user.
    • -
    -

    Com previous_response_id, o estado do assistant é preservado automaticamente. Se você reproduz o histórico manualmente, preserve cada valor original de phase e devolva-o sem alteração. phase faltante ou descartado pode fazer um preâmbulo ser tratado como resposta final, causando parada precoce.

    -
    Atenção: se o modelo trata uma atualização intermediária como resposta final em workflows tool-heavy, verifique primeiro se sua integração preserva o campo phase corretamente.
    - - -
    - -
    -

    8. Prompting GPT-5.5

    -

    O gpt-5.5 rende melhor com prompts outcome-first: descreva o resultado esperado, critérios de sucesso, restrições e contexto disponível, deixando o modelo escolher o caminho. Evite carregar todo o stack de prompts antigo: instruções que super-especificam o processo viram ruído e estreitam o espaço de busca.

    - -

    8.1 Preâmbulo (time to first token)

    -

    Em streaming, peça um preâmbulo curto antes de chamadas de ferramenta para melhorar a responsividade percebida sem mudar a tarefa.

    -
    Antes de qualquer chamada de ferramenta numa tarefa multi-etapa, envie uma
    -atualização curta e visível ao usuário que reconheça o pedido e indique o
    -primeiro passo. Mantenha em uma ou duas frases.
    - -

    8.2 Outcome-first e critérios de parada

    -

    Descreva o destino, não cada passo. Reserve palavras absolutas (ALWAYS, NEVER, must) para invariantes reais (segurança, campos obrigatórios). Para julgamentos (quando buscar, perguntar, usar ferramenta, iterar), prefira regras de decisão. Adicione critérios de parada explícitos:

    -
    Resolva o pedido do usuário no menor número útil de loops de ferramenta, mas
    -não deixe a minimização de loops superar correção, evidência ou citações
    -obrigatórias para afirmações factuais.
    -
    -Após cada resultado, pergunte: "Já consigo responder o pedido central com
    -evidência útil e citações?" Se sim, responda.
    - -

    8.3 Formatação e personalidade

    -

    O gpt-5.5 é altamente direcionável em formato. Por padrão é eficiente e direto; para produtos conversacionais, defina personalidade (tom, calor, formalidade) e estilo de colaboração (quando perguntar, quando assumir, quanto contexto dar) — sempre curtos. Use text.verbosity e indique público e tamanho:

    -
    Escreva para um público sênior de negócios. Mantenha a resposta abaixo de 400
    -palavras. Use parágrafos curtos e bullets só quando melhorarem a leitura.
    -Priorize a conclusão primeiro, depois o raciocínio, depois ressalvas.
    - -

    8.4 Orçamento de retrieval e checagem

    -

    Orçamentos de retrieval são regras de parada para busca: dizem ao modelo quando há evidência suficiente. Para tarefas com validação, dê ferramentas para o modelo checar o próprio trabalho (testes, type/lint checks, build, ou inspeção do artefato renderizado em UI). Para drafting, separe fatos que precisam de fonte de partes que podem ser escritas criativamente.

    -
    Para Q&A comum, comece com uma busca ampla usando palavras-chave curtas e
    -discriminativas. Se os melhores resultados já dão suporte citável ao pedido
    -central, responda a partir deles em vez de buscar de novo.
    -
    -Faça nova chamada de retrieval só quando: faltar fato/parâmetro/data/ID/fonte
    -exigidos, o usuário pedir cobertura exaustiva, ou houver afirmação factual
    -importante sem suporte.
    - -
    Nota: o gpt-5.5 já conhece a data atual em UTC — não inclua a data nas instruções, salvo quando precisar de um fuso/política específica do negócio. Prefira definir o schema de saída via Structured Outputs em vez de descrevê-lo no prompt.
    - - -
    - -
    -

    9. Saída estruturada

    -

    Structured Outputs garante que a resposta siga exatamente um JSON Schema fornecido — sem chaves faltando nem enums inválidos. Benefícios: type-safety confiável, recusas explícitas e prompting mais simples. Na Responses API, configure via text.format com type: "json_schema" e strict: true.

    - -

    9.1 Definindo o schema

    -

    Os SDKs facilitam definir o schema em código com Pydantic (Python) e Zod (JavaScript), via os helpers responses.parse / text_format / zodTextFormat.

    -
    -
    - - - -
    -
    -
    from pydantic import BaseModel
    -from openai import OpenAI
    -
    -client = OpenAI()
    -
    -class Passo(BaseModel):
    -    explicacao: str
    -    saida: str
    -
    -class Raciocinio(BaseModel):
    -    passos: list[Passo]
    -    resposta_final: str
    -
    -response = client.responses.parse(
    -    model="gpt-5.5",
    -    input=[
    -        {"role": "system", "content": "Você é um tutor de matemática. Guie passo a passo."},
    -        {"role": "user", "content": "Como resolvo 8x + 7 = -23?"},
    -    ],
    -    text_format=Raciocinio,
    -)
    -
    -for output in response.output:
    -    if output.type != "message":
    -        continue
    -    for item in output.content:
    -        if item.type == "refusal":
    -            print(item.refusal)   # recusa de segurança
    -        elif item.parsed:
    -            print(item.parsed)
    -
    -
    -
    import OpenAI from "openai";
    -import { z } from "zod";
    -import { zodTextFormat } from "openai/helpers/zod";
    -
    -const client = new OpenAI();
    -
    -const Passo = z.object({ explicacao: z.string(), saida: z.string() });
    -const Raciocinio = z.object({ passos: z.array(Passo), resposta_final: z.string() });
    -
    -const response = await client.responses.parse({
    -  model: "gpt-5.5",
    -  input: [
    -    { role: "system", content: "Você é um tutor de matemática. Guie passo a passo." },
    -    { role: "user", content: "Como resolvo 8x + 7 = -23?" },
    -  ],
    -  text: { format: zodTextFormat(Raciocinio, "raciocinio") },
    -});
    -
    -for (const output of response.output) {
    -  if (output.type !== "message") continue;
    -  for (const item of output.content) {
    -    if (item.type === "refusal") console.log(item.refusal);
    -    else if (item.parsed) console.log(item.parsed);
    -  }
    -}
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": [
    -      { "role": "system", "content": "Você é um tutor de matemática. Guie passo a passo." },
    -      { "role": "user", "content": "Como resolvo 8x + 7 = -23?" }
    -    ],
    -    "text": {
    -      "format": {
    -        "type": "json_schema",
    -        "name": "raciocinio",
    -        "strict": true,
    -        "schema": {
    -          "type": "object",
    -          "properties": {
    -            "passos": {
    -              "type": "array",
    -              "items": {
    -                "type": "object",
    -                "properties": { "explicacao": {"type":"string"}, "saida": {"type":"string"} },
    -                "required": ["explicacao", "saida"],
    -                "additionalProperties": false
    -              }
    -            },
    -            "resposta_final": { "type": "string" }
    -          },
    -          "required": ["passos", "resposta_final"],
    -          "additionalProperties": false
    -        }
    -      }
    -    }
    -  }'
    -
    -
    - -

    9.2 Recusas (refusals)

    -

    Com entrada gerada por usuário, o modelo pode recusar por segurança. Como a recusa não segue o schema, a resposta inclui um campo refusal em vez do conteúdo estruturado. Detecte-o programaticamente e trate na sua UI/lógica.

    -
    {
    -  "type": "message",
    -  "role": "assistant",
    -  "content": [
    -    { "type": "refusal", "refusal": "Desculpe, não posso ajudar com isso." }
    -  ]
    -}
    - -
    Dica: use text.format quando quiser estruturar a resposta ao usuário; use function calling (com strict) quando estiver conectando o modelo a ferramentas e dados do seu sistema. Para evitar divergência, prefira o suporte nativo de Pydantic/Zod a escrever o JSON Schema à mão.
    - -
    Atenção: existe ainda o JSON mode (text.format = {"type": "json_object"}), que garante JSON válido mas não adesão a schema. Prefira Structured Outputs sempre que possível; ao usar JSON mode, instrua explicitamente o modelo a gerar JSON.
    - - -
    - -
    -

    10. Function calling

    -

    Function calling (ou tool calling) conecta o modelo a sistemas e dados externos. Você declara funções por JSON Schema; o modelo decide quando chamá-las, emite uma function_call com argumentos, sua aplicação executa e devolve o function_call_output, e o modelo produz a resposta final (ou mais chamadas).

    - -

    10.1 Definindo funções

    -

    Cada função tem type: "function", name, description (quando e como usar), parameters (JSON Schema) e strict.

    -
    {
    -  "type": "function",
    -  "name": "get_weather",
    -  "description": "Retorna o tempo atual para a localização dada.",
    -  "parameters": {
    -    "type": "object",
    -    "properties": {
    -      "location": { "type": "string", "description": "Cidade e país, ex.: Bogotá, Colômbia" },
    -      "units": { "type": "string", "enum": ["celsius", "fahrenheit"] }
    -    },
    -    "required": ["location", "units"],
    -    "additionalProperties": false
    -  },
    -  "strict": true
    -}
    - -

    10.2 Loop de execução

    -
    -
    - - - -
    -
    -
    import json
    -from openai import OpenAI
    -
    -client = OpenAI()
    -
    -tools = [{
    -    "type": "function",
    -    "name": "get_weather",
    -    "description": "Retorna o tempo atual para a localização dada.",
    -    "parameters": {
    -        "type": "object",
    -        "properties": {
    -            "location": {"type": "string"},
    -            "units": {"type": "string", "enum": ["celsius", "fahrenheit"]},
    -        },
    -        "required": ["location", "units"],
    -        "additionalProperties": False,
    -    },
    -    "strict": True,
    -}]
    -
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    input=[{"role": "user", "content": "Qual o tempo em Paris?"}],
    -    tools=tools,
    -)
    -
    -# 1) Detectar e executar chamadas (assuma 0..N)
    -inputs = []
    -for item in resp.output:
    -    if item.type == "function_call":
    -        args = json.loads(item.arguments)
    -        result = {"temperature": "25", "unit": "C"}  # sua lógica real
    -        inputs.append({
    -            "type": "function_call_output",
    -            "call_id": item.call_id,
    -            "output": json.dumps(result),
    -        })
    -
    -# 2) Reenviar reasoning + chamadas + saídas; encadeie com previous_response_id
    -final = client.responses.create(
    -    model="gpt-5.5",
    -    previous_response_id=resp.id,
    -    input=inputs,
    -    tools=tools,
    -)
    -print(final.output_text)
    -
    -
    -
    import OpenAI from "openai";
    -const client = new OpenAI();
    -
    -const tools = [{
    -  type: "function",
    -  name: "get_weather",
    -  description: "Retorna o tempo atual para a localização dada.",
    -  parameters: {
    -    type: "object",
    -    properties: {
    -      location: { type: "string" },
    -      units: { type: "string", enum: ["celsius", "fahrenheit"] },
    -    },
    -    required: ["location", "units"],
    -    additionalProperties: false,
    -  },
    -  strict: true,
    -}];
    -
    -const resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: [{ role: "user", content: "Qual o tempo em Paris?" }],
    -  tools,
    -});
    -
    -const inputs = [];
    -for (const item of resp.output) {
    -  if (item.type === "function_call") {
    -    const args = JSON.parse(item.arguments);
    -    const result = { temperature: "25", unit: "C" }; // sua lógica real
    -    inputs.push({
    -      type: "function_call_output",
    -      call_id: item.call_id,
    -      output: JSON.stringify(result),
    -    });
    -  }
    -}
    -
    -const final = await client.responses.create({
    -  model: "gpt-5.5",
    -  previous_response_id: resp.id,
    -  input: inputs,
    -  tools,
    -});
    -console.log(final.output_text);
    -
    -
    -
    # 1) Primeira chamada com a definição da ferramenta
    -curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": [{ "role": "user", "content": "Qual o tempo em Paris?" }],
    -    "tools": [{
    -      "type": "function", "name": "get_weather", "strict": true,
    -      "description": "Retorna o tempo atual para a localização dada.",
    -      "parameters": {
    -        "type": "object",
    -        "properties": {
    -          "location": {"type":"string"},
    -          "units": {"type":"string","enum":["celsius","fahrenheit"]}
    -        },
    -        "required": ["location","units"], "additionalProperties": false
    -      }
    -    }]
    -  }'
    -
    -# 2) Devolva o resultado encadeando previous_response_id
    -curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "previous_response_id": "resp_123",
    -    "input": [{
    -      "type": "function_call_output",
    -      "call_id": "call_abc",
    -      "output": "{\"temperature\":\"25\",\"unit\":\"C\"}"
    -    }]
    -  }'
    -
    -
    - -

    10.3 tool_choice e parallel calls

    -
    - - - - - - - - - -
    tool_choiceComportamento
    "auto" (padrão)O modelo chama zero, uma ou várias funções.
    "required"O modelo deve chamar uma ou mais funções.
    {"type":"function","name":"..."}Força exatamente uma função específica.
    {"type":"allowed_tools","mode":"auto","tools":[...]}Restringe a um subconjunto sem remover ferramentas — útil para preservar prompt caching.
    "none"Imita o comportamento de não passar funções.
    -
    -

    O modelo pode chamar várias funções no mesmo turno (parallel tool calls). Desative com parallel_tool_calls: false para garantir zero ou uma chamada. Parallel calls não se aplicam a ferramentas integradas.

    - -
    Dica: habilite sempre strict: true — ele usa Structured Outputs para garantir aderência ao schema (exige additionalProperties: false e todos os campos em required; campos opcionais via tipo null). Mantenha menos de ~20 funções disponíveis no início de um turno; para catálogos grandes, use tool search.
    - -
    Nota: na Responses API o type: "function" fica no topo da definição (ao lado de name/parameters), diferente do Chat Completions, que aninha tudo sob uma chave "function". Da mesma forma, tool_choice específico aqui é {"type":"function","name":"..."} — sem aninhamento.
    - -

    10.4 Custom tools & gramáticas (CFG)

    -

    Quando a entrada da ferramenta é texto livre (código, um comando, uma consulta) em vez de um objeto JSON, use uma custom tool (type: "custom"). O modelo emite um item custom_tool_call com o campo input em texto puro. Custom tools não suportam parallel tool calls — passe parallel_tool_calls: false.

    -

    Para garantir que esse texto seja sintaticamente válido (um dialeto SQL, uma DSL), anexe uma gramática livre de contexto (CFG) via bloco format, com syntax "lark" ou "regex". A amostragem é restringida à gramática, então a saída sempre casa com ela.

    -
    mssql_grammar = r"""
    -start: "SELECT" column "FROM" table
    -column: "id" | "name" | "email"
    -table: "users" | "orders"
    -"""
    -
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    input="Liste os e-mails de todos os usuários.",
    -    tools=[{
    -        "type": "custom",
    -        "name": "mssql_query",
    -        "description": "Gera uma consulta SQL válida no dialeto suportado.",
    -        "format": {"type": "grammar", "syntax": "lark", "definition": mssql_grammar},
    -    }],
    -    parallel_tool_calls=False,
    -)
    -# A resposta traz um item custom_tool_call com .input em texto restrito pela gramática.
    -
    Atenção: mantenha a gramática o mais simples possível — gramáticas complexas podem ser rejeitadas. O dialeto Lark não suporta lookaround, modificadores lazy (*?, +?), prioridades de terminal, templates nem %import (exceto %import common); o mesmo vale para lookaround/lazy em regex.
    - - -
    - -
    -

    11. Ferramentas integradas

    -

    Além das suas funções, a Responses API oferece ferramentas integradas (hosted tools), ativadas pelo array tools. Elas estão in-distribution para o pós-treino dos modelos, então tendem a ter melhor seleção e execução do que ferramentas customizadas equivalentes. O modelo decide quando usá-las com base no prompt; você guia com tool_choice.

    - -

    11.1 Web search

    -

    Permite acesso a informação atualizada da internet com citações. Para integrações novas, use { "type": "web_search" } (suporta controles como filters, sources, external_web_access e return_token_budget). A saída inclui um item web_search_call (com a ação: search, open_page ou find_in_page) e uma message com texto e anotações url_citation. Desde jun/2026 a busca também pode retornar resultados de imagem (ver abaixo). Para pesquisa profunda multi-etapa, use gpt-5.5 com reasoning em high/xhigh e background mode.

    -
    -
    - - - -
    -
    -
    response = client.responses.create(
    -    model="gpt-5.5",
    -    input="Quais foram as novidades de IA esta semana?",
    -    tools=[{"type": "web_search"}],
    -)
    -print(response.output_text)
    -
    -
    -
    const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Quais foram as novidades de IA esta semana?",
    -  tools: [{ type: "web_search" }],
    -});
    -console.log(response.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "Quais foram as novidades de IA esta semana?",
    -    "tools": [{ "type": "web_search" }]
    -  }'
    -
    -
    -
    Atenção: trate o conteúdo de páginas, PDFs e e-mails retornados como entrada não confiável. Só instruções diretas do usuário contam como permissão.
    - -

    Resultados de imagem (image search)

    -

    O web search pode retornar imagens junto dos resultados de texto (novidade de jun/2026) — útil quando o app precisa de visuais atuais e ancorados na web: fotos de produtos, lugares, eventos, referências visuais com link da fonte. Configure search_content_types incluindo "image" (adicione "text" se também quiser resultados textuais que ajudem o modelo a resumir, ranquear ou explicar as imagens) e ajuste o comportamento com image_settings: max_results (quantidade de imagens) e caption (descrições curtas quando disponíveis).

    -

    Os resultados de imagem não entram na message final: eles voltam no próprio item web_search_call. Para inspecioná-los, peça include: ["web_search_call.results"] e leia web_search_call.results[] — cada image_result traz image_url (URL canônica da imagem), source_website_url (página onde a imagem foi encontrada), thumbnail_url e caption (quando disponíveis).

    -
    resp = client.responses.create(
    -    model="gpt-5.5",
    -    input="Fotos recentes da Golden Gate ao pôr do sol",
    -    tools=[{
    -        "type": "web_search",
    -        "search_content_types": ["image", "text"],
    -        "image_settings": {"max_results": 5, "caption": True},
    -    }],
    -    include=["web_search_call.results"],
    -)
    -
    -for item in resp.output:
    -    if item.type == "web_search_call":
    -        for r in (item.results or []):
    -            if r.type == "image_result":
    -                print(r.image_url, "|", r.source_website_url, "|", r.caption)
    -
    {
    -  "output": [
    -    {
    -      "type": "web_search_call",
    -      "status": "completed",
    -      "results": [
    -        {
    -          "type": "image_result",
    -          "image_url": "https://cdn.example/golden-gate-sunset.jpg",
    -          "thumbnail_url": "https://cdn.example/golden-gate-sunset-thumb.jpg",
    -          "source_website_url": "https://example.com/source-page",
    -          "caption": "Golden Gate Bridge at sunset"
    -        }
    -      ]
    -    }
    -  ]
    -}
    - -

    11.2 File search

    -

    Recupera informação de uma base de conhecimento de arquivos enviados, via busca semântica e por palavra-chave. Antes, crie um vector store e suba arquivos a ele; depois inclua file_search com os vector_store_ids. A saída traz um item file_search_call e uma message com citações de arquivo. Você pode limitar resultados, incluir os resultados via include e filtrar por metadados.

    -
    -
    - - - -
    -
    -
    response = client.responses.create(
    -    model="gpt-5.5",
    -    input="O que é deep research da OpenAI?",
    -    tools=[{
    -        "type": "file_search",
    -        "vector_store_ids": ["vs_abc123"],
    -    }],
    -)
    -print(response.output_text)
    -
    -
    -
    const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "O que é deep research da OpenAI?",
    -  tools: [{ type: "file_search", vector_store_ids: ["vs_abc123"] }],
    -});
    -console.log(response.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "O que é deep research da OpenAI?",
    -    "tools": [{ "type": "file_search", "vector_store_ids": ["vs_abc123"] }]
    -  }'
    -
    -
    - -

    11.3 MCP & Connectors

    -

    Dê ao modelo novas capacidades via servidores MCP remotos (qualquer servidor que implemente o Model Context Protocol) e connectors (wrappers MCP mantidos pela OpenAI para serviços como Google Workspace ou Dropbox). Ambos usam o tipo de ferramenta mcp. MCP remoto exige server_url (e às vezes um token OAuth em authorization); connectors exigem connector_id e o token OAuth. As chamadas podem ser automáticas ou exigir aprovação (require_approval).

    -
    -
    - - - -
    -
    -
    resp = client.responses.create(
    -    model="gpt-5.5",
    -    tools=[{
    -        "type": "mcp",
    -        "server_label": "dmcp",
    -        "server_description": "Servidor MCP de D&D para rolagem de dados.",
    -        "server_url": "https://dmcp-server.deno.dev/sse",
    -        "require_approval": "never",
    -    }],
    -    input="Role 2d4+1",
    -)
    -print(resp.output_text)
    -
    -
    -
    const resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  tools: [{
    -    type: "mcp",
    -    server_label: "dmcp",
    -    server_description: "Servidor MCP de D&D para rolagem de dados.",
    -    server_url: "https://dmcp-server.deno.dev/sse",
    -    require_approval: "never",
    -  }],
    -  input: "Role 2d4+1",
    -});
    -console.log(resp.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "tools": [{
    -      "type": "mcp",
    -      "server_label": "dmcp",
    -      "server_description": "Servidor MCP de D&D para rolagem de dados.",
    -      "server_url": "https://dmcp-server.deno.dev/sse",
    -      "require_approval": "never"
    -    }],
    -    "input": "Role 2d4+1"
    -  }'
    -
    -
    -
    Cuidado: confie apenas em servidores MCP que você revisou. Um servidor malicioso pode exfiltrar qualquer dado que entre no contexto do modelo. Para servidores privados/on-premises, use o Secure MCP Tunnel em vez de expô-los à internet pública.
    - -

    11.4 Code Interpreter

    -

    Permite ao modelo escrever e executar Python num ambiente sandbox (o modelo o conhece como "python tool"). Use para análise de dados, geração de arquivos/gráficos, matemática e código iterativo. Requer um container: modo auto (cria ou reusa) ou explícito (via /v1/containers). O memory_limit padrão é 1 GB.

    -
    -
    - - - -
    -
    -
    resp = client.responses.create(
    -    model="gpt-5.5",
    -    tools=[{
    -        "type": "code_interpreter",
    -        "container": {"type": "auto", "memory_limit": "4g"},
    -    }],
    -    instructions="Use a python tool para resolver problemas de matemática.",
    -    input="Resolva 3x + 11 = 14.",
    -)
    -print(resp.output_text)
    -
    -
    -
    const resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  tools: [{
    -    type: "code_interpreter",
    -    container: { type: "auto", memory_limit: "4g" },
    -  }],
    -  instructions: "Use a python tool para resolver problemas de matemática.",
    -  input: "Resolva 3x + 11 = 14.",
    -});
    -console.log(resp.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "tools": [{ "type": "code_interpreter", "container": { "type": "auto", "memory_limit": "4g" } }],
    -    "instructions": "Use a python tool para resolver problemas de matemática.",
    -    "input": "Resolva 3x + 11 = 14."
    -  }'
    -
    -
    - -

    11.5 Computer use

    -

    Permite ao modelo operar software pela interface: ele inspeciona screenshots e devolve ações de UI (cliques, digitação, rolagem, pedidos de screenshot) que seu código executa. O gpt-5.4 recebeu treino específico para esse trabalho. Há três formatos de harness: o loop integrado (ferramenta computer), uma ferramenta/harness custom sobre Playwright/Selenium/VNC/MCP, ou um harness de execução de código.

    -
    Cuidado: rode Computer use em navegador/VM isolado, mantenha humano no loop para ações de alto impacto e trate todo conteúdo de tela como entrada não confiável. Passe um env vazio e desative extensões e acesso ao filesystem do host quando possível.
    - -

    11.6 Apply Patch

    -

    A ferramenta apply_patch deixa o modelo criar, atualizar e deletar arquivos no seu código via diffs estruturados (formato V4A), habilitando edição iterativa multi-arquivo. Por ser uma ferramenta nomeada (não uma função freeform que você descreve), está in-distribution para o pós-treino — o que reduz a taxa de falha de patch em cerca de 35% frente à abordagem freeform/JSON anterior. O fluxo: ative tools=[{"type":"apply_patch"}], o modelo emite itens apply_patch_call (operações create_file/update_file/delete_file, com path e diff), sua aplicação aplica os patches e devolve um apply_patch_call_output por call_id com status (completed/failed). Disponível só pela Responses API. Ótima combinada com a ferramenta shell para descoberta de arquivos.

    -
    Nota: o diff V4A é baseado em contexto, não em números de linha — usa âncoras @@ e o envelope *** Begin Patch / *** Add File: / *** Update File: / *** Delete File: / *** Move to: / *** End Patch, com prefixos de linha + (adição), - (remoção) e espaço (contexto). Aplicar a um arquivo divergente falha; devolva status: "failed" com output para o modelo se recuperar.
    -
    resp = client.responses.create(
    -    model="gpt-5.5",
    -    tools=[{"type": "apply_patch"}],
    -    input="Renomeie a função `parse` para `parse_input` em src/io.py.",
    -)
    -# Itere sobre resp.output procurando itens type == "apply_patch_call",
    -# aplique o diff no seu workspace e devolva apply_patch_call_output por call_id.
    -
    Atenção: no seu harness, valide caminhos (evite directory traversal), restrinja edições a diretórios permitidos, faça backup antes de aplicar e sempre devolva status: "failed" com um output claro quando um patch não aplicar — assim o modelo se recupera.
    - -

    11.7 Tool search

    -

    Tool search deixa o modelo buscar e carregar ferramentas no contexto sob demanda, evitando carregar todo o catálogo de uma vez — reduz tokens e custo. Só gpt-5.4 e modelos posteriores suportam. Para ativar: adicione {"type": "tool_search"} ao tools e marque as funções/MCP a adiar com defer_loading: true. As ferramentas carregadas são injetadas no fim do contexto, preservando o cache.

    -
    {
    -  "tools": [
    -    {
    -      "type": "namespace",
    -      "name": "crm",
    -      "description": "Ferramentas de CRM para busca de clientes e gestão de pedidos.",
    -      "tools": [
    -        {
    -          "type": "function",
    -          "name": "list_open_orders",
    -          "description": "Lista pedidos abertos por customer_id.",
    -          "defer_loading": true,
    -          "parameters": {
    -            "type": "object",
    -            "properties": { "customer_id": { "type": "string" } },
    -            "required": ["customer_id"],
    -            "additionalProperties": false
    -          }
    -        }
    -      ]
    -    },
    -    { "type": "tool_search" }
    -  ]
    -}
    -

    Há dois modos: hosted (a OpenAI busca entre as ferramentas declaradas e devolve o subconjunto carregado na mesma resposta, via itens tool_search_call e tool_search_output) e client-executed (execution: "client": o modelo emite tool_search_call, sua aplicação faz a busca e devolve um tool_search_output com as ferramentas a carregar). Prefira agrupar em namespaces ou servidores MCP, com até ~10 funções cada e descrições curtas e discriminativas.

    - -

    11.8 Local shell & Shell

    -

    A ferramenta shell dá ao modelo um ambiente de terminal completo, em container hospedado pela OpenAI (use environment: {"type": "container_auto"}) ou num runtime local que você executa. Disponível só pela Responses API.

    -
    -
    - - - -
    -
    -
    response = client.responses.create(
    -    model="gpt-5.5",
    -    tools=[{"type": "shell", "environment": {"type": "container_auto"}}],
    -    input=[{
    -        "type": "message",
    -        "role": "user",
    -        "content": [{
    -            "type": "input_text",
    -            "text": "Execute: ls -lah /mnt/data && python --version",
    -        }],
    -    }],
    -    tool_choice="auto",
    -)
    -print(response.output_text)
    -
    -
    -
    const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  tools: [{ type: "shell", environment: { type: "container_auto" } }],
    -  input: [{
    -    type: "message",
    -    role: "user",
    -    content: [{ type: "input_text", text: "Execute: ls -lah /mnt/data && python --version" }],
    -  }],
    -  tool_choice: "auto",
    -});
    -console.log(response.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "tools": [{ "type": "shell", "environment": { "type": "container_auto" } }],
    -    "input": [{
    -      "type": "message", "role": "user",
    -      "content": [{ "type": "input_text", "text": "Execute: ls -lah /mnt/data" }]
    -    }],
    -    "tool_choice": "auto"
    -  }'
    -
    -
    -

    O runtime hospedado é baseado em Debian 12, com diretório de trabalho /mnt/data (caminho suportado para artefatos baixáveis) e linguagens pré-instaladas (Python 3.11, Node.js 22, Java 17, PHP 8.2, Ruby 3.1, Go 1.23). Não há TTY interativo nem sudo. Para fluxos iterativos, crie um container reutilizável e referencie-o entre chamadas.

    -
    Cuidado: executar comandos arbitrários é perigoso. Sempre faça sandbox, aplique allowlists/denylists e registre a atividade da ferramenta para auditoria.
    - -

    11.9 Programmatic Tool Calling (PTC) gpt-5.6 · 2026-07-09

    -

    O Programmatic Tool Calling deixa o modelo escrever e executar JavaScript que coordena as tools de um request da Responses API: chamadas em paralelo, loops, condições e resultados intermediários mantidos no runtime hospedado — em vez de um round trip modelo↔tool por chamada. Vale quando uma etapa tem fluxo de controle previsível e o código pode devolver um resultado estruturado menor (filtrar/juntar/agregar N resultados antes de voltar ao contexto do modelo).

    -
      -
    • Runtime: cada programa roda em um V8 isolado e efêmero (JS com top-level await). Não há Node.js, instalação de pacotes, rede direta, filesystem geral, subprocessos, console nem estado persistente entre execuções. O programa só interage com o mundo via tools habilitadas no request e emite saída com text(...)/image(...).
    • -
    • Config: adicione a hosted tool {"type":"programmatic_tool_calling"} e marque cada tool elegível com allowed_callers: ["direct"] (só o modelo), ["programmatic"] (só código) ou ambos. Defina output_schema nas functions para o JS usar os campos com segurança. Suportadas em programa: function/custom, mcp (com require_approval pausando o programa), apply_patch, shell local/hosted e code_interpreter. tool_search roda só top-level — deferred tools precisam ser carregadas antes do programa começar.
    • -
    • Quem executa o quê: a OpenAI executa o JS gerado; sua aplicação continua executando as function calls client-owned que o programa dispara (itens function_call com caller.caller_id apontando para o program). Devolva cada resultado como function_call_output copiando o campo caller sem alterar — é ele que retoma o programa certo. O resultado final chega num item program_output (status completed/incomplete).
    • -
    • ZDR/store=false: PTC suporta ZDR sem container persistente de execução. Sob store:false, replaye todos os itens (program, reasoning, function calls/outputs, program_output) + include: ["reasoning.encrypted_content"].
    • -
    • Quando NÃO usar: uma única chamada; quando cada resultado precisa de julgamento fresco do modelo; ações com side-effect/aprovação (mantenha direct para preservar a fronteira de autorização); validação final de citações/artefatos nativos. Cheque as permissões de cada chamada na sua aplicação, mesmo vindo de programa hospedado — e meça contra baseline direct (tokens, latência, corretude) antes de adotar.
    • -
    - - -

    11.10 Receitas e exemplos oficiais (Cookbook)

    -

    O OpenAI Cookbook traz receitas executáveis para os padrões desta parte. As abaixo estão alinhadas à Responses API e aos modelos atuais; use-as como ponto de partida e adapte os IDs de modelo para gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano.

    -
    - - - - - - - - - - - - -
    ReceitaO que ensinaLink oficial
    GPT-5 prompting guideControle de eagerness/persistência, context gathering, preâmbulos de ferramenta e o ganho de qualidade ao encadear com previous_response_id.cookbook.openai.com/examples/gpt-5/gpt-5_prompting_guide
    GPT-5.1 prompting guidereasoning.effort: none com ferramentas, as ferramentas nomeadas apply_patch e shell, e atualizações de status (preâmbulos).cookbook.openai.com/examples/gpt-5/gpt-5-1_prompting_guide
    GPT-5 — novos parâmetros e ferramentasverbosity, custom tools de texto livre e gramáticas livres de contexto (CFG, Lark/regex).cookbook.openai.com/examples/gpt-5/gpt-5_new_params_and_tools
    Construindo um coding agent com GPT-5.1Loop de agente de código real fiando apply_patch + shell pela Responses API.cookbook.openai.com/examples/Build_a_coding_agent_with_GPT-5.1
    Structured Outputs — introduçãoJSON estrito por json_schema + helper Pydantic; regras de schema (todos os campos em required, additionalProperties: false, raiz objeto) e refusals.cookbook.openai.com/examples/structured_outputs_intro
    File Search com a Responses APIVector stores, a ferramenta file_search e citações de arquivo em RAG.cookbook.openai.com/examples/file_search_responses
    Guia da ferramenta MCPConfigurar o tool mcp, listar ferramentas remotas e tratar o fluxo de aprovação.cookbook.openai.com/examples/mcp/mcp_tool_guide
    Agents SDK (Python)Agent/Runner, @function_tool, handoffs vs agent.as_tool(), guardrails com tripwire e sessões de memória — sobre a Responses API.openai.github.io/openai-agents-python
    -
    -
    Atenção — receitas legadas: várias receitas mais antigas do Cookbook usam a Chat Completions API antiga e modelos descontinuados (ex.: How to format inputs to ChatGPT models, How to call functions with chat models, Orchestrating agents — um protótipo Swarm — e versões "with older completions API"). Aproveite delas só os conceitos atemporais (regras de schema, padrões de prompt); o equivalente moderno é sempre a Responses API com gpt-5.5 e, para multi-agentes, o Agents SDK (em vez de reimplementar o loop sobre Chat Completions).
    - -

    Exemplos executáveis (Python e JavaScript) das receitas-chave desta parte, adaptados à Responses API e modelos atuais:

    - -

    Structured Outputs (json_schema estrito) — cookbook.openai.com/examples/structured_outputs_intro

    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -from pydantic import BaseModel
    -
    -client = OpenAI()
    -
    -# Schema estrito: campos tipados via Pydantic (vira json_schema com strict=true)
    -class Step(BaseModel):
    -    explanation: str
    -    output: str
    -
    -class MathReasoning(BaseModel):
    -    steps: list[Step]
    -    final_answer: str
    -
    -# responses.parse aplica o schema e devolve o objeto já tipado
    -response = client.responses.parse(
    -    model="gpt-5.5",
    -    input=[
    -        {"role": "system", "content": "Você é um tutor de matemática. Resolva passo a passo."},
    -        {"role": "user", "content": "Como resolvo 8x + 7 = -23?"},
    -    ],
    -    text_format=MathReasoning,
    -)
    -
    -for output in response.output:
    -    if output.type != "message":
    -        continue
    -    for item in output.content:
    -        if item.type == "refusal":
    -            # Recusa por segurança: não segue o schema; trate à parte
    -            print("Recusa:", item.refusal)
    -        elif item.parsed:
    -            print(item.parsed.final_answer)
    -
    -
    -
    import OpenAI from "openai";
    -import { z } from "zod";
    -import { zodTextFormat } from "openai/helpers/zod";
    -
    -const client = new OpenAI();
    -
    -// Schema estrito definido com Zod (vira json_schema com strict=true)
    -const Step = z.object({ explanation: z.string(), output: z.string() });
    -const MathReasoning = z.object({
    -  steps: z.array(Step),
    -  final_answer: z.string(),
    -});
    -
    -const response = await client.responses.parse({
    -  model: "gpt-5.5",
    -  input: [
    -    { role: "system", content: "Você é um tutor de matemática. Resolva passo a passo." },
    -    { role: "user", content: "Como resolvo 8x + 7 = -23?" },
    -  ],
    -  text: { format: zodTextFormat(MathReasoning, "math_reasoning") },
    -});
    -
    -for (const output of response.output) {
    -  if (output.type !== "message") continue;
    -  for (const item of output.content) {
    -    if (item.type === "refusal") {
    -      // Recusa por segurança: não segue o schema; trate à parte
    -      console.log("Recusa:", item.refusal);
    -    } else if (item.parsed) {
    -      console.log(item.parsed.final_answer);
    -    }
    -  }
    -}
    -
    -
    - -

    File Search / RAG (vector store + tool file_search) — cookbook.openai.com/examples/file_search_responses

    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -# 1) Cria o vector store e anexa um arquivo (a indexação roda no servidor)
    -vector_store = client.vector_stores.create(name="base_conhecimento")
    -# purpose="assistants" é o valor documentado para ingestão em vector store / file_search
    -file = client.files.create(file=open("manual.pdf", "rb"), purpose="assistants")
    -client.vector_stores.files.create(
    -    vector_store_id=vector_store.id,
    -    file_id=file.id,
    -)
    -
    -# 2) A Responses API chama o tool file_search e cita os arquivos
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    input="Qual é a política de reembolso?",
    -    tools=[{
    -        "type": "file_search",
    -        "vector_store_ids": [vector_store.id],
    -        "max_num_results": 5,
    -    }],
    -)
    -
    -# 3) output[0] = file_search_call; output[1] = message com texto + citações
    -print(response.output_text)
    -for item in response.output:
    -    if item.type == "message":
    -        for ann in item.content[0].annotations:
    -            print("Citação:", ann.filename)
    -
    -
    -
    import OpenAI from "openai";
    -import fs from "fs";
    -
    -const client = new OpenAI();
    -
    -// 1) Cria o vector store e anexa um arquivo (a indexação roda no servidor)
    -const vectorStore = await client.vectorStores.create({ name: "base_conhecimento" });
    -// purpose: "assistants" é o valor documentado para ingestão em vector store / file_search
    -const file = await client.files.create({
    -  file: fs.createReadStream("manual.pdf"),
    -  purpose: "assistants",
    -});
    -await client.vectorStores.files.create(vectorStore.id, { file_id: file.id });
    -
    -// 2) A Responses API chama o tool file_search e cita os arquivos
    -const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Qual é a política de reembolso?",
    -  tools: [{
    -    type: "file_search",
    -    vector_store_ids: [vectorStore.id],
    -    max_num_results: 5,
    -  }],
    -});
    -
    -// 3) output[0] = file_search_call; output[1] = message com texto + citações
    -console.log(response.output_text);
    -for (const item of response.output) {
    -  if (item.type === "message") {
    -    for (const ann of item.content[0].annotations) console.log("Citação:", ann.filename);
    -  }
    -}
    -
    -
    - -

    MCP remoto (tool mcp com fluxo de aprovação) — cookbook.openai.com/examples/mcp/mcp_tool_guide

    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -# require_approval="always" faz a API pedir aprovação antes de cada chamada
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    tools=[{
    -        "type": "mcp",
    -        "server_label": "dmcp",
    -        "server_description": "Servidor MCP de D&D para rolar dados.",
    -        "server_url": "https://dmcp-server.deno.dev/sse",
    -        "require_approval": "always",
    -    }],
    -    input="Role 2d4+1",
    -)
    -
    -# A saída traz um item mcp_approval_request; aprove encadeando a resposta
    -for item in resp.output:
    -    if item.type == "mcp_approval_request":
    -        resp = client.responses.create(
    -            model="gpt-5.5",
    -            previous_response_id=resp.id,
    -            input=[{
    -                "type": "mcp_approval_response",
    -                "approve": True,
    -                "approval_request_id": item.id,
    -            }],
    -        )
    -
    -print(resp.output_text)
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -
    -// require_approval: "always" faz a API pedir aprovação antes de cada chamada
    -let resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  tools: [{
    -    type: "mcp",
    -    server_label: "dmcp",
    -    server_description: "Servidor MCP de D&D para rolar dados.",
    -    server_url: "https://dmcp-server.deno.dev/sse",
    -    require_approval: "always",
    -  }],
    -  input: "Role 2d4+1",
    -});
    -
    -// A saída traz um item mcp_approval_request; aprove encadeando a resposta
    -for (const item of resp.output) {
    -  if (item.type === "mcp_approval_request") {
    -    resp = await client.responses.create({
    -      model: "gpt-5.5",
    -      previous_response_id: resp.id,
    -      input: [{
    -        type: "mcp_approval_response",
    -        approve: true,
    -        approval_request_id: item.id,
    -      }],
    -    });
    -  }
    -}
    -
    -console.log(resp.output_text);
    -
    -
    - - -
    - -
    -

    12. Streaming

    -

    Por padrão a API gera toda a saída antes de devolvê-la. Com stream=true, a Responses API transmite eventos semânticos via Server-Sent Events (SSE), permitindo processar/exibir o início da resposta enquanto ela é gerada. Em produção, lembre que transmitir a saída dificulta a moderação de conteúdo — conclusões parciais são mais difíceis de avaliar; considere isso nas suas políticas de uso aprovado.

    - -

    12.1 Eventos comuns

    -

    Cada evento é tipado. Os principais para streaming de texto:

    -
      -
    • response.created — a resposta começou.
    • -
    • response.output_text.delta — pedaços de texto à medida que são gerados.
    • -
    • response.completed — a resposta terminou.
    • -
    • error — falha durante o streaming.
    • -
    -

    Há ainda eventos para itens (response.output_item.added/done), partes de conteúdo, refusals, function_call_arguments.delta (argumentos de função em tempo real) e eventos específicos de file search / code interpreter.

    -
    -
    - - - -
    -
    -
    stream = client.responses.create(
    -    model="gpt-5.5",
    -    input="Escreva um conto curto sobre lontras no espaço.",
    -    stream=True,
    -)
    -
    -for event in stream:
    -    if event.type == "response.output_text.delta":
    -        print(event.delta, end="", flush=True)
    -    elif event.type == "response.completed":
    -        print("\n[fim]")
    -
    -
    -
    const stream = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Escreva um conto curto sobre lontras no espaço.",
    -  stream: true,
    -});
    -
    -for await (const event of stream) {
    -  if (event.type === "response.output_text.delta") process.stdout.write(event.delta);
    -  else if (event.type === "response.completed") console.log("\n[fim]");
    -}
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "Escreva um conto curto sobre lontras no espaço.",
    -    "stream": true
    -  }'
    -
    -
    - -

    12.2 WebSocket Mode

    -

    A Responses API também suporta um modo WebSocket para fluxos longos e tool-call-heavy: você mantém uma conexão persistente com /v1/responses e continua cada turno enviando só os itens novos mais o previous_response_id, via eventos response.create no mesmo socket. Os campos de transporte stream e background não são usados nesse modo.

    -

    Como a conexão fica aberta e cada turno envia só o incremento, o WebSocket Mode reduz o overhead de continuação e melhora a latência ponta a ponta — em rollouts de 20+ chamadas de ferramenta, ganhos de até ~40%. Uma conexão trata uma resposta por vez (sem multiplexação; paralelismo exige conexões adicionais) e expira em ~60 min; a continuação usa a mesma semântica de previous_response_id, com um cache local da conexão para a resposta mais recente. É compatível com Zero Data Retention e store=false (dados só em memória). As amostras oficiais usam websocket-client em Python e ws em JavaScript.

    - -
    HTTP é o padrão — e o fallback. Se o fluxo é uma requisição, uma resposta, fique no HTTP/SSE: o ganho do WebSocket só aparece em agentes de longa duração com muitas chamadas de ferramenta na mesma cadeia. O modo WebSocket é uma otimização de latência opt-in, não o transporte default da Responses API. No Agents SDK (Python) o mesmo transporte é controlado por set_default_openai_responses_transport("websocket") — ver guia_agents_sdk §8.4.
    - -
    WebSocket Mode não fornece resume de UX. Ele otimiza a conversa backend↔OpenAI dentro de uma conexão — a reconexão após queda/60 min abre novo socket e, sob store=false/ZDR, a cadeia se perde (previous_response_id=null + reenvio do contexto completo ou compactado). O usuário que fechou a aba e voltou é atendido por outra camada: event store durável + replay por cursor no SEU backend — arquitetura completa no guia Streaming Durável & Resumível.
    - - -
    - -
    -

    13. Estado de conversa

    -

    Cada geração é independente e stateless por padrão. Há três formas de manter contexto entre turnos.

    - -

    13.1 Manual

    -

    Inclua o histórico no input com mensagens user/assistant alternadas, ou anexe os itens de output da resposta anterior ao próximo input.

    - -

    13.2 previous_response_id

    -

    Encadeia respostas passando o id da anterior. O estado prévio (incluindo reasoning e contexto de ferramenta) é preservado automaticamente — o jeito mais simples de threading.

    -
    -
    - - - -
    -
    -
    first = client.responses.create(model="gpt-5.5", input="Conte uma piada.")
    -print(first.output_text)
    -
    -second = client.responses.create(
    -    model="gpt-5.5",
    -    previous_response_id=first.id,
    -    input=[{"role": "user", "content": "Explique por que tem graça."}],
    -)
    -print(second.output_text)
    -
    -
    -
    const first = await client.responses.create({ model: "gpt-5.5", input: "Conte uma piada." });
    -console.log(first.output_text);
    -
    -const second = await client.responses.create({
    -  model: "gpt-5.5",
    -  previous_response_id: first.id,
    -  input: [{ role: "user", content: "Explique por que tem graça." }],
    -});
    -console.log(second.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "previous_response_id": "resp_123",
    -    "input": [{ "role": "user", "content": "Explique por que tem graça." }]
    -  }'
    -
    -
    - -

    13.3 Conversations API e compaction

    -

    A Conversations API persiste o estado como um objeto durável (com id próprio) que você reusa entre sessões/dispositivos; passe-o no parâmetro conversation. Itens de uma conversa não têm o TTL de 30 dias das respostas avulsas.

    -

    Para agentes de longa duração, use compaction para reduzir o contexto preservando o estado necessário: deixe o servidor compactar (com previous_response_id + context_management e compact_threshold) ou chame client.responses.compact() e use a saída diretamente no próximo turno. Não edite a saída compactada — ela é estado de máquina, não um resumo humano.

    -
    Nota: mesmo com previous_response_id, todos os tokens de entrada da cadeia são cobrados como input a cada turno. Respostas são guardadas por 30 dias por padrão (desative com store=false).
    - - -
    - -
    -

    14. Background & webhooks

    -

    Tarefas de raciocínio podem levar minutos. O background mode executa de forma assíncrona, sem risco de timeout: faça a requisição com background: true e faça polling do objeto de resposta.

    - -

    14.1 background=true e polling

    -
    -
    - - - -
    -
    -
    from time import sleep
    -
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    input="Escreva um romance longo sobre lontras no espaço.",
    -    background=True,
    -)
    -
    -while resp.status in {"queued", "in_progress"}:
    -    sleep(2)
    -    resp = client.responses.retrieve(resp.id)
    -
    -print(resp.status, resp.output_text)
    -
    -
    -
    let resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Escreva um romance longo sobre lontras no espaço.",
    -  background: true,
    -});
    -
    -while (resp.status === "queued" || resp.status === "in_progress") {
    -  await new Promise((r) => setTimeout(r, 2000));
    -  resp = await client.responses.retrieve(resp.id);
    -}
    -console.log(resp.status, resp.output_text);
    -
    -
    -
    # Inicia em background
    -curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{ "model": "gpt-5.5", "input": "Escreva um romance longo...", "background": true }'
    -
    -# Polling pelo id
    -curl https://api.openai.com/v1/responses/resp_123 \
    -  -H "Authorization: Bearer $OPENAI_API_KEY"
    -
    -# Cancelar (idempotente)
    -curl -X POST https://api.openai.com/v1/responses/resp_123/cancel \
    -  -H "Authorization: Bearer $OPENAI_API_KEY"
    -
    -
    -

    Você pode combinar background com stream: true para começar a receber eventos imediatamente; guarde o sequence_number de cada evento como cursor e, se a conexão cair, retome com ?stream=true&starting_after=<cursor>. Cancelar é idempotente.

    -
    Atenção: background=true requer store=true (requisições stateless são rejeitadas) e não é compatível com Zero Data Retention, pois guarda dados por ~10 minutos para o polling. Você só pode iniciar um stream a partir de uma resposta em background se a criou com stream=true.
    - -

    14.2 Webhooks (assinatura e verificação)

    -

    Webhooks entregam notificações em tempo real de eventos (ex.: response.completed, conclusão de batch ou fine-tuning) a um endpoint HTTP seu, seguindo a especificação Standard Webhooks. Verifique sempre a assinatura: configure o OPENAI_WEBHOOK_SECRET e use client.webhooks.unwrap(...), que lança erro se a assinatura for inválida.

    -
    -
    - - -
    -
    -
    import os
    -from flask import Flask, request, Response
    -from openai import OpenAI, InvalidWebhookSignatureError
    -
    -app = Flask(__name__)
    -client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
    -
    -@app.route("/webhook", methods=["POST"])
    -def webhook():
    -    try:
    -        event = client.webhooks.unwrap(request.data, request.headers)
    -        if event.type == "response.completed":
    -            resp = client.responses.retrieve(event.data.id)
    -            print("Saída:", resp.output_text)
    -        return Response(status=200)
    -    except InvalidWebhookSignatureError as e:
    -        return Response("Assinatura inválida", status=400)
    -
    -
    -
    import OpenAI from "openai";
    -import express from "express";
    -
    -const app = express();
    -const client = new OpenAI({ webhookSecret: process.env.OPENAI_WEBHOOK_SECRET });
    -
    -// Use o corpo cru — a verificação de assinatura precisa do texto original
    -app.use(express.text({ type: "application/json" }));
    -
    -app.post("/webhook", async (req, res) => {
    -  try {
    -    const event = await client.webhooks.unwrap(req.body, req.headers);
    -    if (event.type === "response.completed") {
    -      const resp = await client.responses.retrieve(event.data.id);
    -      console.log("Saída:", resp.output_text);
    -    }
    -    res.status(200).send();
    -  } catch (error) {
    -    if (error instanceof OpenAI.InvalidWebhookSignatureError) {
    -      res.status(400).send("Assinatura inválida");
    -    } else throw error;
    -  }
    -});
    -
    -
    -
    Cuidado: use o corpo cru (raw body) na verificação — em Express, express.text(), não express.json(). Sem isso, a assinatura não confere.
    - - -
    - -
    -

    15. Prompt caching

    -

    O Prompt Caching roteia requisições para servidores que processaram recentemente o mesmo prefixo, reduzindo latência em até ~80% e custo de tokens de entrada em até ~90%. É automático (sem mudança de código, sem custo extra) para prompts de 1024 tokens ou mais, e os hits aparecem em usage.input_tokens_details.cached_tokens na Responses API (ou usage.prompt_tokens_details.cached_tokens em Chat Completions); prompts abaixo de 1024 tokens sempre reportam cached_tokens igual a 0.

    - -

    15.1 Estruturando para cache

    -

    Cache hits exigem prefixo idêntico. Coloque conteúdo estático (instruções, exemplos, schema, tools, imagens) no início do prompt e o conteúdo variável (dados do usuário) no fim. Pode ser cacheado: o array de mensagens completo, imagens (com detail idêntico), o array tools, e o schema de Structured Outputs.

    - -

    15.2 prompt_cache_key e retenção

    -

    Para tráfego repetido com prefixos comuns, use prompt_cache_key de forma consistente: ele é combinado ao hash do prefixo para melhorar o roteamento e a taxa de acerto. Mantenha cada par prefixo+chave abaixo de ~15 requisições por minuto para evitar overflow. Monitore usage.input_tokens_details.cached_tokens na Responses API (em Chat Completions, usage.prompt_tokens_details.cached_tokens).

    -
    {
    -  "model": "gpt-5.5",
    -  "input": "...",
    -  "prompt_cache_key": "checkout-v3",
    -  "prompt_cache_retention": "24h"
    -}
    -

    O parâmetro prompt_cache_retention aceita in_memory (cache em memória volátil, 5–10 min de inatividade até ~1h) e 24h (retenção estendida, até 24h, descarregando tensores key/value para storage GPU-local). Atual (confirmado no changelog oficial): o padrão é 24h para organizações sem ZDR (Zero Data Retention) em todos os modelos elegíveis de v1/responses, v1/chat/completions e v1/batch — antes, a maioria dos modelos usava in_memory por padrão. Para gpt-5.5, gpt-5.5-pro e modelos futuros, o padrão é 24h e in_memory não é mais suportado (retorna erro de request). Data UNVERIFIED A mudança consta na seção "May 2026" do changelog; o dia exato (citado antes como 2026-05-29) não foi confirmável linha a linha na fonte — o fato em si está confirmado.

    -
    Nota: caches não são compartilhados entre organizações; o caching não altera a saída gerada (só o prefixo é cacheado, a resposta é recalculada) nem isenta tokens dos limites de TPM. Não há limpeza manual de cache.
    - -

    15.3 Caching explícito (família gpt-5.6 e posteriores) 2026-07-09

    -

    A partir de gpt-5.6, o caching ficou mais previsível e controlável. Além do caching implícito (que detecta prefixos automaticamente), você pode marcar breakpoints explícitos no fim de um prefixo reutilizável:

    -
      -
    • prompt_cache_breakpoint: {"mode":"explicit"} em blocos de conteúdo suportados (input_text, input_image, input_file) na Responses API — marca onde termina o prefixo reaproveitável.
    • -
    • prompt_cache_options.mode: implicit (padrão — coloca um breakpoint automático na última mensagem, além dos explícitos que você adicionar) ou explicit (desativa o automático; só os breakpoints explícitos são usados para leitura/escrita de cache).
    • -
    • prompt_cache_options.ttl: define uma vida mínima do cache (piso, não teto). O único valor suportado é "30m" — o prefixo fica reutilizável por ao menos 30 minutos (a OpenAI pode mantê-lo ativo por mais).
    • -
    • prompt_cache_key passa a ser obrigatório para matching confiável (tanto no modo implícito quanto no explícito).
    • -
    • Limites: até 4 escritas de cache por request — no modo implicit, o breakpoint automático da última mensagem consome 1 dos 4 slots (sobram até 3 explícitos); no modo explicit, até 4 explícitos. Breakpoints de turnos anteriores são read-only (dão hit, mas não são re-escritos). A leitura considera os últimos 50 breakpoints da conversa; havendo vários matches, lê-se o prefixo mais longo.
    • -
    • prompt_cache_retention está deprecated para gpt-5.6+ — as semânticas são diferentes: retention (≤5.5) escolhe uma política de retenção máxima; ttl (5.6+) define uma vida mínima. Não misture os dois.
    • -
    -
    Política por workflow (a camada de decisão): chat comum → implicit puro; prefixo grande e estável (sistema+tools+KB) reusado por muitos requests → implicit + 1–3 breakpoints explícitos após os blocos estáveis; pipeline com prefixos controlados e tráfego previsível → mode:"explicit" (só cacheia o que você marcou — sem breakpoint, sem cobrança de write); upload one-shot / prompt que não repete → não marque breakpoint (write de 1,25× sem reuso é só +25% de custo perdido). Breakeven: o write custa 0,25× extra e cada read economiza 0,9× — um único reuso já paga a escrita (derivação na contagem de tokens). Sinais para revisar a política: cache_write_tokens alto com cached_tokens baixo (está pagando write sem colher read) ou hit rate caindo com >15 req/min por prompt_cache_key (particione as keys).
    -
    Mudança de custo: em gpt-5.6+, a escrita de cache passa a custar 1,25× a taxa de input não-cacheado (rastreada no campo cache_write_tokens) — antes as escritas eram gratuitas. A leitura de cache mantém o desconto de 90% (input cacheado = 10% do input padrão). Modelos gpt-5.5 e anteriores usam apenas o caching implícito com prompt_cache_retention e rejeitam prompt_cache_options / prompt_cache_breakpoint se enviados.
    - - -
    - -
    -

    16. Contagem de tokens (texto)

    -

    Tokens são a unidade de medida de entrada e saída. A janela de contexto é o total máximo de tokens por requisição, incluindo input, output e reasoning. Estouros podem truncar a saída — confira a janela na página de cada modelo.

    - -

    16.1 Como contar

    -

    Para texto puro, use o tiktoken ou a ferramenta de tokenizer da plataforma. Para entradas que incluem imagens, arquivos, tools ou conversas, estimativas locais (tipo caracteres / 4) são imprecisas — use o endpoint de contagem de tokens de entrada, que aceita o mesmo payload da Responses API e devolve a contagem exata que o modelo receberá.

    -
    POST /v1/responses/input_tokens
    -# Resposta: { "object": "response.input_tokens", "input_tokens": 1234 }
    -
    -
    - - -
    -
    -
    count = client.responses.input_tokens.count(
    -    model="gpt-5.5",
    -    input=[{"role": "user", "content": "Quantos tokens isto usa?"}],
    -)
    -print(count.input_tokens)
    -
    -
    -
    const count = await client.responses.inputTokens.count({
    -  model: "gpt-5.5",
    -  input: [{ role: "user", content: "Quantos tokens isto usa?" }],
    -});
    -console.log(count.input_tokens);
    -
    -
    - -

    16.2 Otimização e custos

    -

    Após a chamada, o objeto usage reporta o consumo real: input_tokens (com cached_tokens em input_tokens_details), output_tokens (com reasoning_tokens em output_tokens_details) e total_tokens. Os tokens de raciocínio são cobrados como saída. Para controlar custo, limite a geração com max_output_tokens, reduza o número de funções carregadas (ou use tool search) e aproveite o prompt caching.

    -
    Dica: use a contagem prévia de tokens para validar tamanho antes de enviar, estimar custo e rotear por tamanho (prompts menores para modelos mais rápidos como gpt-5.4-mini/gpt-5.4-nano).
    - - -
    - -

    Parte B — Imagem & Visão

    Geração e edição de imagens com gpt-image-2, entrada de imagens (visão) na Responses API e como a tokenização de imagem afeta custos.

    - -
    -

    17. Geração de imagens (gpt-image-2)

    -

    - O modelo de geração de imagens atual e estado da arte é o gpt-image-2 (snapshot fixável - gpt-image-2-2026-04-21): ele entende texto e imagens, usa conhecimento de mundo para criar cenas - realistas e tem forte aderência a instruções. Esse é o ID confirmado na página oficial de modelos e no guia de - geração de imagens. Há dois caminhos para gerar imagens: -

    -
    - - - - - - - - - - - - - - -
    CaminhoQuando usarModelo no campo model
    Image API
    /v1/images/generations
    Gerar/editar uma imagem a partir de um único prompt, sem conversa.gpt-image-2 (modelo de imagem direto)
    Responses API
    tool image_generation
    Experiências conversacionais e multi-turno, com edição iterativa e entrada de imagens por file_id.Um modelo mainline com texto (ex.: gpt-5.5) que chama a tool — o GPT Image roda por baixo.
    -
    - -
    Nota: na Responses API, o valor de model é sempre um modelo de texto (por exemplo gpt-5.5) com a tool image_generation habilitada — gpt-image-2 não é um valor válido em model nesse fluxo. Na Image API, ao contrário, você passa gpt-image-2 diretamente em model.
    - -
    Atenção: antes de usar GPT Image (incluindo gpt-image-2) sua organização pode precisar concluir a API Organization Verification no console de desenvolvedor.
    - -
    Nota — referência de API desatualizada: alguns exemplos na API Reference de /v1/images ainda mostram um ID de modelo de imagem anterior no campo model. Isso é apenas texto de exemplo desatualizado — o ID canônico e recomendado para geração e edição é gpt-image-2.
    - -
    Nota — família de modelos de imagem (2026-06-29): o default e SOTA é gpt-image-2 — use sempre ele em novos projetos. Os demais estão todos depreciados: gpt-image-1-mini, gpt-image-1.5 e chatgpt-image-latest têm sunset em 2026-12-01 (anunciado 2026-06-02); gpt-image-1 tem sunset em 2026-10-23. dall-e-2/dall-e-3 já foram removidos da API (2026-05-12). Em todos os casos migre para gpt-image-2. Fonte: developers.openai.com/api/docs/deprecations.
    - -

    17.1 Gerar e salvar a imagem

    -

    - Os dois caminhos retornam a imagem em base64. Na Image API o conteúdo vem em - result.data[0].b64_json; na Responses API ele aparece no item de saída do tipo - image_generation_call, no campo result. Decodifique o base64 e grave os bytes em disco. -

    - -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -import base64
    -
    -client = OpenAI()
    -
    -# Caminho 1 — Image API (modelo de imagem direto)
    -result = client.images.generate(
    -    model="gpt-image-2",
    -    prompt="Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
    -    size="1024x1024",
    -    quality="high",
    -)
    -image_bytes = base64.b64decode(result.data[0].b64_json)
    -with open("gato_lontra.png", "wb") as f:
    -    f.write(image_bytes)
    -
    -# Caminho 2 — Responses API (tool image_generation; modelo mainline)
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    input="Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
    -    tools=[{"type": "image_generation"}],
    -)
    -image_data = [
    -    out.result
    -    for out in response.output
    -    if out.type == "image_generation_call"
    -]
    -if image_data:
    -    with open("gato_lontra_resp.png", "wb") as f:
    -        f.write(base64.b64decode(image_data[0]))
    -
    -
    -
    import OpenAI from "openai";
    -import fs from "fs";
    -
    -const client = new OpenAI();
    -
    -// Caminho 1 — Image API
    -const result = await client.images.generate({
    -  model: "gpt-image-2",
    -  prompt: "Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
    -  size: "1024x1024",
    -  quality: "high",
    -});
    -fs.writeFileSync("gato_lontra.png", Buffer.from(result.data[0].b64_json, "base64"));
    -
    -// Caminho 2 — Responses API (tool image_generation)
    -const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
    -  tools: [{ type: "image_generation" }],
    -});
    -const imageData = response.output
    -  .filter((o) => o.type === "image_generation_call")
    -  .map((o) => o.result);
    -if (imageData.length > 0) {
    -  fs.writeFileSync("gato_lontra_resp.png", Buffer.from(imageData[0], "base64"));
    -}
    -
    -
    -
    curl -X POST "https://api.openai.com/v1/images/generations" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "gpt-image-2",
    -    "prompt": "Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
    -    "n": 1,
    -    "size": "1024x1024",
    -    "quality": "high"
    -  }' | jq -r '.data[0].b64_json' | base64 --decode > gato_lontra.png
    -
    -
    - -
    Nota: a resposta inclui usage com input_tokens, output_tokens e total_tokens (mais input_tokens_details separando text_tokens de image_tokens). Use esses campos para medir custo real — ver a seção 20.
    - -

    17.2 Parâmetros de saída

    -

    Tanto a Image API quanto a tool da Responses API aceitam as mesmas opções de saída:

    -
    - - - - - - - - - - - - - - -
    ParâmetroValoresDescrição
    promptstringDescrição da imagem desejada.
    size1024x1024, 1536x1024, 1024x1536, 2048x2048, 3840x2160, … ou autoDimensões. O gpt-image-2 aceita resoluções flexíveis dentro das restrições da seção 17.3. auto deixa o modelo escolher.
    qualitylow, medium, high, auto padrão: autolow é o mais rápido (rascunhos, miniaturas); suba para medium/high nos finais.
    backgroundopaque, autoFundo opaco ou automático. O gpt-image-2 não suporta fundo transparente; background: "transparent" falha.
    output_format / formatopng (padrão), jpeg, webpFormato do arquivo de saída. jpeg é mais rápido que png — prefira-o se latência importa.
    output_compression0–100Nível de compressão para jpeg/webp. Ex.: 50 comprime ~50%.
    ninteiroNúmero de imagens por requisição (padrão 1).
    moderationauto (padrão), lowRigor de moderação de conteúdo. low é menos restritivo.
    partial_images0–3Quantas imagens parciais receber em streaming (ver 17.4).
    action toolauto (padrão), generate, editSó na tool da Responses API: força gerar nova imagem ou editar uma já no contexto.
    -
    -
    Dica: na Responses API você força a chamada da tool com tool_choice = {"type": "image_generation"}. As opções de saída acima entram dentro do objeto da tool, ex.: tools=[{"type": "image_generation", "quality": "high", "partial_images": 2}].
    - -

    17.3 Resoluções suportadas e prompt revisado

    -

    O gpt-image-2 aceita milhares de resoluções, desde que respeitem:

    -
    - - - - - - - - -
    Restrição de sizeRegra
    Borda máximaLado mais longo ≤ 3840px
    MúltiploAmbos os lados múltiplos de 16px
    ProporçãoRazão lado longo : lado curto ≤ 3:1
    Pixels totais≥ 655.360 e ≤ 8.294.400
    -
    -

    - Saídas acima de 2560x1440 (~3,69 MP, o "2K") são consideradas experimentais. - Imagens quadradas costumam ser as mais rápidas de gerar. -

    -

    - Ao usar a tool na Responses API, o modelo mainline (ex.: gpt-5.5) reescreve automaticamente seu prompt - para melhorar o resultado. Você lê o texto final em revised_prompt dentro do image_generation_call: -

    -
    {
    -  "id": "ig_123",
    -  "type": "image_generation_call",
    -  "status": "completed",
    -  "revised_prompt": "A gray tabby cat hugging an otter wearing an orange scarf...",
    -  "result": "...base64..."
    -}
    - -

    17.4 Streaming de imagens parciais

    -

    - Para feedback visual mais rápido, ative partial_images (1–3). Com 0 você recebe apenas a imagem final; - com valores maiores você pode receber menos parciais do que pediu, caso a imagem fique pronta antes. -

    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -import base64
    -
    -client = OpenAI()
    -
    -# Image API: evento image_generation.partial_image / b64_json
    -stream = client.images.generate(
    -    model="gpt-image-2",
    -    prompt="Um rio feito de penas brancas de coruja serpenteando por uma paisagem de inverno",
    -    stream=True,
    -    partial_images=2,
    -)
    -for event in stream:
    -    if event.type == "image_generation.partial_image":
    -        idx = event.partial_image_index
    -        with open(f"rio_{idx}.png", "wb") as f:
    -            f.write(base64.b64decode(event.b64_json))
    -
    -# Responses API: evento response.image_generation_call.partial_image / partial_image_b64
    -resp_stream = client.responses.create(
    -    model="gpt-5.5",
    -    input="Desenhe um rio feito de penas brancas de coruja numa paisagem de inverno serena",
    -    stream=True,
    -    tools=[{"type": "image_generation", "partial_images": 2}],
    -)
    -for event in resp_stream:
    -    if event.type == "response.image_generation_call.partial_image":
    -        idx = event.partial_image_index
    -        with open(f"rio_resp_{idx}.png", "wb") as f:
    -            f.write(base64.b64decode(event.partial_image_b64))
    -
    -
    -
    import OpenAI from "openai";
    -import fs from "fs";
    -
    -const client = new OpenAI();
    -
    -// Image API
    -const stream = await client.images.generate({
    -  model: "gpt-image-2",
    -  prompt: "Um rio feito de penas brancas de coruja numa paisagem de inverno",
    -  stream: true,
    -  partial_images: 2,
    -});
    -for await (const event of stream) {
    -  if (event.type === "image_generation.partial_image") {
    -    const idx = event.partial_image_index;
    -    fs.writeFileSync(`rio_${idx}.png`, Buffer.from(event.b64_json, "base64"));
    -  }
    -}
    -
    -// Responses API
    -const respStream = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Desenhe um rio feito de penas brancas de coruja numa paisagem de inverno",
    -  stream: true,
    -  tools: [{ type: "image_generation", partial_images: 2 }],
    -});
    -for await (const event of respStream) {
    -  if (event.type === "response.image_generation_call.partial_image") {
    -    const idx = event.partial_image_index;
    -    fs.writeFileSync(`rio_resp_${idx}.png`, Buffer.from(event.partial_image_b64, "base64"));
    -  }
    -}
    -
    -
    -
    curl -s -N -X POST "https://api.openai.com/v1/images/generations" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "gpt-image-2",
    -    "prompt": "Um rio feito de penas brancas de coruja numa paisagem de inverno",
    -    "size": "1024x1024",
    -    "stream": true,
    -    "partial_images": 2
    -  }'
    -# Eventos SSE: image_generation.partial_image (com b64_json e partial_image_index)
    -# e image_generation.completed (com b64_json final e usage)
    -
    -
    -
    Atenção: cada imagem parcial em streaming custa +100 tokens de imagem de saída. Use partial_images com parcimônia em produção de alto volume.
    - -
    Nota — proveniência: a OpenAI declara, fora da referência de API, que imagens geradas por GPT Image carregam metadados de proveniência no padrão C2PA. A referência de API consultada não documenta esse comportamento, então trate o detalhe como UNVERIFIED e não dependa dele em fluxos críticos sem confirmar na documentação atual.
    - - -
    - -
    -

    18. Edição & inpainting

    -

    - O endpoint de edições (/v1/images/edits) e a tool image_generation na Responses API permitem três coisas: - editar uma imagem existente, gerar uma nova usando outras como referência, e substituir uma região específica via máscara (inpainting). -

    - -

    18.1 Editar e combinar imagens de referência

    -

    - Passe uma ou mais imagens de entrada. Com várias referências, o modelo combina os elementos no resultado. - Na Image API você envia os bytes (multipart/form-data); na Responses API você pode referenciar por - file_id da Files API. -

    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -import base64
    -
    -client = OpenAI()
    -
    -prompt = (
    -    "Gere uma imagem fotorrealista de uma cesta de presentes em fundo branco, "
    -    "rotulada 'Relax & Unwind', contendo todos os itens das imagens de referência."
    -)
    -
    -result = client.images.edit(
    -    model="gpt-image-2",
    -    image=[
    -        open("body-lotion.png", "rb"),
    -        open("bath-bomb.png", "rb"),
    -        open("incense-kit.png", "rb"),
    -        open("soap.png", "rb"),
    -    ],
    -    prompt=prompt,
    -)
    -with open("cesta.png", "wb") as f:
    -    f.write(base64.b64decode(result.data[0].b64_json))
    -
    -
    -
    import fs from "fs";
    -import OpenAI, { toFile } from "openai";
    -
    -const client = new OpenAI();
    -
    -const files = ["bath-bomb.png", "body-lotion.png", "incense-kit.png", "soap.png"];
    -const images = await Promise.all(
    -  files.map((file) => toFile(fs.createReadStream(file), null, { type: "image/png" }))
    -);
    -
    -const response = await client.images.edit({
    -  model: "gpt-image-2",
    -  image: images,
    -  prompt: "Gere uma cesta de presentes fotorrealista em fundo branco com todos os itens das referências.",
    -});
    -fs.writeFileSync("cesta.png", Buffer.from(response.data[0].b64_json, "base64"));
    -
    -
    -
    curl -s -X POST "https://api.openai.com/v1/images/edits" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -F "model=gpt-image-2" \
    -  -F "image[]=@body-lotion.png" \
    -  -F "image[]=@bath-bomb.png" \
    -  -F "image[]=@incense-kit.png" \
    -  -F "image[]=@soap.png" \
    -  -F 'prompt=Gere uma cesta de presentes fotorrealista em fundo branco com todos os itens das referências' \
    -  | jq -r '.data[0].b64_json' | base64 --decode > cesta.png
    -
    -
    -
    Dica: a geração funciona melhor com verbos como desenhe ou edite. Para combinar imagens, em vez de "combine" ou "mescle", peça algo como "edite a primeira imagem adicionando este elemento da segunda imagem".
    - -

    18.2 Inpainting com máscara

    -

    - A máscara indica qual região da imagem deve ser substituída. Na Image API, passe mask junto com image; - na Responses API, use input_image_mask dentro da tool, apontando para o file_id da máscara. - Se você fornecer várias imagens de entrada, a máscara é aplicada à primeira. -

    -
    Nota: o mascaramento no GPT Image é guiado por prompt. O modelo usa a máscara como orientação, mas pode não seguir o contorno exato com precisão absoluta.
    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -import base64
    -
    -client = OpenAI()
    -
    -# Image API: image + mask (mesmo formato/tamanho; máscara com canal alfa)
    -result = client.images.edit(
    -    model="gpt-image-2",
    -    image=open("sunlit_lounge.png", "rb"),
    -    mask=open("mask.png", "rb"),
    -    prompt="Uma sala de estar iluminada pelo sol com uma piscina contendo um flamingo",
    -)
    -with open("lounge.png", "wb") as f:
    -    f.write(base64.b64decode(result.data[0].b64_json))
    -
    -# Responses API: input_image_mask por file_id, dentro da tool
    -file_id = create_file("sunlit_lounge.png")  # purpose="vision"
    -mask_id = create_file("mask.png")
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    input=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "input_text", "text": "Mesma sala iluminada, mas a piscina deve conter um flamingo"},
    -            {"type": "input_image", "file_id": file_id},
    -        ],
    -    }],
    -    tools=[{
    -        "type": "image_generation",
    -        "quality": "high",
    -        "input_image_mask": {"file_id": mask_id},
    -    }],
    -)
    -data = [o.result for o in response.output if o.type == "image_generation_call"]
    -if data:
    -    with open("lounge_resp.png", "wb") as f:
    -        f.write(base64.b64decode(data[0]))
    -
    -
    -
    import fs from "fs";
    -import OpenAI, { toFile } from "openai";
    -
    -const client = new OpenAI();
    -
    -// Image API
    -const rsp = await client.images.edit({
    -  model: "gpt-image-2",
    -  image: await toFile(fs.createReadStream("sunlit_lounge.png"), null, { type: "image/png" }),
    -  mask: await toFile(fs.createReadStream("mask.png"), null, { type: "image/png" }),
    -  prompt: "Uma sala iluminada pelo sol com uma piscina contendo um flamingo",
    -});
    -fs.writeFileSync("lounge.png", Buffer.from(rsp.data[0].b64_json, "base64"));
    -
    -// Responses API com input_image_mask
    -const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: [{
    -    role: "user",
    -    content: [
    -      { type: "input_text", text: "Mesma sala iluminada, mas a piscina deve conter um flamingo" },
    -      { type: "input_image", file_id: fileId },
    -    ],
    -  }],
    -  tools: [{ type: "image_generation", quality: "high", input_image_mask: { file_id: maskId } }],
    -});
    -
    -
    -
    curl -s -X POST "https://api.openai.com/v1/images/edits" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -F "model=gpt-image-2" \
    -  -F "image[]=@sunlit_lounge.png" \
    -  -F "mask=@mask.png" \
    -  -F 'prompt=Uma sala iluminada pelo sol com uma piscina contendo um flamingo' \
    -  | jq -r '.data[0].b64_json' | base64 --decode > lounge.png
    -
    -
    - -

    Requisitos da máscara

    -
      -
    • A imagem a editar e a máscara devem ter o mesmo formato e tamanho (cada uma com menos de 50 MB).
    • -
    • A máscara precisa ter um canal alfa — a transparência define a área a substituir. Salve a máscara preservando o alfa.
    • -
    • É possível converter uma máscara preto e branco em RGBA por código, usando a própria máscara para preencher o canal alfa:
    • -
    -
    from PIL import Image
    -from io import BytesIO
    -
    -mask = Image.open("mask_pb.png").convert("L")   # 1. carrega como tons de cinza
    -mask_rgba = mask.convert("RGBA")                  # 2. espaço para canal alfa
    -mask_rgba.putalpha(mask)                          # 3. usa a própria máscara como alfa
    -
    -buf = BytesIO()
    -mask_rgba.save(buf, format="PNG")                 # 4. serializa em PNG
    -with open("mask_alpha.png", "wb") as f:           # 5. salva
    -    f.write(buf.getvalue())
    - -

    18.3 input_fidelity e edição multi-turno

    -

    - O parâmetro input_fidelity controla quão fortemente o modelo preserva os detalhes das imagens de entrada - durante edições e fluxos com referência. Para gpt-image-2, omita esse parâmetro: a API não - permite alterá-lo porque o modelo já processa toda imagem de entrada em alta fidelidade automaticamente. -

    -
    Atenção: como o gpt-image-2 sempre trata entradas em alta fidelidade, requisições de edição que incluem imagens de referência podem consumir mais tokens de imagem de entrada. Considere isso no custo (seção 20).
    -

    - Na Responses API a edição é naturalmente multi-turno: você continua a conversa referenciando o - previous_response_id ou reinjetando o item image_generation_call (pelo id) num turno seguinte. - Use action: "edit" para forçar edição de uma imagem já no contexto (forçar edit sem imagem em contexto retorna erro); - action: "generate" força criar uma nova; auto deixa o modelo decidir. -

    -
    from openai import OpenAI
    -client = OpenAI()
    -
    -# Turno 1 — gera
    -r1 = client.responses.create(
    -    model="gpt-5.5",
    -    input="Gere um gato tabby cinza abraçando uma lontra com cachecol laranja",
    -    tools=[{"type": "image_generation"}],
    -)
    -
    -# Turno 2 — refina referenciando o turno anterior
    -r2 = client.responses.create(
    -    model="gpt-5.5",
    -    previous_response_id=r1.id,
    -    input="Agora deixe a imagem realista",
    -    tools=[{"type": "image_generation"}],
    -)
    - - -
    - -
    -

    19. Visão (entrada de imagens)

    -

    - Visão é a capacidade do modelo de "enxergar" e entender imagens — objetos, formas, cores, texturas e até - texto contido nelas. Na Responses API você envia imagens como conteúdo do tipo input_image, ao lado de - input_text, dentro de uma mensagem de usuário. -

    - -

    19.1 Três formas de passar a imagem

    -
    - - - - - - - -
    FormaCampo em input_imageQuando usar
    URL públicaimage_url (URL http(s))Imagem já hospedada e acessível publicamente.
    Base64 (data URL)image_url com data:image/jpeg;base64,...Imagem local, sem upload prévio; embute os bytes na requisição.
    File IDfile_idImagem enviada à Files API (purpose="vision"), reutilizável entre chamadas.
    -
    -

    Você pode passar várias imagens na mesma requisição, incluindo múltiplos itens input_image no array content — lembrando que cada imagem conta como tokens (seção 20).

    - -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -import base64
    -
    -client = OpenAI()
    -
    -def encode_image(path):
    -    with open(path, "rb") as f:
    -        return base64.b64encode(f.read()).decode("utf-8")
    -
    -b64 = encode_image("foto.jpg")
    -
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    input=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "input_text", "text": "O que há nestas imagens? Compare-as."},
    -            # 1) por URL pública
    -            {"type": "input_image",
    -             "image_url": "https://exemplo.com/imagem.jpg",
    -             "detail": "high"},
    -            # 2) por base64 (data URL)
    -            {"type": "input_image",
    -             "image_url": f"data:image/jpeg;base64,{b64}"},
    -            # 3) por file_id (Files API, purpose="vision")
    -            {"type": "input_image", "file_id": "file-abc123", "detail": "auto"},
    -        ],
    -    }],
    -)
    -print(response.output_text)
    -
    -
    -
    import fs from "fs";
    -import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -const b64 = fs.readFileSync("foto.jpg", "base64");
    -
    -const response = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: [{
    -    role: "user",
    -    content: [
    -      { type: "input_text", text: "O que há nestas imagens? Compare-as." },
    -      { type: "input_image", image_url: "https://exemplo.com/imagem.jpg", detail: "high" },
    -      { type: "input_image", image_url: `data:image/jpeg;base64,${b64}` },
    -      { type: "input_image", file_id: "file-abc123", detail: "auto" },
    -    ],
    -  }],
    -});
    -console.log(response.output_text);
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": [
    -      {
    -        "role": "user",
    -        "content": [
    -          {"type": "input_text", "text": "O que há nesta imagem?"},
    -          {
    -            "type": "input_image",
    -            "image_url": "https://exemplo.com/imagem.jpg",
    -            "detail": "high"
    -          }
    -        ]
    -      }
    -    ]
    -  }'
    -
    -
    -
    Dica: para subir a imagem à Files API antes de usar por file_id, crie o arquivo com client.files.create(file=open("foto.jpg","rb"), purpose="vision") e use o id retornado.
    - -

    19.2 Nível de detalhe (detail)

    -

    - O parâmetro detail diz ao modelo o nível de detalhe ao processar a imagem. Vale tanto na Responses API quanto na Chat Completions. - Se omitido, o padrão é auto. No gpt-5.5, auto e o comportamento padrão omitido equivalem a original. -

    -
    - - - - - - - - -
    NívelMelhor para
    lowEntendimento rápido e barato quando o detalhe fino não importa. O modelo recebe uma versão de 512px × 512px.
    highCompreensão de alta fidelidade padrão.
    originalImagens grandes, densas, espacialmente sensíveis ou de uso de computador. Disponível em gpt-5.4 e modelos futuros.
    autoSeleção automática. No gpt-5.5, equivale a original.
    -
    -

    Para uso de computador, localização e precisão de clique nos modelos gpt-5.4 e futuros, recomenda-se "detail": "original".

    - -
    Dica — detail ≠ raciocínio: detail resolve percepção (deixar a imagem legível). Depois que a imagem está legível, o gargalo costuma ser raciocínio, não percepção — jogar detail: "original" numa falha de raciocínio não ajuda. Para gráficos, tabelas, plantas e leitura composicional, aumente reasoning.effort (ex.: reasoning={"effort": "high"}) em vez de só subir o detail.
    - -

    19.3 Requisitos da imagem e comportamento de redimensionamento

    -
    - - - - - - - - -
    RequisitoValor
    Formatos suportadosPNG (.png), JPEG (.jpeg/.jpg), WEBP (.webp), GIF não animado (.gif)
    Tamanho do payloadAté 512 MB de payload total por requisição
    QuantidadeAté 1.500 imagens individuais por requisição
    OutrosSem marcas d'água/logos, sem conteúdo NSFW, nítida o bastante para um humano entender
    -
    -

    - Modelos diferentes redimensionam antes de tokenizar. Em gpt-5.5 e gpt-5.4: high permite até - 2.500 patches ou dimensão máxima de 2048px; original permite até 10.000 patches ou 6000px. - Se algum limite é excedido, a imagem é reduzida preservando a proporção até caber. Em gpt-5.4-mini e gpt-5.4-nano, - high permite até 1.536 patches ou 2048px (sem original). Detalhes da matemática na seção 20. -

    -
    Nota — limitações conhecidas de visão: imagens médicas especializadas (ex.: tomografias) não são adequadas; texto em alfabetos não latinos pode ter desempenho menor; texto pequeno deve ser ampliado (e "detail": "original" ajuda); imagens rotacionadas, panorâmicas ou olho-de-peixe confundem o modelo; contagens podem ser aproximadas; metadados e nomes de arquivo não são processados; e CAPTCHAs são bloqueados por segurança.
    - -

    19.4 Entradas de arquivo (input_file): PDF, documentos e planilhas

    -

    Além de imagens, a Responses API aceita arquivos como itens de conteúdo do tipo input_file — passados de três formas: URL externa (file_url), ID da Files API (file_id, após upload com purpose="user_data") ou base64 (file_data + filename). É o caminho para Q&A direto sobre um documento, sem montar um pipeline de RAG.

    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -client = OpenAI()
    -
    -# (a) Arquivo por URL externa — sem upload
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    input=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "input_text", "text": "Resuma os pontos-chave deste relatório."},
    -            {"type": "input_file", "file_url": "https://exemplo.com/relatorio.pdf"},
    -        ],
    -    }],
    -)
    -print(resp.output_text)
    -
    -# (b) Upload pela Files API e referência por file_id
    -f = client.files.create(file=open("contrato.pdf", "rb"), purpose="user_data")
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    input=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "input_file", "file_id": f.id},
    -            {"type": "input_text", "text": "Quais são as cláusulas de rescisão?"},
    -        ],
    -    }],
    -)
    -print(resp.output_text)
    -
    -
    -
    import OpenAI from "openai";
    -import fs from "fs";
    -const client = new OpenAI();
    -
    -// (a) Arquivo por URL externa — sem upload
    -let resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: [{
    -    role: "user",
    -    content: [
    -      { type: "input_text", text: "Resuma os pontos-chave deste relatório." },
    -      { type: "input_file", file_url: "https://exemplo.com/relatorio.pdf" },
    -    ],
    -  }],
    -});
    -console.log(resp.output_text);
    -
    -// (b) Upload pela Files API e referência por file_id
    -const f = await client.files.create({
    -  file: fs.createReadStream("contrato.pdf"),
    -  purpose: "user_data",
    -});
    -resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: [{
    -    role: "user",
    -    content: [
    -      { type: "input_file", file_id: f.id },
    -      { type: "input_text", text: "Quais são as cláusulas de rescisão?" },
    -    ],
    -  }],
    -});
    -console.log(resp.output_text);
    -
    -
    -
    Como cada tipo é processado: PDF — o modelo recebe o texto extraído e uma imagem de cada página (importa para layout/diagramas), então PDFs consomem mais tokens; documentos de texto (.txt/.md/.docx/.pptx/.html) — só o texto; planilhas (.csv/.xlsx) — augmentação específica que lê as primeiras 1.000 linhas. Para arquivos grandes ou muitos documentos, prefira File Search (RAG) em vez de despejar tudo como input_file.
    - - -
    - -
    -

    20. Tokenização & custos de imagem

    -

    - Imagens de entrada são medidas e cobradas em tokens, como o texto, e contam para o limite de tokens por minuto (TPM). - A forma de converter pixels em tokens depende da geração do modelo: os modelos gpt-5.x atuais usam o método - patch-based (por blocos de 32px); as gerações anteriores usavam o - método tile-based. Apresentamos o patch como principal e o tile apenas como nota de cálculo/migração. -

    - -

    20.1 Patch-based (método atual)

    -

    - O modelo cobre a imagem com patches de 32px × 32px e define um orçamento máximo de patches. O custo em tokens segue 4 passos: -

    -

    A. Conte quantos patches de 32px cobrem a imagem original (um patch pode ultrapassar a borda):

    -
    original_patch_count = ceil(width / 32) * ceil(height / 32)
    -

    B. Se exceder o orçamento de patches do modelo, reduza proporcionalmente até caber, ajustando a escala para que as dimensões inteiras finais permaneçam dentro do orçamento:

    -
    shrink_factor = sqrt((32**2 * patch_budget) / (width * height))
    -adjusted_shrink_factor = shrink_factor * min(
    -    floor(width  * shrink_factor / 32) / (width  * shrink_factor / 32),
    -    floor(height * shrink_factor / 32) / (height * shrink_factor / 32),
    -)
    -

    C. Converta a escala ajustada em pixels inteiros e reconte os patches. Esse é o número de tokens de imagem antes do multiplicador, limitado pelo orçamento:

    -
    resized_patch_count = ceil(resized_width / 32) * ceil(resized_height / 32)
    -

    D. Aplique o multiplicador do modelo para obter os tokens finais:

    -
    - - - - - - -
    ModeloMultiplicador
    gpt-5.4-mini1.62
    gpt-5.4-nano2.46
    -
    -
    Nota — gpt-5.5: o gpt-5.5 (frontier) não aparece na tabela de multiplicadores acima, o que significa multiplicador efetivo de ×1,0 — a contagem de patches já é a contagem de tokens de imagem. Seu orçamento de patches por nível de detalhe é maior: high = 2.500 patches (ou 2048px); original = 10.000 patches (ou 6000px); auto e o detalhe omitido equivalem a original. Para gpt-5.4-mini/gpt-5.4-nano, high = 1.536 patches.
    - -

    Exemplo (orçamento de 1.536 patches)

    -
      -
    • Imagem 1024 × 1024: ceil(1024/32) × ceil(1024/32) = 32 × 32 = 1024 patches. Está abaixo de 1.536, então não há redimensionamento. Tokens antes do multiplicador = 1024.
    • -
    • Imagem 1800 × 2400: original = 57 × 75 = 4275 patches (excede 1.536). shrink_factor ≈ 0,603 → adjusted ≈ 0,586 → redimensiona para 1056 × 1408 → 33 × 44 = 1452 patches. Tokens antes do multiplicador = 1452.
    • -
    -

    Em ambos, multiplique o resultado pelo fator do modelo (tabela acima) para obter as unidades de token cobradas.

    - -

    20.2 Tile-based (legado)

    -

    - Nas gerações anteriores ao gpt-5.x, o custo dependia de tamanho e detail — nenhum modelo SOTA atual - usa este método, mantido aqui apenas como referência de migração. - Com detail: "low" o custo era um número-base fixo de tokens. Com detail: "high": -

    -
      -
    1. Escala para caber num quadrado de 2048px × 2048px, mantendo a proporção.
    2. -
    3. Escala para que o menor lado fique com 768px.
    4. -
    5. Conta os quadrados de 512px; cada quadrado custava um valor fixo de tokens.
    6. -
    7. Soma os tokens-base ao total: tokens = base + (tokens_por_tile × nº de tiles).
    8. -
    -
    Nota: os valores de tokens-base e tokens por tile variavam por geração de modelo legado e não se aplicam a nenhum modelo atual. O método patch-based dos modelos gpt-5.x substitui inteiramente essa contagem por tiles; consulte a calculadora oficial para qualquer integração ativa.
    - -

    20.3 Custo de saída do gpt-image-2

    -

    - Para o gpt-image-2, o custo de saída depende de quality e size. Como ele aceita milhares de - resoluções, o caminho recomendado é estimar os tokens de saída pela calculadora oficial (a partir de - quality + size); a tabela abaixo lista os tamanhos clássicos confirmados, para comparação. O custo total de - uma requisição é a soma de: tokens de texto de entrada + tokens de imagem de entrada (se editando referências) + - tokens de imagem de saída. -

    -
    - - - - - - - -
    Qualidade1024×10241024×15361536×1024
    LowUS$ 0,006US$ 0,005US$ 0,005
    MediumUS$ 0,053US$ 0,041US$ 0,041
    HighUS$ 0,211US$ 0,165US$ 0,165
    -
    -
    Dica: uma resolução não quadrada maior às vezes gera menos tokens de saída do que uma menor/quadrada na mesma qualidade. E cada imagem parcial em streaming adiciona +100 tokens de saída.
    -
    Atenção — entradas em edição: como o gpt-image-2 processa toda imagem de entrada em alta fidelidade, edições com referências consomem mais tokens de imagem de entrada. Inclua isso ao estimar o custo. Preços são perecíveis — confirme sempre na calculadora e na página de preços oficiais.
    - -

    20.4 Receitas e exemplos oficiais (Cookbook)

    -

    - O OpenAI Cookbook traz receitas práticas de imagem e visão. Use as marcadas como atual como - referência: elas já usam gpt-image-2 para geração/edição e visão gpt-5.x pela Responses API. - Algumas receitas mais antigas continuam no ar com stack legado (modelos de imagem anteriores, - visão por Chat Completions); para essas, prefira o equivalente moderno indicado. -

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ReceitaO que ensinaStatus
    GPT Image Models Prompting GuidePrompting de geração e edição com gpt-image-2 (estrutura cena→sujeito→detalhes→constraints, texto na imagem, multi-imagem por índice, iteração).atual
    Document & Multimodal Understanding TipsVisão de documentos com gpt-5.4 na Responses API: detail="original", reasoning.effort, bounding boxes em grade 0–999, code_interpreter para crop/zoom.atual
    Grounded Spatial Reasoning & LayoutsRaciocínio espacial com gpt-5.5 + render gpt-image-2: separar semântica (modelo) de geometria (validação determinística); saída como spec JSON.atual
    Image EvalsAvaliar imagem geradas com padrão Gate → Grade → Tag e juiz multimodal gpt-5.x via Responses API (gates hard pass/fail antes de pontuar; nunca usar média para contornar um gate).atual
    Image Gen 1.5 Prompting GuidePrompting de geração em um modelo de imagem anterior. Equivalente moderno: trocar por gpt-image-2 e remover input_fidelity (no gpt-image-2 é automático).legado
    GPT-4 Vision with Function CallingVisão + tool calling via Chat Completions e biblioteca externa. Equivalente moderno: Responses API com input_image nativo + tools de função + Structured Outputs, em modelo gpt-5.x.legado
    Vision RAG com PineconeRAG sobre PDF com visão via Chat Completions. Equivalente moderno: Responses API com input_image/Files API nativo e visão gpt-5.x.legado
    Custom Image Embedding SearchBusca por similaridade com embedding de imagem local + QA por um modelo de visão anterior. Equivalente moderno: visão gpt-5.x pela Responses API; não tratar como padrão atual.legado
    -
    -
    Dica — padrão de edição que evita "drift": ao editar, descreva exatamente o que muda e o que permanece: "mude APENAS X; mantenha todo o resto exatamente igual" (rosto, pose, fundo, proporções). Repita a lista de preservação a cada iteração — isso reduz o desvio acumulado em edições multi-turno.
    - -

    - A seguir, três receitas mínimas em Python e JavaScript, fiéis aos exemplos oficiais da documentação: - geração de imagem, edição com máscara (inpainting) e visão. Todas usam gpt-image-2 para imagem e a Responses API - com input_image para visão — sem stacks legados e sem parâmetros inventados (no gpt-image-2, - input_fidelity é automático e não deve ser enviado). -

    - -

    Receita 1 — Geração de imagem com gpt-image-2 · via tool image_generation (Responses API) ou images.generate · image-generation#generate-images

    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -import base64
    -
    -client = OpenAI()
    -
    -# Caminho A — Responses API: tool image_generation no modelo mainline
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    input="Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
    -    tools=[{"type": "image_generation"}],
    -)
    -
    -# Coleta os resultados das chamadas de geração de imagem
    -image_data = [
    -    output.result
    -    for output in response.output
    -    if output.type == "image_generation_call"
    -]
    -
    -if image_data:
    -    image_base64 = image_data[0]
    -    with open("lontra.png", "wb") as f:
    -        f.write(base64.b64decode(image_base64))
    -
    -# Caminho B — Image API: modelo de imagem direto (retorna b64_json)
    -result = client.images.generate(
    -    model="gpt-image-2",
    -    prompt="Desenho de livro infantil: um veterinario auscultando uma lontra bebe",
    -)
    -image_bytes = base64.b64decode(result.data[0].b64_json)
    -with open("lontra_direto.png", "wb") as f:
    -    f.write(image_bytes)
    -
    -
    -
    -
    import OpenAI from "openai";
    -import fs from "fs";
    -
    -const openai = new OpenAI();
    -
    -// Caminho A — Responses API: tool image_generation no modelo mainline
    -const response = await openai.responses.create({
    -  model: "gpt-5.5",
    -  input: "Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
    -  tools: [{ type: "image_generation" }],
    -});
    -
    -// Coleta os resultados das chamadas de geração de imagem
    -const imageData = response.output
    -  .filter((output) => output.type === "image_generation_call")
    -  .map((output) => output.result);
    -
    -if (imageData.length > 0) {
    -  const imageBase64 = imageData[0];
    -  fs.writeFileSync("lontra.png", Buffer.from(imageBase64, "base64"));
    -}
    -
    -// Caminho B — Image API: modelo de imagem direto (retorna b64_json)
    -const result = await openai.images.generate({
    -  model: "gpt-image-2",
    -  prompt: "Desenho de livro infantil: um veterinario auscultando uma lontra bebe",
    -});
    -const imageBytes = Buffer.from(result.data[0].b64_json, "base64");
    -fs.writeFileSync("lontra_direto.png", imageBytes);
    -
    -
    -
    - -

    Receita 2 — Edição / inpainting com gpt-image-2 · images.edit com imagem + máscara (a máscara precisa de canal alfa) · image-generation#edit-images

    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -import base64
    -
    -client = OpenAI()
    -
    -# A máscara marca a área a substituir; imagem e máscara devem ter
    -# o mesmo formato e tamanho, e a máscara precisa de canal alfa.
    -result = client.images.edit(
    -    model="gpt-image-2",
    -    image=open("sunlit_lounge.png", "rb"),
    -    mask=open("mask.png", "rb"),
    -    prompt="Uma sala de estar ensolarada com uma piscina contendo um flamingo",
    -)
    -
    -image_bytes = base64.b64decode(result.data[0].b64_json)
    -with open("lounge_editado.png", "wb") as f:
    -    f.write(image_bytes)
    -
    -
    -
    -
    import fs from "fs";
    -import OpenAI, { toFile } from "openai";
    -
    -const client = new OpenAI();
    -
    -// A máscara marca a área a substituir; imagem e máscara devem ter
    -// o mesmo formato e tamanho, e a máscara precisa de canal alfa.
    -const rsp = await client.images.edit({
    -  model: "gpt-image-2",
    -  image: await toFile(fs.createReadStream("sunlit_lounge.png"), null, {
    -    type: "image/png",
    -  }),
    -  mask: await toFile(fs.createReadStream("mask.png"), null, {
    -    type: "image/png",
    -  }),
    -  prompt: "Uma sala de estar ensolarada com uma piscina contendo um flamingo",
    -});
    -
    -const imageBytes = Buffer.from(rsp.data[0].b64_json, "base64");
    -fs.writeFileSync("lounge_editado.png", imageBytes);
    -
    -
    -
    - -

    Receita 3 — Visão: analisar uma imagem com gpt-5.5 · Responses API com input_image (URL ou base64) · images-vision#analyze-images

    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -import base64
    -
    -client = OpenAI()
    -
    -# Opção 1 — imagem por URL pública
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    input=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "input_text", "text": "O que há nesta imagem?"},
    -            {
    -                "type": "input_image",
    -                "image_url": "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
    -            },
    -        ],
    -    }],
    -)
    -print(response.output_text)
    -
    -# Opção 2 — imagem local em base64 (data URL)
    -def encode_image(path):
    -    with open(path, "rb") as f:
    -        return base64.b64encode(f.read()).decode("utf-8")
    -
    -base64_image = encode_image("foto.jpg")
    -response = client.responses.create(
    -    model="gpt-5.5",
    -    input=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "input_text", "text": "Descreva esta imagem."},
    -            {
    -                "type": "input_image",
    -                "image_url": f"data:image/jpeg;base64,{base64_image}",
    -            },
    -        ],
    -    }],
    -)
    -print(response.output_text)
    -
    -
    -
    -
    import fs from "fs";
    -import OpenAI from "openai";
    -
    -const openai = new OpenAI();
    -
    -// Opção 1 — imagem por URL pública
    -const response = await openai.responses.create({
    -  model: "gpt-5.5",
    -  input: [{
    -    role: "user",
    -    content: [
    -      { type: "input_text", text: "O que há nesta imagem?" },
    -      {
    -        type: "input_image",
    -        image_url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
    -      },
    -    ],
    -  }],
    -});
    -console.log(response.output_text);
    -
    -// Opção 2 — imagem local em base64 (data URL)
    -const base64Image = fs.readFileSync("foto.jpg", "base64");
    -const response2 = await openai.responses.create({
    -  model: "gpt-5.5",
    -  input: [{
    -    role: "user",
    -    content: [
    -      { type: "input_text", text: "Descreva esta imagem." },
    -      {
    -        type: "input_image",
    -        image_url: `data:image/jpeg;base64,${base64Image}`,
    -      },
    -    ],
    -  }],
    -});
    -console.log(response2.output_text);
    -
    -
    -
    - - -
    - -

    Parte C — Áudio & Realtime

    Fala em tempo real (gpt-realtime-2), tradução e transcrição ao vivo, transcrição de arquivos (gpt-4o-transcribe), síntese de voz (gpt-4o-mini-tts) e áudio no chat (gpt-audio-1.5).

    - -
    -

    21. Visão geral de áudio

    -

    Os modelos de áudio da OpenAI sabem entender fala, gerar fala ou fazer as duas coisas na mesma interação. Antes de escrever código, vale fixar o vocabulário comum e, principalmente, decidir entre duas grandes arquiteturas: APIs baseadas em requisição (você envia um arquivo ou um texto e recebe uma resposta delimitada) e sessões em tempo real (uma conexão aberta por onde fluem áudio e eventos com baixa latência). Essa escolha define endpoint, transporte, modelo e complexidade do cliente.

    - -

    21.1 Modalidades de áudio

    -

    Uma aplicação de áudio combina uma ou mais destas modalidades. Pense nelas como "peças" que você liga ou desliga conforme a tarefa.

    -
    - - - - - - - - -
    ModalidadeO que éUsos comuns
    Entrada de áudioO modelo recebe som do usuário ou da aplicação.Agentes de voz, transcrição, tradução.
    Saída de áudioO modelo ou a API devolve áudio falado.Agentes de voz, text-to-speech, respostas faladas.
    Transcrição em textoA fala vira texto.Legendas, análise de chamadas, busca, registros.
    Prompt de textoTexto controla o que o modelo diz ou faz.Geração de fala, fluxos de voz roteirizados, prompts.
    -
    - -

    21.2 Tarefas comuns de fala

    -
      -
    • Speech-to-text (STT) — converte fala em texto. Para legendas, notas, transcrições, analytics, busca e acessibilidade. Pode ser baseada em requisição (arquivos) ou em streaming (áudio ao vivo).
    • -
    • Text-to-speech (TTS) — converte texto em áudio falado. Para narração, assistentes, acessibilidade e respostas geradas. A geração pode transmitir o áudio em streaming à medida que é produzido.
    • -
    • Speech-to-speech (S2S) — um único modelo escuta, raciocina e fala em uma sessão de baixa latência. Para agentes de voz conversacionais que respondem, chamam tools e mantêm estado de sessão.
    • -
    • Tradução de fala — escuta fala em um idioma e devolve áudio/transcrição traduzidos em outro idioma. Use uma sessão de tradução em tempo real quando a tradução deve começar continuamente conforme o áudio chega.
    • -
    - -

    21.3 Streaming e latência

    -

    Streaming significa que cliente e serviço trocam entrada ou saída parcial enquanto a interação ainda está ativa — essencial quando o usuário espera feedback imediato (legendas ao vivo, chamadas, agentes de voz, tradução). Latência mais baixa exige uma conexão em tempo real, manejo cuidadoso de mídia e um modelo de sessão capaz de emitir eventos parciais. As APIs baseadas em requisição são mais simples para upload de arquivos e trabalho não interativo, mas não suportam os mesmos padrões de interação ao vivo.

    - -

    21.4 APIs baseadas em requisição vs. sessões realtime

    -

    A OpenAI oferece três arquiteturas de áudio. Comece pelo resultado desejado e deixe ele escolher a arquitetura:

    -
    - - - - - - - -
    ArquiteturaUse quandoExemplos / endpoints
    APIs de áudio por requisiçãoVocê tem um arquivo, um texto ou uma requisição delimitada.Speech-to-text (/v1/audio/transcriptions), text-to-speech (/v1/audio/speech).
    Sessões em tempo realO áudio é ao vivo e o app precisa de eventos de baixa latência.Agentes de voz, tradução, transcrição — sobre /v1/realtime e endpoints irmãos.
    Chat multimodalVocê está estendendo um fluxo de chat existente com áudio.Entrada/saída de áudio em Chat Completions com gpt-audio-1.5.
    -
    - -

    21.5 Escolha de modelo por tarefa

    -

    Cada tarefa de áudio tem um modelo recomendado. Esta tabela é o mapa de toda a Parte C — as seções seguintes detalham cada linha.

    -
    - - - - - - - - - - - -
    ObjetivoModeloOnde detalhar
    Agente de voz de baixa latência (fala↔fala)gpt-realtime-2 realtimeSeções 22 e 28
    Traduzir fala ao vivo para outro idiomagpt-realtime-translateSeção 23
    Transcrever áudio ao vivo em texto contínuogpt-realtime-whisperSeção 24
    Transcrever arquivos / requisições delimitadasgpt-4o-transcribe, gpt-4o-mini-transcribe, gpt-4o-transcribe-diarizeSeção 25
    Tradução de áudio→inglês e timestamps/word-levelwhisper-1Seção 25
    Gerar fala a partir de textogpt-4o-mini-ttsSeção 26
    Adicionar áudio a um app de Chat Completionsgpt-audio-1.5Seção 27
    -
    -
    Nota: gpt-realtime-2 e gpt-audio-1.5 são nativamente multimodais — entendem e geram áudio e texto como entrada e saída. A diferença prática é o transporte: gpt-realtime-2 vive em uma sessão de streaming bidirecional; gpt-audio-1.5 responde a uma requisição de chat delimitada.
    - - -
    - -
    -

    22. Realtime API (gpt-realtime-2)

    -

    A Realtime API mantém uma conexão aberta enquanto sua aplicação envia áudio, recebe eventos e atualiza o estado da sessão. O modelo principal atual é o gpt-realtime-2.1 (lançado 2026-07-06), que atualiza o gpt-realtime-2 com melhor reconhecimento alfanumérico, tratamento de silêncio/ruído e comportamento de interrupção, mantendo fala↔fala com reasoning effort configurável, obediência a instruções e uso de tools para fluxos de agente complexos. Há também o gpt-realtime-2.1-mini, versão destilada mais rápida e barata. Para um modelo fala↔fala rápido e sem reasoning, há o gpt-realtime-1.5 (speech-to-speech rápido e confiável, sem reasoning; tem guia de prompting dedicado na doc oficial). O SDK Agents (Python e TS) já usa gpt-realtime-2.1 como default do RealtimeAgent.

    - -
    Dica: em produção, comece com reasoning.effort: "low" na maioria dos agentes de voz e suba só se a tarefa exigir — reasoning maior aumenta latência e tokens de saída.
    - -

    22.1 Tipos de sessão realtime

    -

    Uma sessão em tempo real é uma interação stateful. Existem três tipos, cada um com um propósito distinto:

    -
    - - - - - - - -
    Tipo de sessãoUse quandoEndpoint / padrão
    Sessão de agente de vozO modelo deve responder ao usuário, chamar tools e gerenciar o estado da conversa.Sessão de conversa em /v1/realtime
    Sessão de traduçãoO app deve traduzir fala continuamente conforme chega.Sessão contínua em /v1/realtime/translations (Seção 23)
    Sessão de transcriçãoO app precisa de deltas de transcrição sem resposta falada do modelo.Sessão type: "transcription" (Seção 24)
    -
    -

    Esta seção foca na sessão de agente de voz (fala↔fala). Os componentes do estado são: o objeto Session (modelo, voz, configuração), a Conversation (itens de entrada do usuário e de saída do modelo) e as Responses (itens de áudio/texto gerados que entram na conversa). A duração máxima de uma sessão Realtime é de 60 minutos.

    - -

    22.2 Transportes: WebRTC, WebSocket e SIP

    -

    Escolha o transporte pelo lugar onde sua aplicação captura e toca o áudio:

    -
    - - - - - - - -
    TransporteUse quandoCaracterística
    WebRTCCliente em navegador/mobile captura ou toca áudio diretamente.Mais robusto sob redes incertas; o WebRTC cuida da mídia (microfone via getUserMedia, saída via track remota).
    WebSocketSeu servidor já recebe áudio cru de um pipeline de mídia, sistema de chamadas ou worker.Interface de mais baixo nível: você envia e recebe chunks Base64 de áudio manualmente sobre o socket.
    SIPAgentes de voz por telefonia (PSTN via SIP trunking, ex.: Twilio).Webhook realtime.call.incoming → você aceita/rejeita a chamada e monitora via WebSocket. Confirme suporte do modelo antes de usar SIP para tradução/transcrição.
    -
    -
    Atenção: ao conectar de um cliente (navegador ou mobile), prefira WebRTC a WebSocket — desempenho mais consistente. Use WebSocket para integração servidor↔servidor, onde a chave de API fica segura no backend.
    - -

    22.2.1 WebRTC: interface unificada e token efêmero

    -

    Há dois mecanismos para conectar do navegador via WebRTC: a interface unificada (seu servidor encaminha o SDP e fica no caminho crítico da inicialização) ou tokens efêmeros (seu servidor emite um client secret de curta duração e o navegador conecta direto). Em ambos, a chave de API padrão só existe no servidor. A negociação WebRTC é feita contra POST /v1/realtime/calls (SDP), e o token efêmero vem de POST /v1/realtime/client_secrets.

    -
    -
    - - - -
    -
    -
    # Servidor: emite um client secret efêmero (Python + SDK oficial)
    -from openai import OpenAI
    -
    -client = OpenAI()
    -
    -# O client secret de curta duração que o navegador usará para conectar via WebRTC.
    -secret = client.realtime.client_secrets.create(
    -    session={
    -        "type": "realtime",
    -        "model": "gpt-realtime-2",
    -        "audio": {"output": {"voice": "marin"}},
    -    },
    -)
    -
    -print(secret.value)  # ek_... -> devolva ao navegador (NUNCA exponha a chave de API)
    -
    -
    -
    -
    // Navegador: conecta ao Realtime via WebRTC usando o token efêmero do servidor
    -const tokenResponse = await fetch("/token");
    -const { value: EPHEMERAL_KEY } = await tokenResponse.json();
    -
    -const pc = new RTCPeerConnection();
    -
    -// Toca o áudio remoto vindo do modelo
    -const audioEl = document.createElement("audio");
    -audioEl.autoplay = true;
    -pc.ontrack = (e) => (audioEl.srcObject = e.streams[0]);
    -
    -// Microfone local como track de entrada
    -const ms = await navigator.mediaDevices.getUserMedia({ audio: true });
    -pc.addTrack(ms.getTracks()[0]);
    -
    -// Canal de dados para eventos cliente/servidor
    -const dc = pc.createDataChannel("oai-events");
    -dc.addEventListener("message", (e) => console.log(JSON.parse(e.data)));
    -
    -// Negociação SDP contra /v1/realtime/calls
    -const offer = await pc.createOffer();
    -await pc.setLocalDescription(offer);
    -const sdpResponse = await fetch("https://api.openai.com/v1/realtime/calls", {
    -  method: "POST",
    -  body: offer.sdp,
    -  headers: {
    -    Authorization: `Bearer ${EPHEMERAL_KEY}`,
    -    "Content-Type": "application/sdp",
    -  },
    -});
    -await pc.setRemoteDescription({ type: "answer", sdp: await sdpResponse.text() });
    -
    -
    -
    -
    # Servidor: mintar um client secret efêmero para o navegador
    -curl https://api.openai.com/v1/realtime/client_secrets \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -H "OpenAI-Safety-Identifier: hashed-user-id" \
    -  -d '{
    -    "session": {
    -      "type": "realtime",
    -      "model": "gpt-realtime-2",
    -      "audio": { "output": { "voice": "marin" } }
    -    }
    -  }'
    -
    -
    -
    - -

    22.2.2 WebSocket: servidor↔servidor

    -

    Para integração de backend, conecte direto via WebSocket com a chave de API padrão (segura no servidor). Inclua, quando aplicável, o cabeçalho OpenAI-Safety-Identifier com um identificador estável e que preserve privacidade (ex.: hash do ID interno do usuário).

    -
    -
    - - - -
    -
    -
    # pip install websocket-client
    -import os, json, websocket
    -
    -url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2"
    -headers = [
    -    "Authorization: Bearer " + os.environ["OPENAI_API_KEY"],
    -    "OpenAI-Safety-Identifier: hashed-user-id",
    -]
    -
    -def on_open(ws):
    -    ws.send(json.dumps({
    -        "type": "session.update",
    -        "session": {"type": "realtime", "instructions": "Seja claro e breve."},
    -    }))
    -
    -def on_message(ws, message):
    -    print(json.loads(message))
    -
    -ws = websocket.WebSocketApp(url, header=headers, on_open=on_open, on_message=on_message)
    -ws.run_forever()
    -
    -
    -
    -
    import WebSocket from "ws";
    -
    -const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2";
    -const ws = new WebSocket(url, {
    -  headers: {
    -    Authorization: "Bearer " + process.env.OPENAI_API_KEY,
    -    "OpenAI-Safety-Identifier": "hashed-user-id",
    -  },
    -});
    -
    -ws.on("open", () => {
    -  ws.send(JSON.stringify({
    -    type: "session.update",
    -    session: { type: "realtime", instructions: "Seja claro e breve." },
    -  }));
    -});
    -
    -ws.on("message", (message) => console.log(JSON.parse(message.toString())));
    -
    -
    -
    -
    # WebSocket não é um verbo HTTP simples; o handshake é um GET com upgrade.
    -# A URL e os cabeçalhos de autenticação são:
    -#   wss://api.openai.com/v1/realtime?model=gpt-realtime-2
    -#   Authorization: Bearer $OPENAI_API_KEY
    -#   OpenAI-Safety-Identifier: hashed-user-id
    -# Use um cliente WebSocket (ws / websocket-client) — ver abas Python e JavaScript.
    -echo "Conecte com um cliente WebSocket; veja as abas Python/JavaScript."
    -
    -
    -
    - -

    22.2.3 SIP: telefonia

    -

    Com SIP você direciona chamadas telefônicas para a Realtime API via um provedor de SIP trunking. Aponte seu trunk para sip:$PROJECT_ID@sip.api.openai.com;transport=tls. Cada chamada dispara um webhook realtime.call.incoming; a partir dele você aceita (configurando modelo, voz, instruções e tools) ou rejeita a chamada e depois monitora a sessão por WebSocket.

    -
    -
    - - -
    -
    -
    from flask import Flask, request, Response
    -from openai import OpenAI, InvalidWebhookSignatureError
    -import os, json, asyncio, threading, requests, websockets
    -
    -app = Flask(__name__)
    -client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
    -AUTH = {"Authorization": "Bearer " + os.environ["OPENAI_API_KEY"]}
    -
    -async def monitor(call_id):
    -    async with websockets.connect(
    -        "wss://api.openai.com/v1/realtime?call_id=" + call_id,
    -        additional_headers=AUTH,
    -    ) as ws:
    -        await ws.send(json.dumps({"type": "response.create"}))
    -        while True:
    -            print(await ws.recv())
    -
    -@app.route("/", methods=["POST"])
    -def webhook():
    -    try:
    -        event = client.webhooks.unwrap(request.data, request.headers)
    -        if event.type == "realtime.call.incoming":
    -            # Aceita a chamada e configura a sessão Realtime que a atenderá
    -            requests.post(
    -                f"https://api.openai.com/v1/realtime/calls/{event.data.call_id}/accept",
    -                headers={**AUTH, "Content-Type": "application/json"},
    -                json={
    -                    "type": "realtime",
    -                    "model": "gpt-realtime-2",
    -                    "instructions": "Você é o Alex, concierge da Example Corp.",
    -                },
    -            )
    -            threading.Thread(
    -                target=lambda: asyncio.run(monitor(event.data.call_id)), daemon=True
    -            ).start()
    -            return Response(status=200)
    -    except InvalidWebhookSignatureError:
    -        return Response("Invalid signature", status=400)
    -
    -
    -
    -
    # Aceitar a chamada recebida (mesmos parâmetros de criar um client secret)
    -curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/accept" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{ "type": "realtime", "model": "gpt-realtime-2",
    -        "instructions": "Você é o Alex, concierge da Example Corp." }'
    -
    -# Rejeitar (ex.: 486 = ocupado), transferir (refer) ou encerrar (hangup):
    -curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/reject" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" \
    -  -d '{"status_code": 486}'
    -curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/refer" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" \
    -  -d '{"target_uri": "tel:+14155550123"}'
    -curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/hangup" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY"
    -
    -
    -
    - -

    22.3 Ciclo de eventos cliente/servidor

    -

    A sessão é gerida por eventos do cliente (que você emite) e eventos do servidor (que a API emite para indicar mudanças de estado). Ao conectar, o servidor envia session.created; você ajusta a configuração com session.update (e recebe session.updated). A maioria das propriedades pode mudar a qualquer momento — exceto a voice, que não pode ser alterada depois que o modelo já emitiu áudio na sessão.

    -

    Para gerar uma resposta: crie um item com conversation.item.create e dispare response.create. Durante a geração, o servidor emite uma sequência de eventos de ciclo de vida que você pode usar para feedback em tempo real:

    -
    - - - - - - - - - - -
    FaseEventos do servidor (ordem aproximada)
    Item adicionadoconversation.item.added → conversation.item.done
    Resposta iniciadaresponse.created → response.output_item.added → response.content_part.added
    Áudio (saída)response.output_audio.delta (bytes Base64) → response.output_audio.done
    Transcrição do áudio geradoresponse.output_audio_transcript.delta → response.output_audio_transcript.done
    Texto (quando há modalidade de texto)response.output_text.delta → response.output_text.done
    Encerramentoresponse.content_part.done → response.output_item.done → response.done → rate_limits.updated
    -
    -
    Atenção: os eventos response.output_audio.done e response.done não carregam os bytes do áudio — apenas a transcrição. Para obter o áudio real, escute os response.output_audio.delta e bufferize/transmita os chunks Base64.
    - -

    22.4 Áudio de entrada e saída

    -

    Em WebRTC, a mídia é praticamente automática: adicione o track local do microfone e o usuário já pode falar; o áudio do modelo chega como track remoto. Você ainda recebe eventos de ciclo de vida (input_audio_buffer.speech_started/speech_stopped, deltas de transcrição, response.done).

    -

    Em WebSocket, você controla o input audio buffer manualmente: envie chunks Base64 com input_audio_buffer.append (cada chunk ≤ 15 MB). Formatos configuráveis por sessão (session.audio.input.format / output.format) — PCM 24 kHz mono (audio/pcm) é a base; há também audio/pcmu para telefonia.

    -

    Vozes disponíveis na sessão Realtime: alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin e cedar. Para melhor qualidade, prefira marin ou cedar. gpt-realtime-2 também aceita entrada de imagem como content part de uma mensagem do usuário.

    -
    -
    - - -
    -
    -
    // session.update define modalidade de saída, formatos, voz e VAD
    -const update = {
    -  type: "session.update",
    -  session: {
    -    type: "realtime",
    -    model: "gpt-realtime-2",
    -    output_modalities: ["audio"], // use ["text"] para texto sem áudio
    -    audio: {
    -      input: {
    -        format: { type: "audio/pcm", rate: 24000 },
    -        turn_detection: { type: "semantic_vad" },
    -      },
    -      output: { format: { type: "audio/pcm" }, voice: "marin" },
    -    },
    -    instructions: "Confirme entendimento antes de agir.",
    -  },
    -};
    -dataChannel.send(JSON.stringify(update)); // WebRTC ou WebSocket: ambos têm .send()
    -
    -// Em WebSocket: streamar áudio cru e disparar a resposta
    -ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: base64Pcm16 }));
    -ws.send(JSON.stringify({ type: "input_audio_buffer.commit" })); // quando VAD está off
    -ws.send(JSON.stringify({ type: "response.create" }));
    -
    -// Coletar os bytes de saída
    -ws.on("message", (m) => {
    -  const ev = JSON.parse(m.toString());
    -  if (ev.type === "response.output_audio.delta") bufferAudio(ev.delta); // Base64
    -});
    -
    -
    -
    -
    import base64, json
    -
    -# session.update equivalente (dicionário enviado como JSON pelo socket)
    -update = {
    -    "type": "session.update",
    -    "session": {
    -        "type": "realtime",
    -        "model": "gpt-realtime-2",
    -        "output_modalities": ["audio"],
    -        "audio": {
    -            "input": {
    -                "format": {"type": "audio/pcm", "rate": 24000},
    -                "turn_detection": {"type": "semantic_vad"},
    -            },
    -            "output": {"format": {"type": "audio/pcm"}, "voice": "marin"},
    -        },
    -        "instructions": "Confirme entendimento antes de agir.",
    -    },
    -}
    -ws.send(json.dumps(update))
    -
    -# Streamar áudio cru e disparar a resposta
    -ws.send(json.dumps({"type": "input_audio_buffer.append", "audio": base64_pcm16}))
    -ws.send(json.dumps({"type": "input_audio_buffer.commit"}))   # quando VAD está off
    -ws.send(json.dumps({"type": "response.create"}))
    -
    -def on_message(ws, message):
    -    ev = json.loads(message)
    -    if ev["type"] == "response.output_audio.delta":
    -        chunk = base64.b64decode(ev["delta"])   # bytes de áudio
    -
    -
    -
    - -

    22.5 Tools na sessão

    -

    Você pode anexar tools para o modelo consultar dados ou agir durante a conversa. A configuração usa o mesmo conjunto de eventos em WebRTC e WebSocket, e pode ser feita no nível da sessão (session.tools em session.update, disponível pela sessão inteira) ou no nível da resposta (response.tools em response.create, só para um turno).

    -
    - - - - - - - -
    Tipo de toolUse quandoQuem executa
    functionSua aplicação detém a lógica de negócio, checagens de aprovação ou acesso privado.Seu cliente/servidor recebe a chamada e devolve function_call_output.
    mcp com server_urlO modelo deve chamar tools expostas por um servidor MCP remoto.A própria Realtime API chama o servidor MCP.
    mcp com connector_idVocê quer um connector embutido (ex.: Google Calendar).A Realtime API chama o connector com a autorização fornecida.
    -
    -
    -
    - - -
    -
    -
    import json
    -
    -# 1) Registrar uma function tool na sessão
    -ws.send(json.dumps({
    -    "type": "session.update",
    -    "session": {
    -        "type": "realtime",
    -        "model": "gpt-realtime-2",
    -        "tools": [{
    -            "type": "function",
    -            "name": "lookup_order",
    -            "description": "Busca um pedido pelo número.",
    -            "parameters": {
    -                "type": "object",
    -                "properties": {"order_number": {"type": "string"}},
    -                "required": ["order_number"],
    -            },
    -        }],
    -        "tool_choice": "auto",
    -    },
    -}))
    -
    -# 2) Quando o modelo chamar a function, execute e devolva o resultado
    -ws.send(json.dumps({
    -    "type": "conversation.item.create",
    -    "item": {
    -        "type": "function_call_output",
    -        "call_id": function_call["call_id"],
    -        "output": json.dumps({"status": "shipped", "delivery_date": "2026-05-09"}),
    -    },
    -}))
    -ws.send(json.dumps({"type": "response.create"}))
    -
    -
    -
    -
    // 1) Registrar a function tool
    -ws.send(JSON.stringify({
    -  type: "session.update",
    -  session: {
    -    type: "realtime",
    -    model: "gpt-realtime-2",
    -    tools: [{
    -      type: "function",
    -      name: "lookup_order",
    -      description: "Busca um pedido pelo número.",
    -      parameters: {
    -        type: "object",
    -        properties: { order_number: { type: "string" } },
    -        required: ["order_number"],
    -      },
    -    }],
    -    tool_choice: "auto",
    -  },
    -}));
    -
    -// 2) Devolver o resultado da function
    -ws.send(JSON.stringify({
    -  type: "conversation.item.create",
    -  item: {
    -    type: "function_call_output",
    -    call_id: functionCall.call_id,
    -    output: JSON.stringify({ status: "shipped", delivery_date: "2026-05-09" }),
    -  },
    -}));
    -ws.send(JSON.stringify({ type: "response.create" }));
    -
    -
    -
    - -

    22.6 Configuração de VAD na sessão

    -

    Por padrão, sessões fala↔fala têm voice activity detection (VAD) ligada — a API decide quando o usuário começou/parou de falar e responde sozinha (server_vad é o default). Configure em session.audio.input.turn_detection. Detalhes dos modos server_vad e semantic_vad estão na Seção 28. Para controle granular (ex.: push-to-talk), desligue a VAD com turn_detection: null e emita manualmente input_audio_buffer.commit e response.create.

    - -

    22.7 Custos e truncation

    -

    O faturamento da Realtime API depende do tipo de sessão. Sessões de agente de voz acumulam tokens de entrada e saída (texto, áudio e imagem) por Response; tradução e transcrição em streaming são cobradas por duração do áudio (não pelo ciclo de Response). Os preços variam por modelo (veja a página de cada modelo).

    -
      -
    • Tokens de áudio: mensagens do usuário = 1 token por 100 ms de áudio; mensagens do assistente = 1 token por 50 ms. Há pequenos tokens especiais além do conteúdo, então as contagens variam um pouco.
    • -
    • Conversa inteira por turno: a cada Response, toda a Conversation é enviada ao modelo; turnos mais tardios na sessão custam mais. Leia o uso real no campo usage do evento response.done.
    • -
    • Caching automático: o prompt caching é aplicado automaticamente e reduz muito o custo de entrada em sessões multiturno (melhor esforço). Mantenha o histórico, as instructions e as definições de tools estáticos — alterá-los no meio da sessão "quebra" o cache dali em diante.
    • -
    • Transcrição de entrada: se habilitada, é cobrada à parte (modelo de transcrição próprio, ex.: whisper-1 ou gpt-4o-transcribe); o uso vem em conversation.item.input_audio_transcription.completed.
    • -
    • Modelo mini: os modelos speech-to-speech têm uma versão "mini" bem mais barata — refine no modelo maior e só então tente otimizar custo migrando para o mini.
    • -
    -

    Quando os tokens excedem o limite de contexto do modelo, a Conversation é truncada (itens mais antigos são descartados). Você pode definir uma janela menor e controlar o trade-off custo × memória com session.truncation: token_limits.post_instructions limita os tokens de entrada por Response (exceto as instructions), e retention_ratio (default 1.0) faz a truncation descartar mais que o necessário para estender a folga antes da próxima truncation — útil porque truncar a cada turno derruba o cache. Também é possível "truncation": "disabled" para gerenciar a Conversation manualmente.

    -
    -
    - -
    -
    -
    # Reduzir custo por sessão: limitar tokens e reter 80% antes de truncar de novo
    -{
    -  "event": "session.update",
    -  "session": {
    -    "truncation": {
    -      "type": "retention_ratio",
    -      "retention_ratio": 0.8,
    -      "token_limits": { "post_instructions": 8000 }
    -    }
    -  }
    -}
    -
    -
    -
    -
    Dica: outra estratégia é editar a Conversation manualmente — remova itens antigos com conversation.item.delete (ou substitua por um resumo via conversation.item.create) para reduzir o tamanho da entrada. Estime custos rodando prompts representativos no Realtime Playground e medindo o uso de tokens por sessão.
    - - -
    - -
    -

    23. Tradução em tempo real (gpt-realtime-translate)

    -

    A tradução em tempo real transmite áudio de origem para uma sessão dedicada e devolve áudio traduzido + deltas de transcrição enquanto a pessoa ainda fala. Casos de uso: interpretação ao vivo, chamadas multilíngues, transmissões, reuniões, aulas e salas de vídeo. Use gpt-realtime-translate quando o app deve traduzir o que um humano diz; se precisa de um assistente que responde, chama tools e gerencia conversa, use gpt-realtime-2 (Seção 22).

    - -

    23.1 Como a sessão de tradução difere

    -
    - - - - - - - - - -
    Sessão de agente de vozSessão de tradução
    Conecta a /v1/realtime.Conecta a /v1/realtime/translations.
    O modelo age como assistente.O modelo age como intérprete.
    Usa ciclo de conversa e resposta.Transmite continuamente a partir do áudio de entrada.
    Pode chamar tools e produzir turnos do assistente.Produz áudio traduzido e deltas de transcrição.
    Você pode chamar response.create.Você não chama response.create.
    -
    -
    Nota: a tradução parte do próprio fluxo de áudio. Continue dando append no áudio — inclusive os silêncios entre frases — e trate os eventos de saída conforme chegam. O modelo emite áudio traduzido em chunks PCM16 de ~200 ms, além de deltas de transcrição no idioma de destino. Use WebRTC para mídia de navegador e WebSockets para pipelines de servidor (Twilio Media Streams, mídia SIP, ingest de broadcast).
    - -

    23.2 Fluxo, configuração e eventos

    -

    Conecte ao endpoint dedicado selecionando o modelo na URL, configure o idioma de destino com session.update (em audio.output.language) e então faça append de áudio continuamente. Escute os eventos de saída: session.output_audio.delta (áudio traduzido), session.output_transcript.delta (transcrição de destino) e session.input_transcript.delta (transcrição da origem).

    -
    -
    - - -
    -
    -
    # pip install websocket-client
    -import os, json, websocket
    -
    -ws = websocket.WebSocket()
    -ws.connect(
    -    "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
    -    header=[
    -        f"Authorization: Bearer {os.environ['OPENAI_API_KEY']}",
    -        "OpenAI-Safety-Identifier: hashed-user-id",
    -    ],
    -)
    -
    -# Idioma de destino (ex.: espanhol)
    -ws.send(json.dumps({
    -    "type": "session.update",
    -    "session": {"audio": {"output": {"language": "es"}}},
    -}))
    -
    -# Streamar áudio de origem continuamente (incluindo silêncios)
    -ws.send(json.dumps({
    -    "type": "session.input_audio_buffer.append",
    -    "audio": base64_pcm16,
    -}))
    -
    -while True:
    -    ev = json.loads(ws.recv())
    -    if ev["type"] == "session.output_audio.delta":
    -        play_pcm16(ev["delta"])              # áudio traduzido (Base64)
    -    elif ev["type"] == "session.output_transcript.delta":
    -        print(ev["delta"], end="", flush=True)  # legenda no idioma de destino
    -    elif ev["type"] == "session.input_transcript.delta":
    -        update_source_transcript(ev["delta"])   # legenda na origem
    -
    -
    -
    -
    import WebSocket from "ws";
    -
    -const ws = new WebSocket(
    -  "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
    -  { headers: {
    -      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
    -      "OpenAI-Safety-Identifier": "hashed-user-id",
    -  } }
    -);
    -
    -ws.on("open", () => {
    -  ws.send(JSON.stringify({
    -    type: "session.update",
    -    session: { audio: { output: { language: "es" } } },
    -  }));
    -});
    -
    -// Áudio de origem (incluindo silêncios entre frases)
    -ws.send(JSON.stringify({
    -  type: "session.input_audio_buffer.append",
    -  audio: base64Pcm16,
    -}));
    -
    -ws.on("message", (data) => {
    -  const ev = JSON.parse(data);
    -  if (ev.type === "session.output_audio.delta") playPcm16(ev.delta);
    -  if (ev.type === "session.output_transcript.delta") process.stdout.write(ev.delta);
    -  if (ev.type === "session.input_transcript.delta") updateSourceTranscript(ev.delta);
    -});
    -
    -
    -
    - -

    23.3 Encerrar o stream de origem

    -

    Quando o áudio de origem termina, envie session.close antes de fechar o WebSocket. Esse evento (suportado apenas em sessões de tradução) faz o serviço esvaziar o áudio de entrada pendente, emitir o áudio/transcrição traduzidos restantes e então enviar session.closed. Pare de dar append e continue lendo eventos no seu loop normal até receber session.closed — fechar o socket imediatamente descarta a saída ainda em drenagem.

    -
    -
    - - -
    -
    -
    import json
    -
    -closing = False
    -
    -def close_translation_session():
    -    global closing
    -    if closing:
    -        return
    -    closing = True
    -    ws.send(json.dumps({"type": "session.close"}))
    -
    -close_translation_session()  # chame quando o stream de origem terminar
    -
    -while True:
    -    ev = json.loads(ws.recv())
    -    if ev["type"] == "session.output_audio.delta":
    -        play_pcm16(ev["delta"])
    -    elif ev["type"] == "session.output_transcript.delta":
    -        print(ev["delta"], end="", flush=True)
    -    elif ev["type"] == "session.closed":
    -        ws.close()
    -        break
    -
    -
    -
    -
    let closing = false;
    -function closeTranslationSession() {
    -  if (closing) return;
    -  closing = true;
    -  ws.send(JSON.stringify({ type: "session.close" }));
    -}
    -
    -ws.on("message", (data) => {
    -  const ev = JSON.parse(data);
    -  if (ev.type === "session.output_audio.delta") playPcm16(ev.delta);
    -  if (ev.type === "session.output_transcript.delta") process.stdout.write(ev.delta);
    -  if (ev.type === "session.closed") ws.close();
    -});
    -
    -closeTranslationSession(); // chame quando o stream de origem terminar
    -
    -
    -
    -
    Dica: use uma sessão por idioma de destino. Para uma chamada entre duas pessoas, crie uma sessão por direção (A→idioma de B, B→idioma de A). Em salas de grupo, o número de sessões ≈ falantes de origem ativos × idiomas de destino distintos. Mantenha os tracks de cada falante separados.
    - - -
    - -
    -

    24. Transcrição em streaming (gpt-realtime-whisper)

    -

    Use transcrição em tempo real quando o app precisa de speech-to-text ao vivo sem resposta falada do modelo. A sessão transmite deltas de transcrição conforme o áudio chega, de modo que o usuário vê texto antes do enunciado terminar. Para o caminho de menor latência, use gpt-realtime-whisper, projetado para ser nativamente em streaming dentro de sessões Realtime com latência controlável.

    - -

    24.1 Escolha do modelo de transcrição

    -
    - - - - - - - -
    ModeloMelhor paraNotas
    gpt-realtime-whisperÁudio ao vivo, deltas de transcrição, latência ajustável.Nativamente em streaming, feito para sessões realtime.
    gpt-4o-transcribeSTT de maior acurácia quando streaming não é necessário.Para fluxos de arquivo e requisição-resposta (Seção 25).
    gpt-4o-mini-transcribeTranscrição de menor custo.Quando custo importa mais que acurácia máxima.
    -
    -
    Atenção: gpt-realtime-whisper é uma alternativa para transcrição ao vivo, não um substituto universal. Teste contra seu áudio, idiomas, vocabulário e requisitos de latência antes de migrar tráfego de produção.
    - -

    24.2 Sessão de transcrição, deltas e uso

    -

    A transcrição em tempo real usa uma sessão type: "transcription". Conecte via WebSocket (pipeline de servidor) ou WebRTC (áudio de navegador). Campos de sessão relevantes:

    -
    - - - - - - - - - - -
    CampoDescrição
    typeDefina como transcription para sessões só de transcrição.
    audio.input.formatEncoding do áudio adicionado ao buffer. Use PCM mono 24 kHz para audio/pcm.
    audio.input.transcription.modelUse gpt-realtime-whisper para streaming.
    audio.input.transcription.languageDica opcional de idioma (ex.: pt, en).
    audio.input.transcription.delayTrade-off latência/acurácia. Valores: minimal, low, medium, high, xhigh.
    audio.input.turn_detectionVAD opcional. Para gpt-realtime-whisper, omita ou defina null e faça commit manual.
    -
    -

    Escute conversation.item.input_audio_transcription.delta (texto incremental) e conversation.item.input_audio_transcription.completed (transcrição final do item). Como a ordem entre turnos diferentes não é garantida, use item_id para casar e reconciliar os resultados.

    -
    -
    - - -
    -
    -
    // 1) Abrir uma sessão de transcrição
    -ws.send(JSON.stringify({
    -  type: "session.update",
    -  session: {
    -    type: "transcription",
    -    audio: {
    -      input: {
    -        format: { type: "audio/pcm", rate: 24000 },
    -        transcription: {
    -          model: "gpt-realtime-whisper",
    -          language: "pt",
    -          delay: "low",        // minimal | low | medium | high | xhigh
    -        },
    -        turn_detection: null,  // gpt-realtime-whisper: commit manual
    -      },
    -    },
    -  },
    -}));
    -
    -// 2) Streamar áudio e (sem VAD) commitar quando quiser iniciar a transcrição
    -ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: base64Pcm16 }));
    -ws.send(JSON.stringify({ type: "input_audio_buffer.commit" }));
    -
    -// 3) Consumir os deltas e o evento final
    -ws.on("message", (data) => {
    -  const ev = JSON.parse(data);
    -  if (ev.type === "conversation.item.input_audio_transcription.delta")
    -    process.stdout.write(ev.delta);
    -  if (ev.type === "conversation.item.input_audio_transcription.completed")
    -    console.log("\nFinal:", ev.transcript, "(item", ev.item_id + ")");
    -});
    -
    -
    -
    -
    # Forma do session.update enviado pelo socket (JSON):
    -{
    -  "type": "session.update",
    -  "session": {
    -    "type": "transcription",
    -    "audio": {
    -      "input": {
    -        "format": { "type": "audio/pcm", "rate": 24000 },
    -        "transcription": { "model": "gpt-realtime-whisper", "language": "pt" }
    -      }
    -    },
    -    "include": ["item.input_audio_transcription.logprobs"]
    -  }
    -}
    -
    -
    -
    -
    Nota: ajuste a latência por delay — minimal/low para legendas ao vivo, medium equilibrado, high/xhigh quando a acurácia importa mais que a exibição imediata. Faça benchmark com áudio representativo (microfones reais, telefonia, sotaques, ruído, código-troca). Em sessões GA com gpt-realtime-whisper, o parâmetro prompt não é suportado; logprobs podem ser pedidos via include quando disponíveis. Sempre confirme suporte de timestamps/diarização/confiança antes do lançamento e tenha fallback.
    - - -
    - -
    -

    25. Speech-to-text (arquivos)

    -

    A Audio API oferece dois endpoints de speech-to-text: transcriptions (transcreve no idioma do áudio) e translations (transcreve traduzindo para inglês). Use esta via para uploads de arquivos e requisições delimitadas; para deltas ao vivo de microfone/chamada, use a Seção 24. Uploads são limitados a 25 MB e aceitam mp3, mp4, mpeg, mpga, m4a, wav e webm.

    - -

    25.1 Endpoint /v1/audio/transcriptions

    -

    O endpoint transcriptions aceita os modelos de maior qualidade gpt-4o-transcribe e gpt-4o-mini-transcribe, além de gpt-4o-transcribe-diarize e do whisper-1. Cada um suporta um conjunto diferente de response_format:

    -
    - - - - - - - - -
    Modeloresponse_format suportadoOutros parâmetros
    gpt-4o-transcribejson, textAceita prompt, logprobs, stream.
    gpt-4o-mini-transcribejson, textAceita prompt, logprobs, stream.
    gpt-4o-transcribe-diarizejson, text, diarized_jsonExige chunking_strategy > 30 s; não aceita prompt, logprobs nem timestamp_granularities[].
    whisper-1json, text, srt, verbose_json, vttÚnico com timestamp_granularities[] e subtítulos srt/vtt; sem streaming.
    -
    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -with open("audio.mp3", "rb") as audio_file:
    -    transcription = client.audio.transcriptions.create(
    -        model="gpt-4o-transcribe",
    -        file=audio_file,
    -        response_format="text",
    -        prompt="Termos de domínio: DALL·E, GPT, OpenAI.",  # melhora reconhecimento
    -    )
    -
    -print(transcription.text)
    -
    -
    -
    -
    import fs from "fs";
    -import OpenAI from "openai";
    -
    -const openai = new OpenAI();
    -
    -const transcription = await openai.audio.transcriptions.create({
    -  file: fs.createReadStream("audio.mp3"),
    -  model: "gpt-4o-transcribe",
    -  response_format: "text",
    -  prompt: "Termos de domínio: DALL·E, GPT, OpenAI.",
    -});
    -
    -console.log(transcription.text);
    -
    -
    -
    -
    curl https://api.openai.com/v1/audio/transcriptions \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: multipart/form-data" \
    -  -F file=@audio.mp3 \
    -  -F model=gpt-4o-transcribe \
    -  -F response_format=text
    -
    -
    -
    - -

    25.2 Diarização de falantes (gpt-4o-transcribe-diarize)

    -

    gpt-4o-transcribe-diarize produz transcrições com identificação de falante. Peça response_format: "diarized_json" para receber um array de segmentos com speaker, start e end. Defina chunking_strategy ("auto" recomendado, ou uma config de VAD) — obrigatório quando o áudio passa de 30 s. Opcionalmente, mapeie até quatro falantes conhecidos com known_speaker_names[] e known_speaker_references[] (clipes de 2–10 s, codificados como data URLs no multipart).

    -
    -
    - - - -
    -
    -
    import base64
    -from openai import OpenAI
    -
    -client = OpenAI()
    -
    -def to_data_url(path: str) -> str:
    -    with open(path, "rb") as fh:
    -        return "data:audio/wav;base64," + base64.b64encode(fh.read()).decode("utf-8")
    -
    -with open("meeting.wav", "rb") as audio_file:
    -    transcript = client.audio.transcriptions.create(
    -        model="gpt-4o-transcribe-diarize",
    -        file=audio_file,
    -        response_format="diarized_json",
    -        chunking_strategy="auto",  # obrigatório se > 30 s
    -        extra_body={
    -            "known_speaker_names": ["agente"],
    -            "known_speaker_references": [to_data_url("agente.wav")],
    -        },
    -    )
    -
    -for seg in transcript.segments:
    -    print(seg.speaker, seg.text, seg.start, seg.end)
    -
    -
    -
    -
    import fs from "fs";
    -import OpenAI from "openai";
    -
    -const openai = new OpenAI();
    -const agentRef = fs.readFileSync("agente.wav").toString("base64");
    -
    -const transcript = await openai.audio.transcriptions.create({
    -  file: fs.createReadStream("meeting.wav"),
    -  model: "gpt-4o-transcribe-diarize",
    -  response_format: "diarized_json",
    -  chunking_strategy: "auto", // obrigatório se > 30 s
    -  extra_body: {
    -    known_speaker_names: ["agente"],
    -    known_speaker_references: ["data:audio/wav;base64," + agentRef],
    -  },
    -});
    -
    -for (const seg of transcript.segments) {
    -  console.log(`${seg.speaker}: ${seg.text}`, seg.start, seg.end);
    -}
    -
    -
    -
    -
    curl https://api.openai.com/v1/audio/transcriptions \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: multipart/form-data" \
    -  -F file=@meeting.wav \
    -  -F model=gpt-4o-transcribe-diarize \
    -  -F response_format=diarized_json \
    -  -F chunking_strategy=auto \
    -  -F 'known_speaker_names[]=agente' \
    -  -F 'known_speaker_references[]=data:audio/wav;base64,AAA...'
    -
    -
    -
    -
    Nota: com stream=true, respostas diarizadas emitem transcript.text.segment quando cada segmento é finalizado. gpt-4o-transcribe-diarize está disponível apenas em /v1/audio/transcriptions e ainda não é suportado na Realtime API.
    - -

    25.3 whisper-1: timestamps/word-level e /v1/audio/translations

    -

    whisper-1 é o modelo da OpenAI para dois trabalhos específicos: timestamps em nível de segmento ou palavra e tradução de áudio→inglês. Para timestamps, use response_format: "verbose_json" com timestamp_granularities[] ("word", "segment" ou ambos) — esse parâmetro é suportado somente pelo whisper-1. Ele também é o único que gera legendas srt/vtt.

    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -# (a) Timestamps em nível de palavra
    -with open("speech.mp3", "rb") as audio_file:
    -    transcription = client.audio.transcriptions.create(
    -        model="whisper-1",
    -        file=audio_file,
    -        response_format="verbose_json",
    -        timestamp_granularities=["word"],   # só whisper-1
    -    )
    -print(transcription.words)
    -
    -# (b) Tradução de áudio para inglês (endpoint translations)
    -with open("german.mp3", "rb") as audio_file:
    -    translation = client.audio.translations.create(
    -        model="whisper-1",                  # único modelo do endpoint translations
    -        file=audio_file,
    -    )
    -print(translation.text)
    -
    -
    -
    -
    import fs from "fs";
    -import OpenAI from "openai";
    -
    -const openai = new OpenAI();
    -
    -// (a) Timestamps em nível de palavra
    -const transcription = await openai.audio.transcriptions.create({
    -  file: fs.createReadStream("speech.mp3"),
    -  model: "whisper-1",
    -  response_format: "verbose_json",
    -  timestamp_granularities: ["word"], // só whisper-1
    -});
    -console.log(transcription.words);
    -
    -// (b) Tradução de áudio para inglês
    -const translation = await openai.audio.translations.create({
    -  file: fs.createReadStream("german.mp3"),
    -  model: "whisper-1", // único modelo do endpoint translations
    -});
    -console.log(translation.text);
    -
    -
    -
    -
    # (a) Timestamps em nível de palavra
    -curl https://api.openai.com/v1/audio/transcriptions \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: multipart/form-data" \
    -  -F file=@speech.mp3 \
    -  -F model=whisper-1 \
    -  -F response_format=verbose_json \
    -  -F "timestamp_granularities[]=word"
    -
    -# (b) Tradução de áudio para inglês
    -curl https://api.openai.com/v1/audio/translations \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: multipart/form-data" \
    -  -F file=@german.mp3 \
    -  -F model=whisper-1
    -
    -
    -
    - -

    25.4 Streaming e arquivos longos

    -

    Para uma gravação já concluída, passe stream=True nos modelos gpt-4o-transcribe/gpt-4o-mini-transcribe e receba eventos transcript.text.delta seguidos de transcript.text.done. Streaming não é suportado no whisper-1; para áudio ao vivo de microfone/chamada, use a transcrição em tempo real (Seção 24).

    -

    Para arquivos longos (acima de 25 MB), divida em pedaços de ≤ 25 MB ou use um formato comprimido — evite cortar no meio de uma frase para não perder contexto. O prompt (até 224 tokens no whisper-1) ajuda a corrigir grafias e acrônimos.

    - - -
    - -
    -

    26. Text-to-speech (gpt-4o-mini-tts)

    -

    O endpoint /v1/audio/speech transforma texto em áudio falado usando o modelo gpt-4o-mini-tts, o modelo de TTS mais recente e confiável da OpenAI. Os três insumos principais são: model, input (o texto, máximo de 4096 caracteres) e voice. Um diferencial do gpt-4o-mini-tts é o parâmetro instructions, que controla como o modelo fala (sotaque, faixa emocional, entonação, velocidade, tom, sussurro).

    -
    Atenção: as políticas de uso exigem que você informe claramente aos usuários finais que a voz TTS é gerada por IA e não é uma voz humana.
    - -
    Nota — modelos TTS (2026-06-29): além do gpt-4o-mini-tts, está disponível o gpt-4o-tts (modelo TTS completo, maior qualidade). Atenção: o snapshot gpt-4o-mini-tts-2025-03-20 encerra em 2026-07-23 — migre para o snapshot gpt-4o-mini-tts-2025-12-15 ou use o alias gpt-4o-mini-tts. Fonte: developers.openai.com/api/docs/deprecations.
    - -

    26.1 Gerar fala

    -
    -
    - - - -
    -
    -
    from pathlib import Path
    -from openai import OpenAI
    -
    -client = OpenAI()
    -speech_file = Path("speech.mp3")
    -
    -with client.audio.speech.with_streaming_response.create(
    -    model="gpt-4o-mini-tts",
    -    voice="coral",
    -    input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
    -    instructions="Fale em tom alegre e positivo.",
    -) as response:
    -    response.stream_to_file(speech_file)
    -
    -
    -
    -
    import fs from "fs";
    -import path from "path";
    -import OpenAI from "openai";
    -
    -const openai = new OpenAI();
    -const speechFile = path.resolve("./speech.mp3");
    -
    -const mp3 = await openai.audio.speech.create({
    -  model: "gpt-4o-mini-tts",
    -  voice: "coral",
    -  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    -  instructions: "Fale em tom alegre e positivo.",
    -});
    -
    -const buffer = Buffer.from(await mp3.arrayBuffer());
    -await fs.promises.writeFile(speechFile, buffer);
    -
    -
    -
    -
    curl https://api.openai.com/v1/audio/speech \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "gpt-4o-mini-tts",
    -    "input": "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    -    "voice": "coral",
    -    "instructions": "Fale em tom alegre e positivo."
    -  }' \
    -  --output speech.mp3
    -
    -
    -
    - -

    26.2 Vozes, instructions e formatos

    -

    O endpoint de fala oferece 13 vozes embutidas no gpt-4o-mini-tts: alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, verse, marin e cedar. Para melhor qualidade, prefira marin ou cedar. As vozes são otimizadas para inglês, mas você pode gerar áudio em vários idiomas fornecendo o texto no idioma desejado. Ouça as vozes em OpenAI.fm.

    -
    Atenção: existem três conjuntos de vozes distintos — não os misture. (1) gpt-4o-mini-tts: as 13 acima. (2) tts-1 / tts-1-hd: apenas 9 (alloy, ash, coral, echo, fable, onyx, nova, sage, shimmer) — e não aceitam instructions. (3) Realtime API: 10 vozes (alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin, cedar) — sem fable, nova nem onyx.
    -
    - - - - - - - - - -
    ParâmetroValoresDescrição
    inputtexto (≤ 4096 caracteres)O texto a sintetizar.
    voiceuma das 13 embutidas, ou { "id": "voice_..." }Voz embutida ou voz personalizada (custom voice).
    instructionsstring livreControla estilo (tom, emoção, velocidade, sotaque, sussurro).
    response_formatmp3 (default), opus, aac, flac, wav, pcmFormato do áudio de saída.
    speed0.25 a 4.0 (default 1.0)Velocidade da fala gerada.
    -
    -

    Formatos por uso: MP3 (uso geral, default), Opus (streaming/baixa latência), AAC (YouTube, Android, iOS), FLAC (lossless), WAV (PCM com cabeçalho), PCM (amostras cruas 24 kHz, 16-bit signed little-endian).

    - -

    26.3 Streaming de áudio em tempo real

    -

    O endpoint suporta streaming via chunk transfer encoding: o áudio pode tocar antes do arquivo inteiro ser gerado. Para as menores latências de resposta, use wav ou pcm como response_format.

    -
    -
    - - - -
    -
    -
    import asyncio
    -from openai import AsyncOpenAI
    -from openai.helpers import LocalAudioPlayer
    -
    -openai = AsyncOpenAI()
    -
    -async def main() -> None:
    -    async with openai.audio.speech.with_streaming_response.create(
    -        model="gpt-4o-mini-tts",
    -        voice="coral",
    -        input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
    -        instructions="Fale em tom alegre e positivo.",
    -        response_format="pcm",   # pcm/wav para menor latência
    -    ) as response:
    -        await LocalAudioPlayer().play(response)
    -
    -asyncio.run(main())
    -
    -
    -
    -
    import OpenAI from "openai";
    -import { playAudio } from "openai/helpers/audio";
    -
    -const openai = new OpenAI();
    -
    -const response = await openai.audio.speech.create({
    -  model: "gpt-4o-mini-tts",
    -  voice: "coral",
    -  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    -  instructions: "Fale em tom alegre e positivo.",
    -  response_format: "wav", // wav/pcm para menor latência
    -});
    -
    -await playAudio(response);
    -
    -
    -
    -
    curl https://api.openai.com/v1/audio/speech \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "gpt-4o-mini-tts",
    -    "input": "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    -    "voice": "coral",
    -    "instructions": "Fale em tom alegre e positivo.",
    -    "response_format": "wav"
    -  }' | ffplay -i -
    -
    -
    -
    -
    Nota: tanto a referência da API quanto a seção "Voice options" do guia confirmam 13 vozes embutidas no gpt-4o-mini-tts (incluindo marin e cedar) — a contagem oficial é 13. O parâmetro instructions controla estilo (tom, emoção, velocidade, sotaque, sussurro) e está documentado como disponível no gpt-4o-mini-tts (não funciona em tts-1/tts-1-hd). Custom voices (voz personalizada via { "id": "voice_..." }) exigem habilitação para clientes elegíveis e gravação de consentimento; até 20 vozes por organização.
    - - -
    - -
    -

    27. Áudio no chat (gpt-audio-1.5)

    -

    Quando você já tem um app baseado em Chat Completions e quer adicionar áudio sem montar uma sessão em tempo real, use o modelo nativamente multimodal gpt-audio-1.5. Ele aceita entrada de áudio e produz saída de áudio em uma única requisição de chat: basta incluir "audio" no array modalities e configurar audio: { voice, format }.

    -
    Nota: esse padrão de áudio no chat usa Chat Completions com um modelo de áudio. A documentação da Responses API descreve, hoje, entradas de texto e imagem com saída de texto; para entrada/saída de áudio direta no modelo, use Chat Completions com gpt-audio-1.5.
    - -

    27.1 Entrada e saída de áudio

    -
    -
    - - - -
    -
    -
    import base64
    -from openai import OpenAI
    -
    -client = OpenAI()
    -
    -# Saída de áudio: pergunta em texto, resposta falada
    -completion = client.chat.completions.create(
    -    model="gpt-audio-1.5",
    -    modalities=["text", "audio"],
    -    audio={"voice": "alloy", "format": "wav"},
    -    messages=[{"role": "user", "content": "Golden retriever é um bom cão de família?"}],
    -)
    -
    -print(completion.choices[0].message)
    -wav_bytes = base64.b64decode(completion.choices[0].message.audio.data)
    -with open("dog.wav", "wb") as f:
    -    f.write(wav_bytes)
    -
    -# Entrada de áudio: enviar gravação como content part input_audio
    -with open("pergunta.wav", "rb") as fh:
    -    audio_b64 = base64.b64encode(fh.read()).decode("utf-8")
    -
    -resp = client.chat.completions.create(
    -    model="gpt-audio-1.5",
    -    modalities=["text", "audio"],
    -    audio={"voice": "alloy", "format": "wav"},
    -    messages=[{
    -        "role": "user",
    -        "content": [
    -            {"type": "text", "text": "O que há nesta gravação?"},
    -            {"type": "input_audio", "input_audio": {"data": audio_b64, "format": "wav"}},
    -        ],
    -    }],
    -)
    -print(resp.choices[0].message)
    -
    -
    -
    -
    import { writeFileSync, readFileSync } from "node:fs";
    -import OpenAI from "openai";
    -
    -const openai = new OpenAI();
    -
    -// Saída de áudio
    -const response = await openai.chat.completions.create({
    -  model: "gpt-audio-1.5",
    -  modalities: ["text", "audio"],
    -  audio: { voice: "alloy", format: "wav" },
    -  messages: [{ role: "user", content: "Golden retriever é um bom cão de família?" }],
    -});
    -writeFileSync("dog.wav",
    -  Buffer.from(response.choices[0].message.audio.data, "base64"));
    -
    -// Entrada de áudio
    -const audioB64 = readFileSync("pergunta.wav").toString("base64");
    -const resp = await openai.chat.completions.create({
    -  model: "gpt-audio-1.5",
    -  modalities: ["text", "audio"],
    -  audio: { voice: "alloy", format: "wav" },
    -  messages: [{
    -    role: "user",
    -    content: [
    -      { type: "text", text: "O que há nesta gravação?" },
    -      { type: "input_audio", input_audio: { data: audioB64, format: "wav" } },
    -    ],
    -  }],
    -});
    -console.log(resp.choices[0].message);
    -
    -
    -
    -
    curl https://api.openai.com/v1/chat/completions \
    -  -H "Content-Type: application/json" \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -d '{
    -    "model": "gpt-audio-1.5",
    -    "modalities": ["text", "audio"],
    -    "audio": { "voice": "alloy", "format": "wav" },
    -    "messages": [
    -      { "role": "user", "content": [
    -        { "type": "text", "text": "O que há nesta gravação?" },
    -        { "type": "input_audio",
    -          "input_audio": { "data": "<base64 do áudio>", "format": "wav" } }
    -      ] }
    -    ]
    -  }'
    -
    -
    -
    - -

    27.2 Quando usar áudio no chat vs. Realtime/STT/TTS

    -
    - - - - - - - - -
    CenárioUsePor quê
    Conversa ao vivo, baixa latência, barge-in, tools em tempo realgpt-realtime-2 (Realtime, Seção 22)Sessão de streaming bidirecional; o modelo escuta e fala continuamente.
    Estender um app de chat com perguntas/respostas faladas e turnos delimitadosgpt-audio-1.5 (Chat Completions)Requisição única; sem gerenciar sessão, buffers ou eventos.
    Só transcrever áudio (sem resposta falada)gpt-4o-transcribe / gpt-realtime-whisperSTT puro de arquivo (Seção 25) ou ao vivo (Seção 24).
    Só converter texto em falagpt-4o-mini-tts (Seção 26)Geração de fala com controle de estilo via instructions.
    -
    - - -
    - -
    -

    28. Voice agents & VAD

    -

    Agentes de voz levam os conceitos de agente para interações faladas de baixa latência. A decisão de arquitetura mais importante é: o modelo deve trabalhar diretamente com áudio ao vivo, ou sua aplicação deve encadear explicitamente speech-to-text, raciocínio em texto e text-to-speech?

    - -

    28.1 Arquitetura: fala↔fala vs. pipeline encadeado

    -
    - - - - - - -
    ArquiteturaMelhor paraPor quê
    Fala↔fala (sessão de áudio ao vivo)Conversas naturais e de baixa latência.O modelo lida com entrada e saída de áudio diretamente (gpt-realtime-2).
    Pipeline de voz encadeadoFluxos previsíveis ou extensão de um agente de texto existente.Seu app mantém controle explícito sobre transcrição, raciocínio em texto e geração de fala.
    -
    -

    No fluxo fala↔fala em navegador: (1) seu servidor cria um client secret efêmero; (2) o frontend cria uma RealtimeSession; (3) a sessão conecta por WebRTC (navegador) ou WebSocket (servidor); (4) o agente trata turnos de áudio, tools, interrupções e handoffs dentro da sessão. No pipeline encadeado, seu app gerencia explicitamente STT → workflow do agente → TTS — melhor para fluxos de suporte, com aprovações, ou quando você quer transcrições duráveis e lógica determinística entre as etapas. A regra prática: escolha a arquitetura de áudio primeiro, depois desenhe o resto do agente como faria para texto. Anexe tools, handoffs e guardrails ao RealtimeAgent do mesmo jeito que faria com um agente de texto.

    -
    Nota: as bibliotecas expõem helpers diferentes: em TypeScript, o caminho mais rápido para voz no navegador é RealtimeAgent + RealtimeSession; em Python, a via simples para estender um agente de texto é um VoicePipeline encadeado.
    - -

    28.2 VAD: server_vad e semantic_vad

    -

    Voice activity detection (VAD) detecta automaticamente quando o usuário começou/parou de falar. É ligada por padrão em sessões fala↔fala (default server_vad); em sessões de transcrição, depende do modelo (e o gpt-realtime-whisper exige turn_detection omitido ou null). Configure em session.audio.input.turn_detection. Quando ligada, a API emite input_audio_buffer.speech_started e input_audio_buffer.speech_stopped.

    -
    - - - - - - -
    ModoComo decide o fim do turnoParâmetros
    server_vad (default)Períodos de silêncio para fatiar o áudio automaticamente.threshold (0–1), prefix_padding_ms, silence_duration_ms.
    semantic_vadUm classificador semântico estima, pelas palavras ditas, se o usuário terminou (um "ummm..." gera timeout maior).eagerness: low | medium | high | auto (default ≈ medium).
    -
    -

    Em conversa fala↔fala, os campos create_response e interrupt_response (só do modo conversa) controlam se a VAD dispara a resposta e se interrompe a fala em andamento. Em sessões de transcrição, a VAD apenas controla como o áudio é fatiado. eagerness: "high" faz o modelo responder/chunkar mais rápido; "low" deixa o usuário falar sem interrupção.

    -
    -
    - - -
    -
    -
    {
    -  "type": "session.update",
    -  "session": {
    -    "type": "realtime",
    -    "audio": {
    -      "input": {
    -        "turn_detection": {
    -          "type": "server_vad",
    -          "threshold": 0.5,
    -          "prefix_padding_ms": 300,
    -          "silence_duration_ms": 500,
    -          "create_response": true,
    -          "interrupt_response": true
    -        }
    -      }
    -    }
    -  }
    -}
    -
    -
    -
    -
    // semantic_vad: o modelo decide o fim do turno pelas palavras
    -const event = {
    -  type: "session.update",
    -  session: {
    -    type: "realtime",
    -    audio: {
    -      input: {
    -        turn_detection: {
    -          type: "semantic_vad",
    -          eagerness: "low",          // low | medium | high | auto
    -          create_response: true,     // só em modo conversa
    -          interrupt_response: true,  // só em modo conversa
    -        },
    -      },
    -    },
    -  },
    -};
    -dataChannel.send(JSON.stringify(event));
    -
    -
    -
    - -

    28.3 Boas práticas de prompt de voz

    -
      -
    • Reasoning effort: comece com low na maioria dos agentes e ajuste pela tolerância de latência e complexidade da tarefa.
    • -
    • Captura exata de entidades: peça ao modelo para confirmar números, nomes e datas antes de agir; valide entidades de alto valor manualmente.
    • -
    • Áudio incerto: instrua o agente a pedir repetição quando o áudio for ambíguo, em vez de adivinhar.
    • -
    • Barge-in e turnos: use semantic_vad com eagerness baixo quando quiser deixar o usuário concluir frases; server_vad ajustado quando o ambiente é ruidoso (suba o threshold).
    • -
    • Tools e preâmbulos: defina políticas de uso de tools e mensagens de preâmbulo curtas; mantenha lógica de negócio na definição do agente e o transporte na camada de sessão.
    • -
    • Segurança: inclua um OpenAI-Safety-Identifier estável (hash do ID do usuário) nas requisições Realtime; ao usar token efêmero, defina o cabeçalho no request que cria o client secret.
    • -
    - - - -

    28.4 Receitas e exemplos oficiais (Cookbook)

    -

    Exemplos oficiais de áudio e tempo real, lidos e classificados em 2026-05-24 quanto a aderência ao estado da arte. Em produção, prefira os modelos atuais (gpt-realtime-2, gpt-realtime-translate, gpt-realtime-whisper, gpt-4o-mini-tts, gpt-audio-1.5).

    -
    - - - - - - - - - - -
    Receita / repositórioO que ensinaStatus
    Build Live Translation Apps (gpt-realtime-translate)Tradução fala→fala ao vivo no endpoint dedicado, em 3 transportes (aba do navegador, Twilio, LiveKit); voz dinâmica.SOTA
    openai-realtime-consoleTemplate mínimo de Realtime via WebRTC (data channel oai-events), com function calling no cliente.SOTA
    ElatoAI — Realtime no ESP32Fala→fala em hardware de borda (ESP32-S3, Opus 12 kbps, Server VAD, relay edge).SOTA
    openai-realtime-agentsPadrões de voice agents (chat-supervisor, handoff sequencial, guardrails) com o Agents SDK.Padrões SOTA · trocar IDs
    One-way translationUm locutor → muitos ouvintes (uma sessão por idioma).Legado
    Steering TTSDirigir tom/estilo da voz.Legado
    -
    -
    Sinais de receita legada (substituir ao portar): IDs de áudio/realtime com sufixo *-preview de gerações anteriores, TTS apenas por um modelo legado dedicado, steering de voz por system message e arquitetura turn-based para tradução. Equivalentes modernos: tradução ao vivo → gpt-realtime-translate (endpoint dedicado); estilo de voz → gpt-4o-mini-tts + instructions; áudio in/out no chat → gpt-audio-1.5; voz em tempo real → gpt-realtime-2 (com reasoning.effort).
    - -

    Os três exemplos abaixo são extraídos e adaptados da documentação oficial (verificados em 2026-06-10), já com os modelos atuais. Use a aba para alternar entre Python e JavaScript.

    - -

    1. Transcrição de arquivo com gpt-4o-transcribe — upload de áudio e leitura do texto. · guides/speech-to-text

    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()  # usa a variável de ambiente OPENAI_API_KEY
    -
    -# Abre o arquivo de áudio em modo binário (mp3, wav, m4a, webm... até 25 MB)
    -with open("/caminho/audio.mp3", "rb") as audio_file:
    -    transcription = client.audio.transcriptions.create(
    -        model="gpt-4o-transcribe",
    -        file=audio_file,
    -        response_format="text",   # gpt-4o-transcribe aceita "json" ou "text"
    -        # prompt opcional melhora termos/siglas do domínio
    -        prompt="Transcrição de uma reunião sobre a API da OpenAI.",
    -    )
    -
    -print(transcription.text)
    -
    -
    -
    -
    import fs from "fs";
    -import OpenAI from "openai";
    -
    -const openai = new OpenAI(); // usa OPENAI_API_KEY do ambiente
    -
    -// Envia o arquivo como stream de leitura
    -const transcription = await openai.audio.transcriptions.create({
    -  file: fs.createReadStream("/caminho/audio.mp3"),
    -  model: "gpt-4o-transcribe",
    -  response_format: "text",
    -  prompt: "Transcrição de uma reunião sobre a API da OpenAI.",
    -});
    -
    -console.log(transcription.text);
    -
    -
    -
    - -

    2. Texto→fala com gpt-4o-mini-tts — estilo dirigido por instructions, voz marin, salvando um mp3. · guides/text-to-speech

    -
    -
    - - -
    -
    -
    from pathlib import Path
    -from openai import OpenAI
    -
    -client = OpenAI()
    -speech_file_path = Path(__file__).parent / "fala.mp3"
    -
    -# instructions controla tom/sotaque/emoção; voz "marin" é uma das recomendadas
    -with client.audio.speech.with_streaming_response.create(
    -    model="gpt-4o-mini-tts",
    -    voice="marin",
    -    input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
    -    instructions="Fale em tom animado, acolhedor e com ritmo tranquilo.",
    -) as response:
    -    response.stream_to_file(speech_file_path)  # grava o mp3 em disco
    -
    -print(f"Áudio salvo em {speech_file_path}")
    -
    -
    -
    -
    import fs from "fs";
    -import path from "path";
    -import OpenAI from "openai";
    -
    -const openai = new OpenAI();
    -const speechFile = path.resolve("./fala.mp3");
    -
    -// instructions dirige o estilo; voz "marin" é uma das recomendadas
    -const mp3 = await openai.audio.speech.create({
    -  model: "gpt-4o-mini-tts",
    -  voice: "marin",
    -  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    -  instructions: "Fale em tom animado, acolhedor e com ritmo tranquilo.",
    -});
    -
    -// O default já é mp3; converte o ArrayBuffer em Buffer e grava
    -const buffer = Buffer.from(await mp3.arrayBuffer());
    -await fs.promises.writeFile(speechFile, buffer);
    -console.log(`Áudio salvo em ${speechFile}`);
    -
    -
    -
    - -

    3. Sessão Realtime com gpt-realtime-2 — no navegador via WebRTC (aba JavaScript: RTCPeerConnection + data channel oai-events + token efêmero) e no servidor via WebSocket (aba Python). Cada aba mostra session.update e o envio/recebimento de eventos no transporte natural de cada ambiente. · realtime-webrtc · realtime-websocket

    -
    -
    - - -
    -
    -
    # servidor→servidor: pip install websocket-client
    -import os
    -import json
    -import websocket
    -
    -# A chave padrão fica só no backend seguro; nunca no navegador.
    -url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2"
    -headers = [
    -    "Authorization: Bearer " + os.environ["OPENAI_API_KEY"],
    -    "OpenAI-Safety-Identifier: hash-do-id-do-usuario",
    -]
    -
    -
    -def on_open(ws):
    -    print("Conectado ao servidor.")
    -    # Configura a sessão (session.update) e envia uma mensagem do usuário
    -    ws.send(json.dumps({
    -        "type": "session.update",
    -        "session": {
    -            "type": "realtime",
    -            "instructions": "Você é um assistente de voz objetivo e gentil.",
    -        },
    -    }))
    -    ws.send(json.dumps({
    -        "type": "conversation.item.create",
    -        "item": {
    -            "type": "message",
    -            "role": "user",
    -            "content": [{"type": "input_text", "text": "Olá! Me dê uma dica rápida."}],
    -        },
    -    }))
    -    ws.send(json.dumps({"type": "response.create"}))
    -
    -
    -def on_message(ws, message):
    -    event = json.loads(message)
    -    print("Evento recebido:", event.get("type"))
    -
    -
    -ws = websocket.WebSocketApp(
    -    url, header=headers, on_open=on_open, on_message=on_message,
    -)
    -ws.run_forever()
    -
    -
    -
    -
    // Navegador: busca um token efêmero gerado pelo SEU backend (/token),
    -// que chama POST /v1/realtime/client_secrets com a chave padrão.
    -const tokenResponse = await fetch("/token");
    -const data = await tokenResponse.json();
    -const EPHEMERAL_KEY = data.value; // ex.: "ek_..." (nunca a chave padrão!)
    -
    -// Conexão peer WebRTC
    -const pc = new RTCPeerConnection();
    -
    -// Toca o áudio remoto do modelo
    -const audioEl = document.createElement("audio");
    -audioEl.autoplay = true;
    -pc.ontrack = (e) => (audioEl.srcObject = e.streams[0]);
    -
    -// Microfone local como faixa de entrada
    -const ms = await navigator.mediaDevices.getUserMedia({ audio: true });
    -pc.addTrack(ms.getTracks()[0]);
    -
    -// Data channel para enviar/receber eventos JSON
    -const dc = pc.createDataChannel("oai-events");
    -dc.addEventListener("open", () => {
    -  // session.update logo após abrir o canal
    -  dc.send(JSON.stringify({
    -    type: "session.update",
    -    session: { type: "realtime", instructions: "Seja gentil e direto." },
    -  }));
    -});
    -dc.addEventListener("message", (e) => {
    -  const event = JSON.parse(e.data); // eventos do servidor
    -  console.log("Evento:", event.type);
    -});
    -
    -// Oferta SDP → troca com a Realtime API usando o token efêmero
    -const offer = await pc.createOffer();
    -await pc.setLocalDescription(offer);
    -const sdpResponse = await fetch("https://api.openai.com/v1/realtime/calls", {
    -  method: "POST",
    -  body: offer.sdp,
    -  headers: {
    -    Authorization: `Bearer ${EPHEMERAL_KEY}`,
    -    "Content-Type": "application/sdp",
    -  },
    -});
    -await pc.setRemoteDescription({ type: "answer", sdp: await sdpResponse.text() });
    -
    -
    -
    - - -
    - -

    Parte D — Embeddings, Moderation, Operação & Referência

    Embeddings e moderation, preços e limites por modelo, processamento em lote/flex/priority, Admin APIs, erros, checklist de produção e referência rápida.

    - -
    -

    29. Embeddings

    -

    Embeddings transformam texto em vetores de ponto flutuante cuja distância mede a relação semântica entre dois trechos: distâncias pequenas indicam alta relação, distâncias grandes indicam baixa relação. São a base de busca semântica, RAG, clustering, recomendação, detecção de anomalias e classificação. O endpoint é POST /v1/embeddings e a cobrança é por token de entrada.

    - -

    29.1 Modelos e dimensões

    -

    OpenAI oferece dois modelos de embedding de terceira geração (sufixo -3). O comprimento padrão do vetor é 1536 para text-embedding-3-small e 3072 para text-embedding-3-large. Ambos aceitam até 8192 tokens por entrada.

    -
    - - - - - - -
    ModeloDimensões padrãoMáx. entrada (tokens)Uso recomendado
    text-embedding-3-small15368192Maior volume e custo baixo; busca/RAG de larga escala.
    text-embedding-3-large30728192Maior qualidade de recuperação quando precisão importa mais que custo.
    -
    -
    Nota: a entrada pode ser uma string ou um array (lote) de strings/arrays de tokens. Cada array é limitado a 2048 elementos e o request inteiro a no máximo 300.000 tokens somados em todas as entradas.
    - -

    29.2 Reduzir dimensões com dimensions

    -

    O parâmetro dimensions (suportado nos modelos text-embedding-3 e posteriores) encurta o vetor sem perder as propriedades de representação de conceito — útil para caber em bancos vetoriais com limite de dimensão, reduzindo memória e custo de armazenamento com pequena perda de acurácia. Ao encurtar manualmente após a geração, é preciso renormalizar (L2) o vetor; ao passar dimensions na chamada, a normalização já vem aplicada — esta é a abordagem recomendada.

    - -

    29.3 Gerar embeddings

    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -resp = client.embeddings.create(
    -    model="text-embedding-3-large",
    -    input="O texto que você quer indexar para busca semântica.",
    -    dimensions=1024,           # encurta de 3072 para 1024 (já normalizado)
    -    encoding_format="float",
    -)
    -
    -vetor = resp.data[0].embedding
    -print(len(vetor), resp.usage.total_tokens)
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -
    -const resp = await client.embeddings.create({
    -  model: "text-embedding-3-large",
    -  input: "O texto que você quer indexar para busca semântica.",
    -  dimensions: 1024,
    -  encoding_format: "float",
    -});
    -
    -const vetor = resp.data[0].embedding;
    -console.log(vetor.length, resp.usage.total_tokens);
    -
    -
    -
    -
    curl https://api.openai.com/v1/embeddings \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "text-embedding-3-large",
    -    "input": "O texto que você quer indexar para busca semântica.",
    -    "dimensions": 1024,
    -    "encoding_format": "float"
    -  }'
    -
    -
    -
    - -

    29.4 Uso em busca e RAG

    -

    Para recuperar os documentos mais relevantes, gere o embedding da consulta com o mesmo modelo usado para indexar e calcule a similaridade de cosseno entre o vetor da consulta e os vetores dos documentos, ordenando do maior para o menor. Coloque os trechos mais relevantes no contexto do modelo de geração para compor a resposta (RAG). Como o endpoint é estável e elegível a Zero Data Retention, embeddings podem ser pré-computados e persistidos em um banco vetorial. Para grandes coleções, prefira gerar os vetores via Batch API com 50% de desconto.

    - - -
    - -
    -

    30. Moderation

    -

    Há dois fluxos de moderação: o endpoint standalone POST /v1/moderations, que classifica um texto ou imagem isoladamente, e os scores inline, que voltam junto da geração na Responses API e no Chat Completions (ver §30.5). O endpoint standalone verifica se um texto ou imagem é potencialmente nocivo, retornando categorias sinalizadas e pontuações de confiança. É gratuito. Com ele você pode filtrar conteúdo, intervir em contas abusivas ou bloquear entradas antes de chegar ao modelo. Arquivos de imagem são limitados a 20 MB.

    - -

    30.1 Modelo atual

    -

    O modelo recomendado é omni-moderation-latest: suporta entradas multimodais (texto e imagem) e mais categorias de classificação. A entrada pode ser uma string simples ou um array de conteúdo com objetos text e image_url.

    - -

    30.2 Estrutura da resposta

    -
    - - - - - - - - -
    CampoDescrição
    flaggedtrue se o modelo classifica o conteúdo como potencialmente nocivo.
    categoriesDicionário com um flag booleano por categoria.
    category_scoresPontuação de 0 a 1 por categoria (confiança do modelo). Políticas que dependem desses scores podem precisar de recalibração ao longo do tempo.
    category_applied_input_typesQuais tipos de entrada ("text", "image") dispararam cada categoria. Disponível apenas nos modelos omni.
    -
    - -

    30.3 Categorias

    -
    - - - - - - - - - - - - - - - - - -
    CategoriaDescriçãoEntradas
    harassmentAssédio dirigido a qualquer alvo.Texto
    harassment/threateningAssédio com violência ou dano grave.Texto
    hateÓdio baseado em grupo protegido (raça, gênero, religião etc.).Texto
    hate/threateningConteúdo de ódio com violência ou dano grave.Texto
    illicitInstruções para cometer atos ilícitos. OmniTexto
    illicit/violentIlícito com referência a violência ou obtenção de arma. OmniTexto
    self-harmPromove, encoraja ou retrata automutilação.Texto e imagem
    self-harm/intentExpressa intenção/engajamento em automutilação.Texto e imagem
    self-harm/instructionsEncoraja ou instrui automutilação.Texto e imagem
    sexualConteúdo sexual (exclui educação/bem-estar).Texto e imagem
    sexual/minorsConteúdo sexual com menor de 18 anos.Texto
    violenceMorte, violência ou lesão física.Texto e imagem
    violence/graphicMorte, violência ou lesão em detalhe gráfico.Texto e imagem
    -
    -
    Nota: categorias marcadas como apenas texto retornam score 0 quando só há imagem na entrada.
    - -

    30.4 Moderar texto e imagem

    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -resp = client.moderations.create(
    -    model="omni-moderation-latest",
    -    input=[
    -        {"type": "text", "text": "Descreva esta imagem."},
    -        {"type": "image_url",
    -         "image_url": {"url": "https://exemplo.com/imagem.jpg"}},
    -    ],
    -)
    -
    -resultado = resp.results[0]
    -if resultado.flagged:
    -    print("Conteúdo sinalizado:", resultado.categories)
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -
    -const resp = await client.moderations.create({
    -  model: "omni-moderation-latest",
    -  input: [
    -    { type: "text", text: "Descreva esta imagem." },
    -    { type: "image_url", image_url: { url: "https://exemplo.com/imagem.jpg" } },
    -  ],
    -});
    -
    -const r = resp.results[0];
    -if (r.flagged) console.log("Conteúdo sinalizado:", r.categories);
    -
    -
    -
    -
    curl https://api.openai.com/v1/moderations \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "omni-moderation-latest",
    -    "input": [
    -      { "type": "text", "text": "Descreva esta imagem." },
    -      { "type": "image_url", "image_url": { "url": "https://exemplo.com/imagem.jpg" } }
    -    ]
    -  }'
    -
    -
    -
    - -

    30.5 Scores de moderação inline (Responses e Chat Completions)

    -

    Desde jun/2026 é possível pedir os scores de moderação no mesmo fluxo da geração, sem requisição separada: passe um objeto moderation no topo da requisição (Responses API ou Chat Completions) com o modelo de moderação em moderation.model. A resposta volta com response.moderation.input (moderação da entrada) e response.moderation.output (moderação da saída gerada) — cada um é um moderation_result com os mesmos campos de §30.2 (flagged, categories, category_scores). Suporte tipado no SDK Python a partir de openai 2.41.0.

    -
    -
    - - - -
    -
    -
    resp = client.responses.create(
    -    model="gpt-5.5",
    -    input="Escreva uma resposta para este e-mail de cliente: ...",
    -    moderation={"model": "omni-moderation-latest"},
    -)
    -
    -# Revise os scores ANTES de exibir a saída ou agir sobre ela.
    -for lado, resultado in (("input", resp.moderation.input), ("output", resp.moderation.output)):
    -    if getattr(resultado, "flagged", False):
    -        enviar_para_fila_de_revisao(lado, resultado.categories, resp.id)
    -
    -
    -
    -
    const resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Escreva uma resposta para este e-mail de cliente: ...",
    -  moderation: { model: "omni-moderation-latest" },
    -});
    -
    -for (const [lado, resultado] of [["input", resp.moderation.input], ["output", resp.moderation.output]]) {
    -  if (resultado?.flagged) enviarParaFilaDeRevisao(lado, resultado.categories, resp.id);
    -}
    -
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "Escreva uma resposta para este e-mail de cliente: ...",
    -    "moderation": { "model": "omni-moderation-latest" }
    -  }'
    -
    -
    -
    -
      -
    • A geração acontece normalmente. Os scores são sinal para a sua política (logging, roteamento, fila de revisão humana, bloqueio) — não um bloqueio automático. Uma recusa ou resposta safety-aware ainda pode vir sinalizada se discute conteúdo nocivo.
    • -
    • Streaming: os scores chegam só depois que a saída completa está disponível — eles não vêm nos deltas parciais.
    • -
    • Tool calling: a moderação cobre argumentos de tool calls e outputs de tools quando aparecem no conteúdo da conversa; não cobre nomes, descriptions e schemas de tools, nem schemas de response_format.
    • -
    • Falhas: se a etapa de moderação não completar, o campo correspondente (input ou output) pode conter um erro em vez de scores — cheque o tipo do resultado antes de ler flagged.
    • -
    - - -
    - -
    -

    31. Preços

    -

    Os preços abaixo são por 1 milhão de tokens (USD) no tier Standard, salvo quando indicado por minuto/unidade/chamada. Preços são perecíveis: confira sempre a página oficial. Conferência feita em 2026-06-10 direto na tabela oficial (fonte ao final).

    -
    Modelos sem linha própria na tabela oficial. Alguns modelos de áudio — gpt-audio-1.5, gpt-4o-mini-tts, gpt-4o-transcribe-diarize e whisper-1 — não aparecem como linha de preço na página oficial (verificado: a página tem só as seções Realtime and audio generation models e Transcription models, e não há seção de TTS). Eles são cobrados por token nas taxas do endpoint/modelo correspondente. Onde a tabela mostra por token, é esse o regime — não um preço fixo por minuto/caractere publicado.
    - -

    31.1 Modelos de texto / reasoning (Standard)

    -
    - - - - - - - - - - - - -
    ModeloEntradaEntrada em cacheSaída
    gpt-5.6-sol (≤272K; long: 2× in / 1,5× out)$5,00$0,50$30,00
    gpt-5.6-terra$2,50$0,25$15,00
    gpt-5.6-luna$1,00$0,10$6,00
    gpt-5.5 (<272K contexto)$5,00$0,50$30,00
    gpt-5.5-pro (<272K contexto)$30,00—$180,00
    gpt-5.4-mini$0,75$0,075$4,50
    gpt-5.4-nano$0,20$0,02$1,25
    gpt-5.4-pro (<272K contexto)$30,00—$180,00
    -
    -
    Nota: endpoints de processamento regional (residência de dados) têm acréscimo de 10% para modelos lançados a partir de 05/03/2026 elegíveis a data residency (critério oficial do rodapé de pricing — inclui a família gpt-5.6 e os gpt-5.4-mini/-nano, cujas páginas de modelo citam o uplift explicitamente). Tarifas de Batch e Flex equivalem a 50% da tarifa Standard — inclusive para a família 5.6 (Sol $2,50/$15 · Terra $1,25/$7,50 · Luna $0,50/$3).
    - -

    31.2 Priority processing

    -

    O tier Priority oferece latência mais baixa e consistente, cobrado com prêmio sobre o Standard (descontos de cache continuam valendo).

    -
    - - - - - - - - - -
    ModeloEntradaEntrada em cacheSaída
    gpt-5.6-sol$10,00$1,00$60,00
    gpt-5.6-terra$5,00$0,50$30,00
    gpt-5.6-luna$2,00$0,20$12,00
    gpt-5.5$12,50$1,25$75,00
    gpt-5.4-mini$1,50$0,15$9,00
    -
    - -

    31.3 Imagem, realtime e áudio

    -

    Preços por 1M tokens, salvo quando indicado por minuto. Modalidades cobradas separadamente por modelo realtime.

    -
    - - - - - - - - - - - - - -
    ModeloModalidadeEntradaCacheSaída
    gpt-image-2Imagem / textoEstimado por quality+size na calculadora oficial (tabela por imagem na §20). Ex. 1024×1024: low ~$0,006 · medium ~$0,053 · high ~$0,211. Tokens de imagem: $8 entrada / $2 cache / $30 saída.
    gpt-realtime-2Áudio$32,00$0,40$64,00
    Texto$4,00$0,40$24,00
    Imagem$5,00$0,50—
    gpt-realtime-miniÁudio$10,00$0,30$20,00
    Texto$0,60$0,06$2,40
    Imagem$0,80$0,08—
    gpt-realtime-translateÁudio——$0,034 / min
    gpt-audio-1.5Áudio no chatCobrado por token (áudio + texto de entrada/saída) às taxas do modelo — sem linha própria na tabela oficial.
    -
    - -

    31.4 Transcrição e fala

    -
    - - - - - - - - - -
    ModeloEntrada (texto)Saída (texto)Áudio
    gpt-4o-transcribe$2,50$10,00$0,006 / min
    gpt-4o-mini-transcribe$1,25$5,00$0,003 / min
    gpt-4o-transcribe-diarizeCobrado como transcrição (tokens de entrada/saída) — sem linha própria: a tabela Transcription models oficial lista só gpt-4o-transcribe e gpt-4o-mini-transcribe.
    gpt-4o-mini-ttsCobrado por token (texto de entrada + áudio de saída) — sem linha própria: a página oficial não tem seção de TTS.
    whisper-1——$0,006 / min (tarifa histórica; não consta na tabela atual)
    -
    - -

    31.5 Embeddings e moderation

    -
    - - - - - - - -
    ModeloPreço
    text-embedding-3-small$0,02 / 1M tokens
    text-embedding-3-large$0,13 / 1M tokens
    omni-moderation-latestGratuito
    -
    - -

    31.6 Ferramentas integradas

    -
    - - - - - - - - - - -
    FerramentaPreço
    Web search (modelos de reasoning gpt-5.x)$10,00 / 1k chamadas + tokens de conteúdo à taxa do modelo
    Web search (modelos não-reasoning)$25,00 / 1k chamadas (conteúdo gratuito)
    File search — armazenamento$0,10 / GB por dia (1 GB grátis)
    File search — chamada$2,50 / 1k chamadas (somente Responses API)
    Containers (Hosted Shell + Code Interpreter)1 GB $0,03 · 4 GB $0,12 · 16 GB $0,48 · 64 GB $1,92 por 20 min (base de preço) — desde 2026-06-02 a cobrança é por minuto, com mínimo de 5 min por sessão (não se cobra mais o bloco de 20 min inteiro)
    computer-use-preview (modelo dedicado de Computer Use, atual — usado só na Responses API; o gpt-5.x não o substitui para a tool de computer use)$3,00 entrada / $12,00 saída por 1M tokens
    -
    -
    Nota: tokens usados pelas ferramentas integradas são cobrados às taxas por token do modelo escolhido. Responses, Chat Completions, Realtime, Batch e Assistants não são cobradas à parte — você paga apenas os tokens.
    - - -
    - -
    -

    32. Rate limits & tiers

    -

    Rate limits restringem quantas requisições e tokens você pode usar por janela de tempo. São aplicados no nível de organização e de projeto (não por usuário), variam por modelo e podem ser atingidos por qualquer métrica — o que vier primeiro.

    - -

    32.1 Métricas

    -
    - - - - - - - - -
    SiglaSignificado
    RPM / RPDRequisições por minuto / por dia.
    TPM / TPDTokens por minuto / por dia.
    IPMImagens por minuto.
    ÁudioMinutos de áudio por minuto, em alguns modelos de streaming.
    -
    -
    Nota: algumas famílias compartilham limite (qualquer chamada conta para o mesmo pool). Modelos de contexto longo têm limite separado. A ingestão em vector store compartilha 300 RPM por vector_store_id.
    - -

    32.2 Tiers de uso

    -

    À medida que o gasto na API sobe, a organização é promovida automaticamente de tier, aumentando os limites na maioria dos modelos.

    -
    - - - - - - - - - - -
    TierQualificaçãoLimite de gasto
    FreeGeografia permitida$100 / mês
    Tier 1$5 pagos$100 / mês
    Tier 2$50 pagos$500 / mês
    Tier 3$100 pagos$1.000 / mês
    Tier 4$250 pagos$5.000 / mês
    Tier 5$1.000 pagos$200.000 / mês
    -
    - -

    32.3 Headers de limite

    -

    Cada resposta HTTP traz o estado atual do seu limite, útil para implementar backoff proativo:

    -
    - - - - - - - - - - -
    HeaderExemploSignificado
    x-ratelimit-limit-requests60Máximo de requisições permitidas.
    x-ratelimit-limit-tokens150000Máximo de tokens permitidos.
    x-ratelimit-remaining-requests59Requisições restantes.
    x-ratelimit-remaining-tokens149984Tokens restantes.
    x-ratelimit-reset-requests1sTempo até resetar o limite de requisições.
    x-ratelimit-reset-tokens6m0sTempo até resetar o limite de tokens.
    -
    - -

    32.4 Estratégia de backoff/retry

    -

    Para se recuperar de 429 sem falhas, faça retry com backoff exponencial e jitter aleatório (para evitar que retries colidam ao mesmo tempo). Lembre que requisições malsucedidas também contam para o limite, então reenviar em loop não resolve. Outras táticas: reduzir max_tokens para perto do tamanho esperado da resposta; juntar várias tarefas por requisição quando o gargalo é RPM (mas há TPM sobrando); e usar a Batch API para cargas que não precisam de resposta imediata.

    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -from tenacity import retry, stop_after_attempt, wait_random_exponential
    -
    -client = OpenAI()
    -
    -@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
    -def responder(**kwargs):
    -    return client.responses.create(**kwargs)
    -
    -resp = responder(model="gpt-5.5", input="Olá!")
    -print(resp.output_text)
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -// O SDK oficial já aplica retries com backoff automaticamente.
    -const client = new OpenAI({ maxRetries: 6 });
    -
    -const resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Olá!",
    -});
    -console.log(resp.output_text);
    -
    -
    -
    -
    # Inspecione os headers de limite antes de decidir o ritmo das chamadas:
    -curl -i https://api.openai.com/v1/responses \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{ "model": "gpt-5.5", "input": "Olá!" }' \
    -  | grep -i "x-ratelimit"
    -
    -
    -
    - - -
    - -
    -

    33. Batch, Flex & Priority

    -

    O parâmetro service_tier controla o regime de processamento, trocando latência por custo. Além dele, a Batch API oferece um caminho assíncrono de maior throughput.

    - -

    33.1 Batch API

    -

    A Batch API processa grandes grupos de requisições de forma assíncrona com 50% de desconto, um pool de rate limits separado (não consome o limite síncrono por modelo) e prazo de até 24 horas (geralmente menos). Ideal para avaliações, classificação de grandes datasets, geração de embeddings de repositórios e jobs offline.

    -

    Fluxo: monte um arquivo .jsonl (uma requisição por linha, cada uma com custom_id único e body idêntico ao do endpoint-alvo) → faça upload via Files API com purpose="batch" → crie o batch com completion_window="24h" → consulte o status → baixe o output_file_id. Endpoints suportados incluem /v1/responses, /v1/chat/completions, /v1/embeddings, /v1/moderations, /v1/images/generations e /v1/videos.

    -
    - - - - - - - - - -
    LimiteValor
    Requisições por batchAté 50.000
    Tamanho do arquivo de entradaAté 200 MB
    Entradas de embeddings por batchAté 50.000
    Criação de batchesAté 2.000 por hora
    Saída disponívelArquivo de saída apagado 30 dias após a conclusão
    -
    -
    Nota: a ordem das linhas de saída pode não corresponder à de entrada — use sempre o custom_id para mapear. Batches não concluídos a tempo vão para expired; você é cobrado apenas pelas requisições completadas.
    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -# 1) upload do .jsonl
    -entrada = client.files.create(file=open("batchinput.jsonl", "rb"), purpose="batch")
    -
    -# 2) cria o batch (janela fixa de 24h)
    -batch = client.batches.create(
    -    input_file_id=entrada.id,
    -    endpoint="/v1/responses",
    -    completion_window="24h",
    -    metadata={"description": "geração noturna de embeddings"},
    -)
    -
    -# 3) consulta o status; 4) ao concluir, baixa o output_file_id
    -batch = client.batches.retrieve(batch.id)
    -if batch.status == "completed":
    -    saida = client.files.content(batch.output_file_id)
    -    print(saida.text)
    -
    -
    -
    -
    import fs from "fs";
    -import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -
    -const entrada = await client.files.create({
    -  file: fs.createReadStream("batchinput.jsonl"),
    -  purpose: "batch",
    -});
    -
    -const batch = await client.batches.create({
    -  input_file_id: entrada.id,
    -  endpoint: "/v1/responses",
    -  completion_window: "24h",
    -});
    -
    -const atual = await client.batches.retrieve(batch.id);
    -if (atual.status === "completed") {
    -  const saida = await client.files.content(atual.output_file_id);
    -  console.log(await saida.text());
    -}
    -
    -
    -
    -
    # upload
    -curl https://api.openai.com/v1/files \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -F purpose="batch" -F file="@batchinput.jsonl"
    -
    -# cria o batch
    -curl https://api.openai.com/v1/batches \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{ "input_file_id": "file-abc123", "endpoint": "/v1/responses", "completion_window": "24h" }'
    -
    -
    -
    - -

    33.2 Flex processing

    -

    Defina service_tier="flex" para custo menor (tarifa de Batch, com desconto adicional de prompt caching) em troca de latência maior e indisponibilidade ocasional de recurso. Ideal para tarefas não produtivas: avaliações, enriquecimento de dados e cargas assíncronas. Está em beta com disponibilidade limitada de modelos.

    -
    Atenção: com Flex, timeouts são mais prováveis — aumente o timeout do SDK (padrão de 10 min). Um 429 Resource Unavailable significa falta de capacidade e não é cobrado; faça retry com backoff, ou retry com service_tier="auto" para cair no processamento padrão.
    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI(timeout=900.0)  # 15 min
    -
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    instructions="Liste e descreva todas as metáforas deste livro.",
    -    input="<texto longo do livro>",
    -    service_tier="flex",
    -)
    -print(resp.output_text)
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI({ timeout: 15 * 60 * 1000 }); // 15 min
    -
    -const resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  instructions: "Liste e descreva todas as metáforas deste livro.",
    -  input: "<texto longo do livro>",
    -  service_tier: "flex",
    -});
    -console.log(resp.output_text);
    -
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "<texto longo do livro>",
    -    "service_tier": "flex"
    -  }'
    -
    -
    -
    - -

    33.3 Priority processing

    -

    Defina service_tier="priority" para latência mais baixa e consistente, mantendo a flexibilidade pay-as-you-go. Ideal para aplicações de alto valor voltadas ao usuário com tráfego regular — não para processamento de dados, avaliações ou tráfego errático. Cobrado com prêmio sobre a padrão; descontos de cache continuam valendo. Pode ser ativado por requisição ou no nível de projeto.

    -
    Atenção: existe um ramp rate limit. Se o tráfego subir rápido demais (≥ 1M TPM e >50% de aumento de TPM em 15 min), parte das requisições é rebaixada para Standard e cobrada como tal — a resposta mostrará service_tier="default". Faça o ramp gradual e evite ETL/batch nesse tier. Contexto longo, modelos fine-tuned e embeddings ainda não são suportados.
    - - -
    - -
    -

    34. Admin APIs

    -

    As Admin APIs automatizam a gestão da organização — convites de usuários, revisão de audit logs, administração de projetos, gestão de chaves, alertas de gasto, retenção de dados, permissões de hosted tools por projeto (/v1/organization/projects/{project_id}/hosted_tool_permissions), itens granulares de cobrança e operações de rate limit — para ferramentas de back-office, fluxos de segurança e tooling operacional fora do dashboard (capacidades expandidas em 26/05/2026).

    -
    Workload Identity Federation (26/05/2026): cargas de trabalho confiáveis podem trocar tokens de identidade externa por tokens de acesso de curta duração da OpenAI API — elimina a necessidade de armazenar API keys de longa duração em CI/CD e infraestrutura.
    - -

    34.1 Chave admin

    -

    Os endpoints sob /v1/organization/... exigem uma Admin API key (criada em Settings → Organization → Admin keys), que não funciona em endpoints comuns. Defina OPENAI_ADMIN_KEY e inicialize o SDK normalmente.

    - -

    34.2 RBAC e acesso a modelo por projeto

    -

    O controle de acesso baseado em papéis (RBAC) governa API e Dashboard com as mesmas permissões. Conceitos: Organização (papéis valem em todos os projetos), Projeto (papéis valem só naquele projeto), Grupos (coleções de usuários, sincronizáveis via SCIM) e Papéis (pacotes de permissões; o acesso de um usuário é a união de seus papéis). Comece pelo princípio do menor privilégio; mudanças de papel podem levar até 30 minutos para propagar.

    -

    Para restringir quais modelos um projeto pode usar, configure model permissions em /v1/organization/projects/{project_id}/model_permissions: defina mode como allow_list (só os modelos listados) ou deny_list (bloqueia os listados, libera os demais).

    - -

    34.3 Alertas de limite de gasto

    -

    Use /v1/organization/projects/{project_id}/spend_alerts para notificar a equipe quando o gasto do projeto atingir um limiar. Os valores são especificados em centavos.

    - -

    34.4 Retenção de dados

    -

    Use /v1/organization/projects/{project_id}/data_retention para sobrescrever ou herdar a política da organização. Defina retention_type="organization_default" para herdar. Por padrão, logs de monitoramento de abuso são retidos por até 30 dias; organizações elegíveis podem solicitar Modified Abuse Monitoring ou Zero Data Retention (ZDR) (sujeito a aprovação prévia da OpenAI). Sob ZDR, o parâmetro store em /v1/responses e /v1/chat/completions é sempre tratado como false.

    - -

    34.5 Convidar usuário e audit logs

    -

    Use /v1/organization/invites para enviar um convite por e-mail à organização (papéis reader ou owner), e /v1/organization/audit_logs para listar ações recentes de usuários e mudanças de configuração — base para auditoria e investigação de segurança.

    -
    -
    - - - -
    -
    -
    import os
    -from openai import OpenAI
    -
    -# Use a chave admin, não a chave de projeto
    -admin = OpenAI(api_key=os.environ["OPENAI_ADMIN_KEY"])
    -
    -# Convidar um usuário como reader
    -admin.organization.invites.create(email="dev@empresa.com.br", role="reader")
    -
    -# Restringir o projeto a um conjunto de modelos
    -admin.organization.projects.model_permissions.create(
    -    project_id="proj_123",
    -    mode="allow_list",
    -    model_ids=["gpt-5.5", "gpt-5.4-mini", "text-embedding-3-large"],
    -)
    -
    -# Alerta de gasto a US$ 50,00 (valor em centavos)
    -admin.organization.projects.spend_alerts.create(
    -    project_id="proj_123", threshold=5000,
    -)
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -const admin = new OpenAI({ apiKey: process.env.OPENAI_ADMIN_KEY });
    -
    -await admin.organization.invites.create({ email: "dev@empresa.com.br", role: "reader" });
    -
    -await admin.organization.projects.modelPermissions.create("proj_123", {
    -  mode: "allow_list",
    -  model_ids: ["gpt-5.5", "gpt-5.4-mini", "text-embedding-3-large"],
    -});
    -
    -await admin.organization.projects.spendAlerts.create("proj_123", { threshold: 5000 });
    -
    -
    -
    -
    # Listar audit logs da organização
    -curl https://api.openai.com/v1/organization/audit_logs \
    -  -H "Authorization: Bearer $OPENAI_ADMIN_KEY"
    -
    -# Restringir modelos de um projeto (allowlist)
    -curl https://api.openai.com/v1/organization/projects/proj_123/model_permissions \
    -  -H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{ "mode": "allow_list", "model_ids": ["gpt-5.5", "text-embedding-3-large"] }'
    -
    -
    -
    -
    Atenção: uma Admin API key concede controle amplo sobre a organização. Guarde-a em secret storage, restrinja quem a possui e audite periodicamente. Nunca a exponha em código ou repositórios.
    - - -
    - -
    -

    35. Códigos de erro

    -

    A API retorna erros HTTP padrão; os SDKs oficiais os mapeiam em exceções tipadas. Trate-os programaticamente e aplique backoff onde indicado.

    - -

    35.1 Erros HTTP

    -
    - - - - - - - - - - - - - -
    CódigoCausaComo tratar
    401 Invalid AuthenticationAutenticação inválida.Confirme a API key e a organização correta.
    401 Incorrect API keyChave incorreta, deletada ou de outra org/projeto.Gere uma nova chave e limpe o cache.
    401 IP not authorizedIP fora do allowlist do projeto/organização.Envie do IP correto ou ajuste o IP allowlist.
    403 Country not supportedAcesso de país/região não suportado.Verifique a lista de países suportados.
    429 Rate limit reachedRequisições rápidas demais.Ritme as chamadas; backoff exponencial.
    429 Quota exceededSem créditos ou limite de gasto atingido.Compre créditos ou aumente o limite de uso.
    500 Server errorErro nos servidores da OpenAI.Retry após breve espera; veja a status page.
    503 Engine overloadedTráfego alto.Retry após espera.
    503 Slow DownAumento súbito de tráfego (modelos pay-as-you-go).Reduza ao ritmo original, mantenha 15 min, e suba gradualmente.
    -
    - -

    35.2 Exceções do SDK Python

    -
    - - - - - - - - - - - - - - -
    TipoCausa
    APIConnectionErrorFalha de conexão/rede/proxy/SSL.
    APITimeoutErrorA requisição expirou.
    AuthenticationErrorChave/token inválido, expirado ou revogado.
    BadRequestErrorRequest malformado ou parâmetros faltando.
    ConflictErrorRecurso atualizado por outra requisição.
    InternalServerErrorProblema no lado da OpenAI.
    NotFoundErrorRecurso solicitado não existe.
    PermissionDeniedErrorSem acesso ao recurso pedido.
    RateLimitErrorLimite de taxa atingido.
    UnprocessableEntityErrorNão foi possível processar apesar do formato correto.
    -
    -
    Nota: no WebSocket mode da Responses API você também pode ver previous_response_not_found (refaça com contexto completo e previous_response_id=null) e websocket_connection_limit_reached (conexão atingiu 60 min; abra uma nova).
    - - -
    - -
    -

    36. Checklist de produção

    -

    Ao levar uma aplicação para produção, estas alavancas melhoram qualidade, custo, latência e confiabilidade. Cada item é cumulativo e configurável na Responses API.

    - -
    - - - - - - - - - - - - - - - -
    ItemImpacto
    Usar a Responses APIQualidade, custo, latência, confiabilidade
    reasoning.effortQualidade, custo, latência
    text.verbosityQualidade, custo, latência
    Parâmetro phase do assistantQualidade, custo
    tool_searchCusto, latência
    Ferramentas nativas (built-in tools)Qualidade
    CompactionCusto
    prompt_cache_keyLatência, custo
    reasoning.encrypted_contentQualidade, latência
    background=TrueResumabilidade
    WebSocket modeLatência
    -
    - -

    36.1 Responses API como base

    -

    Sempre comece pela Responses API: é a API principal e o melhor lugar para acessar o comportamento mais recente dos modelos, ferramentas nativas, fluxos com estado e recursos de agente.

    - -

    36.2 reasoning.effort e text.verbosity

    -

    Para gpt-5.5, reasoning.effort aceita none, low, medium (padrão), high e xhigh. Use low para extração, roteamento, classificação ou reescrita simples; medium/high para diagnosticar, comparar opções, planejar ou raciocinar sobre código; reserve xhigh para quando suas avaliações mostrarem que a latência extra compensa. O text.verbosity equilibra concisão (menos tokens de saída, resposta mais rápida) contra completude.

    - -

    36.3 phase, tool_search e ferramentas nativas

    -

    O phase rotula mensagens do assistant como "commentary" (notas/progresso intermediário) ou "final_answer" (resposta concluída); preserve e reenvie esse campo no histórico em fluxos longos para evitar parada precoce. O tool_search (com defer_loading: true nas ferramentas caras) carrega só o subconjunto necessário em runtime, poupando tokens e preservando o cache — comece com hosted tool search e mantenha namespaces com até ~10 funções. Prefira ferramentas nativas (web search, file search, code interpreter, shell, computer use, image generation, MCP/connectors, skills, apply patch): por estarem em distribuição no pós-treino, têm melhor seleção e menos falhas.

    - -

    36.4 Compaction e prompt caching

    -

    A compaction reduz o tamanho do contexto preservando o estado necessário entre muitos turnos — deixe o servidor cuidar (com previous_response_id + context_management e compact_threshold) ou chame client.responses.compact() e reaproveite a saída como está (não edite). O prompt caching reduz latência e custo quando requisições reusam o mesmo prefixo longo: defina prompt_cache_key de forma consistente para prefixos genuinamente compartilhados, mas com granularidade que evite concentrar tráfego — acima de ~15 req/min num mesmo par prefixo+chave, o cache perde eficácia.

    - -

    36.5 Reasoning encrypted, background e WebSocket

    -

    Sempre faça round-trip dos itens de reasoning. Sob requisitos de ZDR (sem armazenar dados de resposta), adicione reasoning.encrypted_content ao include e devolva o item exatamente como veio para um handoff sem estado. Use background=True (requer store=True; incompatível com ZDR) para jobs longos: a API retorna um ID e você faz polling. Use WebSocket mode para fluxos longos e pesados em tool calls — mantendo a conexão aberta e continuando com previous_response_id e apenas os novos itens; em rollouts com 20+ tool calls fica ~40% mais rápido. Uma conexão trata uma resposta por vez e expira em 60 min; funciona com ZDR (dados só em memória).

    -
    -
    - - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    input="Refatore este módulo e explique as decisões.",
    -    reasoning={"effort": "high", "encrypted_content": True},
    -    text={"verbosity": "medium"},
    -    prompt_cache_key="refactor-service-v1",
    -    background=True,
    -    store=True,
    -)
    -print(resp.id, resp.status)   # faça polling por resp.id até completar
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -
    -const resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Refatore este módulo e explique as decisões.",
    -  reasoning: { effort: "high", encrypted_content: true },
    -  text: { verbosity: "medium" },
    -  prompt_cache_key: "refactor-service-v1",
    -  background: true,
    -  store: true,
    -});
    -console.log(resp.id, resp.status);
    -
    -
    -
    -
    curl https://api.openai.com/v1/responses \
    -  -H "Authorization: Bearer $OPENAI_API_KEY" \
    -  -H "Content-Type: application/json" \
    -  -d '{
    -    "model": "gpt-5.5",
    -    "input": "Refatore este módulo e explique as decisões.",
    -    "reasoning": { "effort": "high" },
    -    "text": { "verbosity": "medium" },
    -    "prompt_cache_key": "refactor-service-v1",
    -    "background": true,
    -    "store": true
    -  }'
    -
    -
    -
    - - -
    - -
    -

    Referência rápida de endpoints

    -

    Base: https://api.openai.com/v1. Principais endpoints usados ao longo deste guia.

    -
    - - - - - - - - - - - - - - - -
    Método + caminhoDescrição
    POST /v1/responsesAPI principal para texto, multimodal, reasoning e ferramentas (com estado).
    POST /v1/embeddingsGera vetores de embedding para busca, RAG, clustering.
    POST /v1/moderationsClassifica conteúdo nocivo em texto e imagem (gratuito).
    POST /v1/audio/transcriptionsTranscreve áudio para texto (STT).
    POST /v1/audio/translationsTraduz áudio para inglês.
    POST /v1/audio/speechSintetiza fala a partir de texto (TTS).
    POST /v1/images/generationsGera imagens.
    POST /v1/images/editsEdita imagens existentes.
    GET /v1/realtime / POST /v1/realtime/callsSessões realtime (speech-to-speech, transcrição, tradução).
    POST /v1/batchesCria jobs assíncronos com 50% de desconto e janela de 24h.
    POST /v1/filesFaz upload de arquivos (batch, fine-tuning, entradas).
    -
    - -
    - -
    -

    Tabela de IDs de modelo

    -

    IDs exatos dos modelos atuais cobertos neste guia. Trate IDs e preços como perecíveis: confirme na doc oficial antes de usar em produção.

    -
    - - - - - - - - - - - - - - - - - - - - - - -
    IDTipo / usoEndpoint(s)Parte
    gpt-5.5Frontier de reasoning/coding (effort: none–xhigh)/v1/responsesA
    gpt-5.5-proVariante pro (raciocínio máximo); preço premium/v1/responsesA
    gpt-5.3-codexModelo especializado em código (Codex)/v1/responsesA
    gpt-5.4-miniTexto rápido/barato/v1/responsesA
    gpt-5.4-nanoTexto de menor latência/custo/v1/responsesA
    gpt-image-2Geração e edição de imagem/v1/images/*B
    gpt-realtime-2Realtime speech-to-speech/v1/realtimeC
    gpt-realtime-translateTradução em realtime/v1/realtime/translationsC
    gpt-realtime-whisperTranscrição em streaming (realtime)/v1/realtime/transcription_sessionsC
    gpt-4o-transcribeSTT de arquivo/v1/audio/transcriptionsC
    gpt-4o-mini-transcribeSTT de arquivo (mais barato)/v1/audio/transcriptionsC
    gpt-4o-transcribe-diarizeSTT com diarização (rótulo de falantes)/v1/audio/transcriptionsC
    gpt-4o-mini-ttsSíntese de fala (TTS)/v1/audio/speechC
    gpt-audio-1.5Áudio no chat/v1/chat/completionsC
    whisper-1Tradução de áudio e timestamps (srt/vtt/verbose_json, word-level)/v1/audio/translations, /v1/audio/transcriptionsC
    text-embedding-3-smallEmbeddings (1536 dim)/v1/embeddingsD
    text-embedding-3-largeEmbeddings (3072 dim)/v1/embeddingsD
    omni-moderation-latestModeration multimodal (gratuito)/v1/moderationsD
    -
    - -
    - -
    -

    Glossário

    -
    - - - - - - - - - - - - - - - - - -
    TermoDefinição
    Responses APIAPI principal da OpenAI para texto/multimodal/tools, com estado e ferramentas nativas (/v1/responses).
    reasoning effortQuanto o modelo raciocina antes de responder (none–xhigh); mais esforço = mais latência e tokens de reasoning.
    verbosityAlavanca de concisão vs. completude da saída (low/medium/high).
    prompt cachingReuso automático de prefixos longos para reduzir latência e custo; direcionado por prompt_cache_key.
    compactionRedução controlada do contexto preservando o estado necessário entre turnos.
    VADVoice Activity Detection — detecção de atividade de voz que define os limites de corte do áudio.
    diarizaçãoIdentificação e rotulagem de quem fala em cada trecho do áudio.
    embeddingsVetores numéricos que representam o significado de um texto; distância = relação semântica.
    moderationClassificação de conteúdo potencialmente nocivo em categorias com pontuação de confiança.
    batchProcessamento assíncrono em lote com 50% de desconto e janela de 24h.
    flexservice_tier de menor custo e maior latência, para cargas não produtivas.
    priorityservice_tier de latência baixa e consistente, cobrado com prêmio.
    service tierRegime de processamento de uma requisição: auto, default, flex ou priority.
    -
    - -
    - -
    -

    Receitas oficiais (Cookbook) — RAG, embeddings, avaliação & operação

    -

    Exemplos oficiais do OpenAI Cookbook (e do repositório openai/openai-cookbook) para embeddings, RAG, avaliação e operação. Lidos e classificados em 2026-05-24 quanto a aderência ao estado da arte.

    -
    - - - - - - - - - - - - -
    ReceitaO que ensinaStatus
    Prompt Caching 201prompt_cache_key como chave de shard; Flex vs Batch; caso real de 60%→87% de hit-rate.SOTA
    api_request_parallel_processor.pyScript de produção para processar lotes mantendo-se sob RPM/TPM (backoff).SOTA
    Multi-tool orchestration + RAG (Responses API)Rotear entre web_search, file_search e vector DB num único loop Responses.SOTA
    Evals — regressão / bulk / monitoramentoAcompanhar desempenho de prompts entre iterações; comparar muitos prompts/modelos; detectar regressões em produção. Atenção: a deprecação da plataforma Evals foi anunciada em 2026-06-03 — planeje migração antes de adotar.Deprecação anunciada
    Busca semântica com Supabase / pgvectorRAG self-hosted: Postgres + pgvector, índice HNSW, operador <#> (inner product, vetores unit-norm).SOTA
    Question answering using embeddingsRAG clássico "Search-Ask": embeda corpus, top-k por cosseno, injeta contexto e responde.Portar p/ Responses
    Embedding long inputsLidar com entradas > 8192 tokens: truncar vs. dividir-e-mediar com tiktoken.Técnica atual
    Semantic text searchBusca semântica mínima por cosseno sobre um dataset.Legado
    -
    -
    Ao portar receitas antigas: várias usam Chat Completions e helpers descontinuados (utils.embeddings_utils) ou embeddings de gerações anteriores. No estado da arte, use a Responses API com gpt-5.x e embeddings text-embedding-3-small/-3-large; calcule similaridade com numpy/JS puro em vez do embeddings_utils.
    - -

    Código real, modernizado para o estado da arte

    -

    Três receitas portadas para o estado da arte: embeddings text-embedding-3-small com cosseno calculado em numpy/JS puro (sem o embeddings_utils descontinuado) e geração/roteamento via Responses API com gpt-5.5. Troque os corpora de exemplo pelos seus dados.

    - -

    1. Embeddings + busca semântica (top-k por cosseno) · porta modernizada de Semantic_text_search_using_embeddings.ipynb

    -
    -
    - - -
    -
    -
    import numpy as np
    -from openai import OpenAI
    -
    -client = OpenAI()
    -MODELO_EMB = "text-embedding-3-small"
    -
    -# Corpus de exemplo (troque pelos seus documentos)
    -corpus = [
    -    "O pinguim-imperador é a maior espécie de pinguim.",
    -    "A fotossíntese converte luz solar em energia química.",
    -    "Python é uma linguagem de programação de alto nível.",
    -    "Os Jogos Olímpicos de Inverno de 2022 ocorreram em Pequim.",
    -]
    -
    -def embeddings(textos: list[str]) -> np.ndarray:
    -    # Embeddings da OpenAI já vêm normalizados (norma 1): cosseno = produto interno
    -    resp = client.embeddings.create(model=MODELO_EMB, input=textos)
    -    return np.array([d.embedding for d in resp.data])
    -
    -corpus_emb = embeddings(corpus)
    -
    -def busca(consulta: str, k: int = 3):
    -    q = embeddings([consulta])[0]
    -    sims = corpus_emb @ q                 # similaridade de cosseno (vetores unit-norm)
    -    ordem = np.argsort(-sims)[:k]         # top-k em ordem decrescente
    -    return [(corpus[i], float(sims[i])) for i in ordem]
    -
    -for texto, score in busca("Quem venceu em Pequim 2022?"):
    -    print(f"{score:.3f}  {texto}")
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -const MODELO_EMB = "text-embedding-3-small";
    -
    -// Corpus de exemplo (troque pelos seus documentos)
    -const corpus = [
    -  "O pinguim-imperador é a maior espécie de pinguim.",
    -  "A fotossíntese converte luz solar em energia química.",
    -  "JavaScript é a linguagem da web.",
    -  "Os Jogos Olímpicos de Inverno de 2022 ocorreram em Pequim.",
    -];
    -
    -// Embeddings da OpenAI já vêm normalizados (norma 1): cosseno = produto interno
    -async function embeddings(textos) {
    -  const resp = await client.embeddings.create({ model: MODELO_EMB, input: textos });
    -  return resp.data.map((d) => d.embedding);
    -}
    -const dot = (a, b) => a.reduce((s, v, i) => s + v * b[i], 0);
    -
    -const corpusEmb = await embeddings(corpus);
    -
    -async function busca(consulta, k = 3) {
    -  const [q] = await embeddings([consulta]);
    -  return corpus
    -    .map((texto, i) => ({ texto, score: dot(corpusEmb[i], q) }))
    -    .sort((a, b) => b.score - a.score)
    -    .slice(0, k);
    -}
    -
    -for (const { texto, score } of await busca("Quem venceu em Pequim 2022?")) {
    -  console.log(score.toFixed(3), texto);
    -}
    -
    -
    -
    - -

    2. RAG "Search-Ask": recupera contexto e responde via Responses API · porta do passo de resposta para a Responses API a partir de question_answering_using_embeddings

    -
    -
    - - -
    -
    -
    import numpy as np
    -from openai import OpenAI
    -
    -client = OpenAI()
    -
    -# Reaproveita corpus_emb / busca() do exemplo anterior (text-embedding-3-small)
    -def responder(pergunta: str, k: int = 3) -> str:
    -    trechos = [texto for texto, _ in busca(pergunta, k)]   # top-k por cosseno
    -    contexto = "\n".join(f"- {t}" for t in trechos)
    -    prompt = (
    -        "Use APENAS o contexto abaixo para responder. "
    -        'Se a resposta não estiver no contexto, diga "Não sei.".\n\n'
    -        f"Contexto:\n{contexto}\n\nPergunta: {pergunta}"
    -    )
    -    # Geração no estado da arte: Responses API + gpt-5.5 (sem Chat Completions)
    -    resp = client.responses.create(model="gpt-5.5", input=prompt)
    -    return resp.output_text
    -
    -print(responder("Onde ocorreram os Jogos de Inverno de 2022?"))
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -
    -// Reaproveita corpusEmb / busca() do exemplo anterior (text-embedding-3-small)
    -async function responder(pergunta, k = 3) {
    -  const trechos = (await busca(pergunta, k)).map((r) => r.texto); // top-k por cosseno
    -  const contexto = trechos.map((t) => `- ${t}`).join("\n");
    -  const prompt =
    -    "Use APENAS o contexto abaixo para responder. " +
    -    'Se a resposta não estiver no contexto, diga "Não sei.".\n\n' +
    -    `Contexto:\n${contexto}\n\nPergunta: ${pergunta}`;
    -  // Geração no estado da arte: Responses API + gpt-5.5 (sem Chat Completions)
    -  const resp = await client.responses.create({ model: "gpt-5.5", input: prompt });
    -  return resp.output_text;
    -}
    -
    -console.log(await responder("Onde ocorreram os Jogos de Inverno de 2022?"));
    -
    -
    -
    - -

    3. Orquestração multiferramenta: web_search + file_search numa única chamada · o modelo roteia entre web e a vector store; shapes oficiais de tools-web-search + tools-file-search

    -
    Por que isto é válido: o parâmetro tools da Responses API é um array que aceita várias ferramentas de tipos diferentes; com tool_choice em auto (padrão), o modelo decide quais acionar. A própria doc descreve o modelo podendo "buscar na web, recuperar dos seus arquivos … e chamar suas funções" no mesmo fluxo. Cada shape de ferramenta aqui é oficial e individual; combiná-las num único array é o mecanismo documentado (não um formato especial). Você pode forçar com tool_choice: "required" quando a busca tiver de rodar.
    -
    -
    - - -
    -
    -
    from openai import OpenAI
    -
    -client = OpenAI()
    -
    -# Uma única chamada com DUAS ferramentas hospedadas; o modelo decide qual usar.
    -# web_search -> fatos atuais da internet; file_search -> sua base privada (vector store).
    -resp = client.responses.create(
    -    model="gpt-5.5",
    -    input="Compare nossa política interna de reembolso com as melhores práticas atuais do setor.",
    -    tools=[
    -        {"type": "web_search"},
    -        {"type": "file_search", "vector_store_ids": ["vs_seu_id_aqui"]},
    -    ],
    -)
    -
    -print(resp.output_text)
    -# resp.output traz os itens web_search_call / file_search_call que o modelo acionou
    -
    -
    -
    -
    import OpenAI from "openai";
    -
    -const client = new OpenAI();
    -
    -// Uma única chamada com DUAS ferramentas hospedadas; o modelo decide qual usar.
    -// web_search -> fatos atuais da internet; file_search -> sua base privada (vector store).
    -const resp = await client.responses.create({
    -  model: "gpt-5.5",
    -  input: "Compare nossa política interna de reembolso com as melhores práticas atuais do setor.",
    -  tools: [
    -    { type: "web_search" },
    -    { type: "file_search", vector_store_ids: ["vs_seu_id_aqui"] },
    -  ],
    -});
    -
    -console.log(resp.output_text);
    -// resp.output traz os itens web_search_call / file_search_call que o modelo acionou
    -
    -
    -
    - - -
    - -
    -

    Histórico deste guia

    -
    - - - - - - - - - - -
    DataAlteração
    2026-05-24Versão inicial; modelos verificados na doc oficial.
    2026-05-24Preços de áudio verificados na tabela oficial (Realtime/Transcription); modelos sem linha própria explicitados. Adicionado código real do Cookbook (Python + JavaScript) em cada parte. Fechadas lacunas in-scope: input_file (PDF/documentos/planilhas), gpt-5.5-pro/gpt-5.4-pro, ponteiro gpt-5.3-codex, campo safety_identifier.
    2026-05-24Resolvidos os 2 itens pendentes: file_search usa purpose="assistants" (valor documentado para ingestão em vector store, confirmado no Cookbook + OpenAPI); orquestração web_search+file_search documentada como mecanismo de array de ferramentas (cada shape oficial; modelo roteia via tool_choice: auto). Zero itens UNVERIFIED de preço/código restantes.
    2026-06-25Adicionados gpt-image-1-mini (imagem econômica) e gpt-4o-tts (TTS completo) na tabela de modelos e nas seções de referência. Nota de sunset gpt-image-1 (2026-10-23 → migrar para gpt-image-2) e snapshot gpt-4o-mini-tts-2025-03-20 (sunset 2026-07-23 → migrar para gpt-4o-mini-tts-2025-12-15). Nota de depreciação de 2026-06-11: snapshots gpt-5-2025-08-07, gpt-5-mini-2025-08-07, gpt-5-nano-2025-08-07, gpt-5-pro-2025-10-06, o3-2025-04-16 e o3-pro-2025-06-10 encerram em 2026-12-11 (substitutos: gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano / gpt-5.5-pro). Verificado em developers.openai.com/api/docs/deprecations.
    2026-06-29Varredura de freshness (changelogs oficiais reverificados): gpt-image-1-mini, gpt-image-1.5 e chatgpt-image-latest com sunset 2026-12-01 (anunciado 2026-06-02 → migrar para gpt-image-2); SDK openai 2.44.0 (Python) / 6.45.0 (Node). Confirmados gpt-5.5 como flagship recomendado e gpt-image-2 como default de imagem. Sunsets adicionais verificados: Assistants API 2026-08-26; Evals/Agent Builder/v1-prompts 2026-11-30; gpt-4.1-nano/o1/o3-mini/o4-mini 2026-10-23; Sora 2 / Videos API 2026-09-24. Fonte: developers.openai.com/api/docs/deprecations.
    2026-06-10Varredura de atualização contra doc oficial: billing de containers (Hosted Shell/Code Interpreter) agora é por minuto com mínimo de 5 min por sessão (mudança de 2026-06-02; taxas por 20 min seguem como base de preço); default de prompt_cache_retention passou a 24h para organizações sem ZDR em v1/responses, v1/chat/completions e v1/batch (mudança de 2026-05-29); deprecação da plataforma Evals anunciada em 2026-06-03 sinalizada na tabela do Cookbook; IDs de Embeddings/Moderation preenchidos no catálogo §1.2 (text-embedding-3-small/-large, omni-moderation-latest); marcadores de verificação atualizados para 2026-06-10.
    -
    - -
    - - -
    -
    - - - - - - + + + + + +Guia OpenAI — Modelos mais recentes & API (Responses, Realtime, Imagem, Áudio) + + + + + + + + +
    +
    +
    Guia OpenAI PT-BR · Modelos mais recentes & API
    +
    + Verificado em 2026-07-12 + SDK openai + SOTA + +
    +
    +
    + +
    + + +
    + +
    +

    Guia OpenAI — Modelos mais recentes & API

    +

    + Referência técnica exaustiva, em PT-BR, dos modelos OpenAI mais recentes e de + como usá-los: gpt-5.6 (Sol/Terra/Luna) e gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano (texto e raciocínio pela + Responses API), gpt-image-2 (geração e edição de imagens, visão), + áudio e tempo real (gpt-realtime-2.1, gpt-realtime-translate, + gpt-realtime-whisper, gpt-4o-transcribe, + gpt-4o-mini-tts, gpt-audio-1.5), além de embeddings, + moderation, preços, limites e operação. Feito para leitura por humanos e por IA. +

    +
    + SDK openai · Python & JavaScript + Responses API + SOTA · 2026-06-29 +
    +
    + +
    +

    Sobre este guia

    +

    + Este documento reúne, de forma estruturada e navegável, a documentação dos modelos OpenAI + mais recentes e das APIs usadas para acessá-los. O foco é a + Responses API (a interface recomendada para texto, raciocínio, multimodal e + ferramentas), complementada pelas APIs dedicadas de imagem, áudio/realtime, + embeddings e moderation. +

    +

    + O guia é deliberadamente centrado nos modelos atuais: descreve apenas os modelos + de ponta e como utilizá-los, sem comparativos com versões anteriores. Cada seção termina com a + fonte oficial correspondente — para fatos perecíveis (IDs de modelo, parâmetros, + preços e limites), consulte sempre a documentação oficial, pois mudam com frequência. +

    +
    + Como navegar: a barra lateral é um sumário fixo. A Parte A cobre os + modelos de texto/raciocínio e a Responses API; a Parte B, imagem e visão; a + Parte C, áudio e tempo real; e a Parte D, embeddings, moderation, + preços e operação. O apêndice traz uma referência rápida de endpoints e a tabela de IDs de modelo. +
    +
    + Convenções de código: exemplos em Python e JavaScript + usam o SDK oficial openai; exemplos REST usam curl contra + https://api.openai.com/v1/… com Authorization: Bearer $OPENAI_API_KEY. + Use os botões de aba para alternar a linguagem. +
    +
    + +
    +

    Fontes oficiais

    +

    Todo o conteúdo deste guia é derivado da documentação pública oficial da OpenAI, verificada em 2026-06-10:

    +
    + + + + + + + + + + +
    RecursoOnde
    Documentação de plataformaplatform.openai.com/docs
    Documentação para desenvolvedoresdevelopers.openai.com
    Referência da APIplatform.openai.com/docs/api-reference
    Modelosplatform.openai.com/docs/models
    Preçosplatform.openai.com/docs/pricing
    Cookbookcookbook.openai.com
    +
    + +
    + +

    Parte A — Modelos, Texto & Responses API

    Os modelos de raciocínio gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano e como usá-los pela Responses API: texto, reasoning, ferramentas, streaming, estado e caching.

    + + + +
    +

    2. Seleção de modelo

    +

    O princípio é simples: otimize primeiro a acurácia até bater sua meta de qualidade; só então otimize custo e latência mantendo essa acurácia. Comece com o modelo mais capaz, defina uma meta clara, monte um conjunto de evals e só desça para um modelo menor quando ele preservar a qualidade no ponto de custo/latência que você precisa.

    + +

    2.1 Quando usar cada modelo

    +
    + + + + + + + +
    Se você precisa de…Comece comPor quê
    Qualidade máxima em coding, agentes e raciocínio multi-etapagpt-5.5Linha de base de fronteira; melhor seleção e uso de ferramentas, planejamento e execução.
    Bom equilíbrio com custo menorgpt-5.4-miniMantém raciocínio e ferramentas com latência e custo reduzidos para volume alto.
    Latência/custo mínimos em tarefas simplesgpt-5.4-nanoIdeal para classificação, extração e respostas curtas onde a tarefa é bem definida.
    +
    + +
    Dica: num mesmo fluxo, misture modelos por especialista — um agente de triagem rápido em gpt-5.4-mini e um especialista profundo em gpt-5.5 podem coexistir. Defina o modelo explicitamente em produção em vez de depender do default do SDK.
    + +

    Antes de escalar o reasoning.effort, lembre que o gpt-5.5 raciocina de forma mais eficiente, usando menos tokens de raciocínio no mesmo nível de esforço. Em fluxos sensíveis à latência, reavalie low antes de subir para medium/high.

    + + +
    + +
    +

    3. Quickstart & SDKs

    +

    Instale o SDK oficial openai, defina a variável de ambiente OPENAI_API_KEY e faça a primeira chamada com client.responses.create(...). O SDK lê a chave do ambiente automaticamente.

    + +

    3.1 Instalação

    +
    +
    + + + +
    +
    +
    pip install openai
    +export OPENAI_API_KEY="sk-..."
    +
    +
    +
    npm install openai
    +export OPENAI_API_KEY="sk-..."
    +
    +
    +
    # Nenhum SDK necessário; basta a chave no ambiente:
    +export OPENAI_API_KEY="sk-..."
    +
    +
    + +

    3.2 Primeira chamada

    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    input="Escreva um haicai sobre IA confiável.",
    +)
    +
    +print(response.output_text)
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +
    +const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Escreva um haicai sobre IA confiável.",
    +});
    +
    +console.log(response.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "Escreva um haicai sobre IA confiável."
    +  }'
    +
    +
    + +
    Atenção: o array output costuma ter mais de um item (chamadas de ferramenta, itens de reasoning, etc.). Não assuma que o texto está em output[0].content[0].text. Use o atalho output_text dos SDKs, que agrega todo o texto da resposta.
    + + +
    + +
    +

    4. Anatomia da Responses API

    +

    A Responses API (POST /v1/responses) é a primitiva recomendada para todo projeto novo. Ela é um loop agêntico por padrão: numa única requisição o modelo pode chamar várias ferramentas (web search, file search, code interpreter, MCP, suas funções) antes de responder. Trabalha com itens (cada um — message, function_call, reasoning, etc. — é uma unidade distinta de contexto), em vez de mensagens monolíticas.

    + +

    4.1 Campos principais da requisição

    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    CampoTipoDescrição
    modelstringSlug do modelo, ex.: gpt-5.5. Em produção, fixe um snapshot quando precisar de comportamento estável.
    inputstring | arrayO prompt. Pode ser uma string simples ou um array de itens com role (developer/user/assistant) e conteúdo (texto, imagem, arquivo).
    instructionsstringInstruções de alto nível (tom, metas, regras). Têm prioridade sobre o input e valem só para a geração atual.
    reasoningobject{ "effort": "...", "summary": "..." }. Controla o esforço de raciocínio e o resumo de raciocínio. Ver §6.
    textobject{ "verbosity": "...", "format": {...} }. Controla concisão da saída e o formato (Structured Outputs). Ver §7 e §9.
    toolsarrayFerramentas disponíveis: funções suas, ferramentas integradas (web_search, file_search, code_interpreter, mcp, shell, computer, apply_patch, image_generation) e tool_search. Ver §11.
    tool_choicestring | objectauto (padrão), required, none, função forçada, ou allowed_tools. Ver §10.
    previous_response_idstringEncadeia a resposta anterior para conversa multi-turno com estado preservado. Ver §13.
    conversationstringID de um objeto da Conversations API para persistir estado de forma durável.
    storebooleanSe a resposta é armazenada (padrão true; respostas ficam 30 dias). Defina false para fluxos stateless/ZDR.
    streambooleanSe true, transmite eventos SSE conforme a geração avança. Ver §12.
    backgroundbooleanExecuta a tarefa de forma assíncrona (requer store=true). Ver §14.
    max_output_tokensintegerLimita o total de tokens gerados (visíveis + raciocínio), controlando custo.
    includearrayInclui dados extras na saída, ex.: "reasoning.encrypted_content" para fluxos stateless.
    prompt_cache_keystringMelhora o roteamento de cache para requisições com prefixo comum. Ver §15.
    promptobjectUsa um prompt reutilizável salvo no dashboard (id, version, variables). Ver §5.
    metadataobjectAté 16 pares chave-valor para anotar a resposta (chaves ≤ 64 chars, valores ≤ 512 chars).
    safety_identifierstringIdentificador estável e opaco do seu usuário final (ex.: hash do ID), usado pela OpenAI para monitorar abuso e preservar seu acesso caso um usuário viole políticas. Não envie e-mail/nome em claro. (Equivale ao header OpenAI-Safety-Identifier no Realtime — ver §22.)
    moderationobject{ "model": "omni-moderation-latest" }. Retorna scores de moderação da entrada e da saída na mesma resposta, sem chamada separada (novidade de jun/2026; também em Chat Completions). Ver §30.5.
    +
    + +

    4.2 O objeto de resposta

    +

    A resposta traz um objeto tipado com id, status (completed, incomplete, queued, in_progress, failed), output (array de itens), output_text (atalho dos SDKs) e usage. O bloco usage detalha o consumo:

    +
    {
    +  "usage": {
    +    "input_tokens": 75,
    +    "input_tokens_details": { "cached_tokens": 0 },
    +    "output_tokens": 1186,
    +    "output_tokens_details": { "reasoning_tokens": 1024 },
    +    "total_tokens": 1261
    +  }
    +}
    +

    Quando a resposta excede o limite, status volta incomplete com incomplete_details.reason = "max_output_tokens" — possivelmente antes de qualquer texto visível, já consumindo tokens de entrada e raciocínio.

    + + +
    + +
    +

    5. Geração de texto

    +

    Texto é o caso de uso primário. Você fornece um prompt e o modelo gera a resposta no array output; o atalho output_text agrega todo o texto produzido.

    + +

    5.1 Roles e instructions

    +

    Você dirige o modelo com níveis de autoridade. O parâmetro instructions dá orientação de alto nível (tom, metas, exemplos) e tem prioridade sobre o input. Como alternativa, use mensagens com role:

    +
      +
    • developer — regras e lógica de negócio da aplicação (como a definição de uma função). Prioridade acima de user.
    • +
    • user — instruções/entradas do usuário final (como os argumentos da função).
    • +
    • assistant — mensagens geradas pelo modelo.
    • +
    + +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +client = OpenAI()
    +
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    reasoning={"effort": "low"},
    +    instructions="Você é um assistente técnico. Responda em PT-BR, conciso.",
    +    input="Explique embeddings em duas frases.",
    +)
    +
    +print(response.output_text)
    +
    +
    +
    import OpenAI from "openai";
    +const client = new OpenAI();
    +
    +const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  reasoning: { effort: "low" },
    +  instructions: "Você é um assistente técnico. Responda em PT-BR, conciso.",
    +  input: "Explique embeddings em duas frases.",
    +});
    +
    +console.log(response.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "reasoning": { "effort": "low" },
    +    "instructions": "Você é um assistente técnico. Responda em PT-BR, conciso.",
    +    "input": "Explique embeddings em duas frases."
    +  }'
    +
    +
    + +
    Nota: instructions vale só para a geração atual. Se você gerencia estado com previous_response_id, as instruções de turnos anteriores não ficam no contexto — reenvie quando necessário.
    + +

    5.2 Prompts reutilizáveis

    +

    Em vez de embutir o prompt no código, crie um prompt reutilizável no dashboard com placeholders como {{customer_name}} e referencie-o via parâmetro prompt (id, version opcional, e variables). Isso facilita iterar e versionar prompts sem mudar o código de integração.

    +
    +
    + + + +
    +
    +
    response = client.responses.create(
    +    model="gpt-5.5",
    +    prompt={
    +        "id": "pmpt_abc123",
    +        "version": "2",
    +        "variables": {"customer_name": "Jane Doe", "product": "caixa de suco 1,2L"},
    +    },
    +)
    +print(response.output_text)
    +
    +
    +
    const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  prompt: {
    +    id: "pmpt_abc123",
    +    version: "2",
    +    variables: { customer_name: "Jane Doe", product: "caixa de suco 1,2L" },
    +  },
    +});
    +console.log(response.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "prompt": {
    +      "id": "pmpt_abc123",
    +      "version": "2",
    +      "variables": { "customer_name": "Jane Doe", "product": "caixa de suco 1,2L" }
    +    }
    +  }'
    +
    +
    + + +
    + +
    +

    6. Reasoning (reasoning.effort)

    +

    Modelos de raciocínio usam reasoning tokens para planejar antes de responder. Esses tokens não são visíveis pela API, mas ocupam espaço na janela de contexto e são cobrados como tokens de saída. O gpt-5.5 suporta interleaved thinking: pode gerar saída visível antes, entre e depois de pensar, inclusive entre chamadas de ferramenta.

    + +

    6.1 Níveis de esforço

    +

    O gpt-5.5 aceita none, low, medium, high e xhigh, com padrão medium. O enum completo do parâmetro reasoning.effort na Responses API tem sete valores — none · minimal · low · medium · high · xhigh · max — mas, nas palavras da doc oficial, not all reasoning models support every value: minimal e max são model-dependent (o max aparece na família gpt-5.6). Confira a página de cada modelo.

    +
    + + + + + + + + + + +
    EsforçoMelhor para…
    nonePiso de esforço (gera pouco ou nenhum reasoning token; ocupa o lugar do antigo nível mínimo). Mesmo em none as ferramentas hospedadas (web/file search) e o function calling continuam funcionando. Tarefas latency-critical sem benefício de raciocínio: voz, recuperação rápida, classificação. Para casos sensíveis à latência, comece em low e desça para none só se necessário; com none, peça ao modelo para "planejar antes de cada chamada de função" para compensar a ausência de tokens de raciocínio.
    lowRaciocínio eficiente com aumento modesto de latência: análise de dados, drafting, coding de execução, suporte/chat. Ideal quando há uso de ferramentas, planejamento ou decisão multi-etapa, otimizando velocidade e custo.
    mediumPadrão. Quando qualidade e confiabilidade importam e há planejamento/julgamento: coding agêntico, pesquisa, planilhas e slides, trabalho de horizonte longo. Ponto bem equilibrado de latência × performance × custo.
    highRaciocínio difícil, debugging complexo, planejamento profundo e tarefas de alto valor onde qualidade importa mais que latência. Avalie medium e high.
    xhighPesquisa profunda, fluxos assíncronos e tarefas agênticas de rollout muito longo: revisão de segurança/código, produtividade corporativa, coding desafiador. Use só quando os evals justificarem a latência/custo extra.
    max 5.6Teto de raciocínio da família gpt-5.6 — mais tempo de raciocínio em um agente. Reserve para o trabalho mais difícil já validado em evals; o custo de reasoning tokens sobe proporcionalmente. Não confunda com orquestração multi-agente (que é outra coisa, ver callout acima). Nem todo modelo aceita este nível.
    +
    + +
    Dica: para melhor time to first token em aplicações sensíveis à latência, peça ao modelo um preâmbulo curto antes de continuar com raciocínio mais profundo. Controle o tamanho da resposta com max_output_tokens — a OpenAI recomenda reservar ao menos ~25.000 tokens para raciocínio + saída ao começar.
    + +

    6.2 Resumos de raciocínio

    +

    Os tokens brutos de raciocínio não são expostos, mas você pode pedir um resumo com reasoning.summary. Use "auto" para o resumidor mais detalhado disponível. O resumo aparece no array summary dentro do item de reasoning na saída.

    +
    +
    + + + +
    +
    +
    response = client.responses.create(
    +    model="gpt-5.5",
    +    input="Qual é a capital da França?",
    +    reasoning={"effort": "low", "summary": "auto"},
    +)
    +print(response.output)
    +
    +
    +
    const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Qual é a capital da França?",
    +  reasoning: { effort: "low", summary: "auto" },
    +});
    +console.log(response.output);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "Qual é a capital da França?",
    +    "reasoning": { "effort": "low", "summary": "auto" }
    +  }'
    +
    +
    +
    Nota: antes de usar resumidores com os modelos de raciocínio mais recentes, pode ser necessário concluir a verificação de organização nas configurações da plataforma.
    + +

    6.3 Manter itens de reasoning no contexto

    +

    Ao fazer function calling com modelo de raciocínio na Responses API, reenvie os itens de reasoning retornados junto com a última chamada de função (além da saída da função). Se o modelo chamou várias funções em sequência, devolva todos os itens de reasoning, function_call e function_call_output desde a última mensagem user. O jeito mais simples é encadear com previous_response_id; o sistema ignora de forma inteligente itens irrelevantes.

    + +

    6.4 Itens de reasoning criptografados (encrypted_content)

    +

    Em modo stateless (store=false) ou sob Zero Data Retention, você ainda precisa manter os itens de reasoning entre turnos. Para isso, adicione "reasoning.encrypted_content" ao parâmetro include. Os itens de reasoning na saída passam a ter encrypted_content, que você devolve intacto nas próximas requisições — sua aplicação não precisa entender o valor.

    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "reasoning": { "effort": "medium" },
    +    "input": "Como está o tempo hoje?",
    +    "tools": [ /* config de função */ ],
    +    "include": [ "reasoning.encrypted_content" ]
    +  }'
    + + +
    + +
    +

    7. Verbosity & phase

    + +

    7.1 text.verbosity

    +

    O text.verbosity é a alavanca principal para equilibrar concisão × completude da resposta. Valores suportados: low, medium (padrão) e high. Verbosidade menor gera menos tokens de saída e responde mais rápido; maior produz explicações mais ricas e estruturadas. No gpt-5.5, defina low quando quiser respostas mais curtas e diretas.

    +
    Dica: trate o tamanho da resposta como separado da qualidade do raciocínio. Combine verbosity com instruções explícitas — orçamento de palavras, número de seções, largura de tabelas ou saída só em JSON — quando precisar de um artefato estável.
    +
    +
    + + + +
    +
    +
    response = client.responses.create(
    +    model="gpt-5.5",
    +    input="Resuma a arquitetura de microsserviços.",
    +    text={"verbosity": "low"},
    +)
    +print(response.output_text)
    +
    +
    +
    const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Resuma a arquitetura de microsserviços.",
    +  text: { verbosity: "low" },
    +});
    +console.log(response.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "Resuma a arquitetura de microsserviços.",
    +    "text": { "verbosity": "low" }
    +  }'
    +
    +
    + +

    7.2 Parâmetro phase

    +

    Em fluxos longos ou tool-heavy, o campo phase nas mensagens assistant distingue atualizações intermediárias da resposta final. É opcional, mas recomendado:

    +
      +
    • phase: "commentary" — atualizações intermediárias, como preâmbulos antes de chamadas de ferramenta.
    • +
    • phase: "final_answer" — a resposta concluída.
    • +
    • Não adicione phase em mensagens user.
    • +
    +

    Com previous_response_id, o estado do assistant é preservado automaticamente. Se você reproduz o histórico manualmente, preserve cada valor original de phase e devolva-o sem alteração. phase faltante ou descartado pode fazer um preâmbulo ser tratado como resposta final, causando parada precoce.

    +
    Atenção: se o modelo trata uma atualização intermediária como resposta final em workflows tool-heavy, verifique primeiro se sua integração preserva o campo phase corretamente.
    + + +
    + +
    +

    8. Prompting GPT-5.5

    +

    O gpt-5.5 rende melhor com prompts outcome-first: descreva o resultado esperado, critérios de sucesso, restrições e contexto disponível, deixando o modelo escolher o caminho. Evite carregar todo o stack de prompts antigo: instruções que super-especificam o processo viram ruído e estreitam o espaço de busca.

    + +

    8.1 Preâmbulo (time to first token)

    +

    Em streaming, peça um preâmbulo curto antes de chamadas de ferramenta para melhorar a responsividade percebida sem mudar a tarefa.

    +
    Antes de qualquer chamada de ferramenta numa tarefa multi-etapa, envie uma
    +atualização curta e visível ao usuário que reconheça o pedido e indique o
    +primeiro passo. Mantenha em uma ou duas frases.
    + +

    8.2 Outcome-first e critérios de parada

    +

    Descreva o destino, não cada passo. Reserve palavras absolutas (ALWAYS, NEVER, must) para invariantes reais (segurança, campos obrigatórios). Para julgamentos (quando buscar, perguntar, usar ferramenta, iterar), prefira regras de decisão. Adicione critérios de parada explícitos:

    +
    Resolva o pedido do usuário no menor número útil de loops de ferramenta, mas
    +não deixe a minimização de loops superar correção, evidência ou citações
    +obrigatórias para afirmações factuais.
    +
    +Após cada resultado, pergunte: "Já consigo responder o pedido central com
    +evidência útil e citações?" Se sim, responda.
    + +

    8.3 Formatação e personalidade

    +

    O gpt-5.5 é altamente direcionável em formato. Por padrão é eficiente e direto; para produtos conversacionais, defina personalidade (tom, calor, formalidade) e estilo de colaboração (quando perguntar, quando assumir, quanto contexto dar) — sempre curtos. Use text.verbosity e indique público e tamanho:

    +
    Escreva para um público sênior de negócios. Mantenha a resposta abaixo de 400
    +palavras. Use parágrafos curtos e bullets só quando melhorarem a leitura.
    +Priorize a conclusão primeiro, depois o raciocínio, depois ressalvas.
    + +

    8.4 Orçamento de retrieval e checagem

    +

    Orçamentos de retrieval são regras de parada para busca: dizem ao modelo quando há evidência suficiente. Para tarefas com validação, dê ferramentas para o modelo checar o próprio trabalho (testes, type/lint checks, build, ou inspeção do artefato renderizado em UI). Para drafting, separe fatos que precisam de fonte de partes que podem ser escritas criativamente.

    +
    Para Q&A comum, comece com uma busca ampla usando palavras-chave curtas e
    +discriminativas. Se os melhores resultados já dão suporte citável ao pedido
    +central, responda a partir deles em vez de buscar de novo.
    +
    +Faça nova chamada de retrieval só quando: faltar fato/parâmetro/data/ID/fonte
    +exigidos, o usuário pedir cobertura exaustiva, ou houver afirmação factual
    +importante sem suporte.
    + +
    Nota: o gpt-5.5 já conhece a data atual em UTC — não inclua a data nas instruções, salvo quando precisar de um fuso/política específica do negócio. Prefira definir o schema de saída via Structured Outputs em vez de descrevê-lo no prompt.
    + + +
    + +
    +

    9. Saída estruturada

    +

    Structured Outputs garante que a resposta siga exatamente um JSON Schema fornecido — sem chaves faltando nem enums inválidos. Benefícios: type-safety confiável, recusas explícitas e prompting mais simples. Na Responses API, configure via text.format com type: "json_schema" e strict: true.

    + +

    9.1 Definindo o schema

    +

    Os SDKs facilitam definir o schema em código com Pydantic (Python) e Zod (JavaScript), via os helpers responses.parse / text_format / zodTextFormat.

    +
    +
    + + + +
    +
    +
    from pydantic import BaseModel
    +from openai import OpenAI
    +
    +client = OpenAI()
    +
    +class Passo(BaseModel):
    +    explicacao: str
    +    saida: str
    +
    +class Raciocinio(BaseModel):
    +    passos: list[Passo]
    +    resposta_final: str
    +
    +response = client.responses.parse(
    +    model="gpt-5.5",
    +    input=[
    +        {"role": "system", "content": "Você é um tutor de matemática. Guie passo a passo."},
    +        {"role": "user", "content": "Como resolvo 8x + 7 = -23?"},
    +    ],
    +    text_format=Raciocinio,
    +)
    +
    +for output in response.output:
    +    if output.type != "message":
    +        continue
    +    for item in output.content:
    +        if item.type == "refusal":
    +            print(item.refusal)   # recusa de segurança
    +        elif item.parsed:
    +            print(item.parsed)
    +
    +
    +
    import OpenAI from "openai";
    +import { z } from "zod";
    +import { zodTextFormat } from "openai/helpers/zod";
    +
    +const client = new OpenAI();
    +
    +const Passo = z.object({ explicacao: z.string(), saida: z.string() });
    +const Raciocinio = z.object({ passos: z.array(Passo), resposta_final: z.string() });
    +
    +const response = await client.responses.parse({
    +  model: "gpt-5.5",
    +  input: [
    +    { role: "system", content: "Você é um tutor de matemática. Guie passo a passo." },
    +    { role: "user", content: "Como resolvo 8x + 7 = -23?" },
    +  ],
    +  text: { format: zodTextFormat(Raciocinio, "raciocinio") },
    +});
    +
    +for (const output of response.output) {
    +  if (output.type !== "message") continue;
    +  for (const item of output.content) {
    +    if (item.type === "refusal") console.log(item.refusal);
    +    else if (item.parsed) console.log(item.parsed);
    +  }
    +}
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": [
    +      { "role": "system", "content": "Você é um tutor de matemática. Guie passo a passo." },
    +      { "role": "user", "content": "Como resolvo 8x + 7 = -23?" }
    +    ],
    +    "text": {
    +      "format": {
    +        "type": "json_schema",
    +        "name": "raciocinio",
    +        "strict": true,
    +        "schema": {
    +          "type": "object",
    +          "properties": {
    +            "passos": {
    +              "type": "array",
    +              "items": {
    +                "type": "object",
    +                "properties": { "explicacao": {"type":"string"}, "saida": {"type":"string"} },
    +                "required": ["explicacao", "saida"],
    +                "additionalProperties": false
    +              }
    +            },
    +            "resposta_final": { "type": "string" }
    +          },
    +          "required": ["passos", "resposta_final"],
    +          "additionalProperties": false
    +        }
    +      }
    +    }
    +  }'
    +
    +
    + +

    9.2 Recusas (refusals)

    +

    Com entrada gerada por usuário, o modelo pode recusar por segurança. Como a recusa não segue o schema, a resposta inclui um campo refusal em vez do conteúdo estruturado. Detecte-o programaticamente e trate na sua UI/lógica.

    +
    {
    +  "type": "message",
    +  "role": "assistant",
    +  "content": [
    +    { "type": "refusal", "refusal": "Desculpe, não posso ajudar com isso." }
    +  ]
    +}
    + +
    Dica: use text.format quando quiser estruturar a resposta ao usuário; use function calling (com strict) quando estiver conectando o modelo a ferramentas e dados do seu sistema. Para evitar divergência, prefira o suporte nativo de Pydantic/Zod a escrever o JSON Schema à mão.
    + +
    Atenção: existe ainda o JSON mode (text.format = {"type": "json_object"}), que garante JSON válido mas não adesão a schema. Prefira Structured Outputs sempre que possível; ao usar JSON mode, instrua explicitamente o modelo a gerar JSON.
    + + +
    + +
    +

    10. Function calling

    +

    Function calling (ou tool calling) conecta o modelo a sistemas e dados externos. Você declara funções por JSON Schema; o modelo decide quando chamá-las, emite uma function_call com argumentos, sua aplicação executa e devolve o function_call_output, e o modelo produz a resposta final (ou mais chamadas).

    + +

    10.1 Definindo funções

    +

    Cada função tem type: "function", name, description (quando e como usar), parameters (JSON Schema) e strict.

    +
    {
    +  "type": "function",
    +  "name": "get_weather",
    +  "description": "Retorna o tempo atual para a localização dada.",
    +  "parameters": {
    +    "type": "object",
    +    "properties": {
    +      "location": { "type": "string", "description": "Cidade e país, ex.: Bogotá, Colômbia" },
    +      "units": { "type": "string", "enum": ["celsius", "fahrenheit"] }
    +    },
    +    "required": ["location", "units"],
    +    "additionalProperties": false
    +  },
    +  "strict": true
    +}
    + +

    10.2 Loop de execução

    +
    +
    + + + +
    +
    +
    import json
    +from openai import OpenAI
    +
    +client = OpenAI()
    +
    +tools = [{
    +    "type": "function",
    +    "name": "get_weather",
    +    "description": "Retorna o tempo atual para a localização dada.",
    +    "parameters": {
    +        "type": "object",
    +        "properties": {
    +            "location": {"type": "string"},
    +            "units": {"type": "string", "enum": ["celsius", "fahrenheit"]},
    +        },
    +        "required": ["location", "units"],
    +        "additionalProperties": False,
    +    },
    +    "strict": True,
    +}]
    +
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    input=[{"role": "user", "content": "Qual o tempo em Paris?"}],
    +    tools=tools,
    +)
    +
    +# 1) Detectar e executar chamadas (assuma 0..N)
    +inputs = []
    +for item in resp.output:
    +    if item.type == "function_call":
    +        args = json.loads(item.arguments)
    +        result = {"temperature": "25", "unit": "C"}  # sua lógica real
    +        inputs.append({
    +            "type": "function_call_output",
    +            "call_id": item.call_id,
    +            "output": json.dumps(result),
    +        })
    +
    +# 2) Reenviar reasoning + chamadas + saídas; encadeie com previous_response_id
    +final = client.responses.create(
    +    model="gpt-5.5",
    +    previous_response_id=resp.id,
    +    input=inputs,
    +    tools=tools,
    +)
    +print(final.output_text)
    +
    +
    +
    import OpenAI from "openai";
    +const client = new OpenAI();
    +
    +const tools = [{
    +  type: "function",
    +  name: "get_weather",
    +  description: "Retorna o tempo atual para a localização dada.",
    +  parameters: {
    +    type: "object",
    +    properties: {
    +      location: { type: "string" },
    +      units: { type: "string", enum: ["celsius", "fahrenheit"] },
    +    },
    +    required: ["location", "units"],
    +    additionalProperties: false,
    +  },
    +  strict: true,
    +}];
    +
    +const resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: [{ role: "user", content: "Qual o tempo em Paris?" }],
    +  tools,
    +});
    +
    +const inputs = [];
    +for (const item of resp.output) {
    +  if (item.type === "function_call") {
    +    const args = JSON.parse(item.arguments);
    +    const result = { temperature: "25", unit: "C" }; // sua lógica real
    +    inputs.push({
    +      type: "function_call_output",
    +      call_id: item.call_id,
    +      output: JSON.stringify(result),
    +    });
    +  }
    +}
    +
    +const final = await client.responses.create({
    +  model: "gpt-5.5",
    +  previous_response_id: resp.id,
    +  input: inputs,
    +  tools,
    +});
    +console.log(final.output_text);
    +
    +
    +
    # 1) Primeira chamada com a definição da ferramenta
    +curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": [{ "role": "user", "content": "Qual o tempo em Paris?" }],
    +    "tools": [{
    +      "type": "function", "name": "get_weather", "strict": true,
    +      "description": "Retorna o tempo atual para a localização dada.",
    +      "parameters": {
    +        "type": "object",
    +        "properties": {
    +          "location": {"type":"string"},
    +          "units": {"type":"string","enum":["celsius","fahrenheit"]}
    +        },
    +        "required": ["location","units"], "additionalProperties": false
    +      }
    +    }]
    +  }'
    +
    +# 2) Devolva o resultado encadeando previous_response_id
    +curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "previous_response_id": "resp_123",
    +    "input": [{
    +      "type": "function_call_output",
    +      "call_id": "call_abc",
    +      "output": "{\"temperature\":\"25\",\"unit\":\"C\"}"
    +    }]
    +  }'
    +
    +
    + +

    10.3 tool_choice e parallel calls

    +
    + + + + + + + + + +
    tool_choiceComportamento
    "auto" (padrão)O modelo chama zero, uma ou várias funções.
    "required"O modelo deve chamar uma ou mais funções.
    {"type":"function","name":"..."}Força exatamente uma função específica.
    {"type":"allowed_tools","mode":"auto","tools":[...]}Restringe a um subconjunto sem remover ferramentas — útil para preservar prompt caching.
    "none"Imita o comportamento de não passar funções.
    +
    +

    O modelo pode chamar várias funções no mesmo turno (parallel tool calls). Desative com parallel_tool_calls: false para garantir zero ou uma chamada. Parallel calls não se aplicam a ferramentas integradas.

    + +
    Dica: habilite sempre strict: true — ele usa Structured Outputs para garantir aderência ao schema (exige additionalProperties: false e todos os campos em required; campos opcionais via tipo null). Mantenha menos de ~20 funções disponíveis no início de um turno; para catálogos grandes, use tool search.
    + +
    Nota: na Responses API o type: "function" fica no topo da definição (ao lado de name/parameters), diferente do Chat Completions, que aninha tudo sob uma chave "function". Da mesma forma, tool_choice específico aqui é {"type":"function","name":"..."} — sem aninhamento.
    + +

    10.4 Custom tools & gramáticas (CFG)

    +

    Quando a entrada da ferramenta é texto livre (código, um comando, uma consulta) em vez de um objeto JSON, use uma custom tool (type: "custom"). O modelo emite um item custom_tool_call com o campo input em texto puro. Custom tools não suportam parallel tool calls — passe parallel_tool_calls: false.

    +

    Para garantir que esse texto seja sintaticamente válido (um dialeto SQL, uma DSL), anexe uma gramática livre de contexto (CFG) via bloco format, com syntax "lark" ou "regex". A amostragem é restringida à gramática, então a saída sempre casa com ela.

    +
    mssql_grammar = r"""
    +start: "SELECT" column "FROM" table
    +column: "id" | "name" | "email"
    +table: "users" | "orders"
    +"""
    +
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    input="Liste os e-mails de todos os usuários.",
    +    tools=[{
    +        "type": "custom",
    +        "name": "mssql_query",
    +        "description": "Gera uma consulta SQL válida no dialeto suportado.",
    +        "format": {"type": "grammar", "syntax": "lark", "definition": mssql_grammar},
    +    }],
    +    parallel_tool_calls=False,
    +)
    +# A resposta traz um item custom_tool_call com .input em texto restrito pela gramática.
    +
    Atenção: mantenha a gramática o mais simples possível — gramáticas complexas podem ser rejeitadas. O dialeto Lark não suporta lookaround, modificadores lazy (*?, +?), prioridades de terminal, templates nem %import (exceto %import common); o mesmo vale para lookaround/lazy em regex.
    + + +
    + +
    +

    11. Ferramentas integradas

    +

    Além das suas funções, a Responses API oferece ferramentas integradas (hosted tools), ativadas pelo array tools. Elas estão in-distribution para o pós-treino dos modelos, então tendem a ter melhor seleção e execução do que ferramentas customizadas equivalentes. O modelo decide quando usá-las com base no prompt; você guia com tool_choice.

    + +

    11.1 Web search

    +

    Permite acesso a informação atualizada da internet com citações. Para integrações novas, use { "type": "web_search" } (suporta controles como filters, sources, external_web_access e return_token_budget). A saída inclui um item web_search_call (com a ação: search, open_page ou find_in_page) e uma message com texto e anotações url_citation. Desde jun/2026 a busca também pode retornar resultados de imagem (ver abaixo). Para pesquisa profunda multi-etapa, use gpt-5.5 com reasoning em high/xhigh e background mode.

    +
    +
    + + + +
    +
    +
    response = client.responses.create(
    +    model="gpt-5.5",
    +    input="Quais foram as novidades de IA esta semana?",
    +    tools=[{"type": "web_search"}],
    +)
    +print(response.output_text)
    +
    +
    +
    const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Quais foram as novidades de IA esta semana?",
    +  tools: [{ type: "web_search" }],
    +});
    +console.log(response.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "Quais foram as novidades de IA esta semana?",
    +    "tools": [{ "type": "web_search" }]
    +  }'
    +
    +
    +
    Atenção: trate o conteúdo de páginas, PDFs e e-mails retornados como entrada não confiável. Só instruções diretas do usuário contam como permissão.
    + +

    Resultados de imagem (image search)

    +

    O web search pode retornar imagens junto dos resultados de texto (novidade de jun/2026) — útil quando o app precisa de visuais atuais e ancorados na web: fotos de produtos, lugares, eventos, referências visuais com link da fonte. Configure search_content_types incluindo "image" (adicione "text" se também quiser resultados textuais que ajudem o modelo a resumir, ranquear ou explicar as imagens) e ajuste o comportamento com image_settings: max_results (quantidade de imagens) e caption (descrições curtas quando disponíveis).

    +

    Os resultados de imagem não entram na message final: eles voltam no próprio item web_search_call. Para inspecioná-los, peça include: ["web_search_call.results"] e leia web_search_call.results[] — cada image_result traz image_url (URL canônica da imagem), source_website_url (página onde a imagem foi encontrada), thumbnail_url e caption (quando disponíveis).

    +
    resp = client.responses.create(
    +    model="gpt-5.5",
    +    input="Fotos recentes da Golden Gate ao pôr do sol",
    +    tools=[{
    +        "type": "web_search",
    +        "search_content_types": ["image", "text"],
    +        "image_settings": {"max_results": 5, "caption": True},
    +    }],
    +    include=["web_search_call.results"],
    +)
    +
    +for item in resp.output:
    +    if item.type == "web_search_call":
    +        for r in (item.results or []):
    +            if r.type == "image_result":
    +                print(r.image_url, "|", r.source_website_url, "|", r.caption)
    +
    {
    +  "output": [
    +    {
    +      "type": "web_search_call",
    +      "status": "completed",
    +      "results": [
    +        {
    +          "type": "image_result",
    +          "image_url": "https://cdn.example/golden-gate-sunset.jpg",
    +          "thumbnail_url": "https://cdn.example/golden-gate-sunset-thumb.jpg",
    +          "source_website_url": "https://example.com/source-page",
    +          "caption": "Golden Gate Bridge at sunset"
    +        }
    +      ]
    +    }
    +  ]
    +}
    + +

    11.2 File search

    +

    Recupera informação de uma base de conhecimento de arquivos enviados, via busca semântica e por palavra-chave. Antes, crie um vector store e suba arquivos a ele; depois inclua file_search com os vector_store_ids. A saída traz um item file_search_call e uma message com citações de arquivo. Você pode limitar resultados, incluir os resultados via include e filtrar por metadados.

    +
    +
    + + + +
    +
    +
    response = client.responses.create(
    +    model="gpt-5.5",
    +    input="O que é deep research da OpenAI?",
    +    tools=[{
    +        "type": "file_search",
    +        "vector_store_ids": ["vs_abc123"],
    +    }],
    +)
    +print(response.output_text)
    +
    +
    +
    const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "O que é deep research da OpenAI?",
    +  tools: [{ type: "file_search", vector_store_ids: ["vs_abc123"] }],
    +});
    +console.log(response.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "O que é deep research da OpenAI?",
    +    "tools": [{ "type": "file_search", "vector_store_ids": ["vs_abc123"] }]
    +  }'
    +
    +
    + +

    11.2.1 Retrieval API — busca direta em vector stores (vector_stores.search)

    +

    Além do tool file_search (que o modelo aciona sozinho dentro da Responses API), a OpenAI expõe a Retrieval API: o endpoint POST /v1/vector_stores/{vector_store_id}/search faz busca semântica direta no vector store, sem passar por um modelo de linguagem. É a peça certa para pipelines de RAG onde você quer montar o prompt final por conta própria, reaproveitar os chunks recuperados em outro serviço, ou apenas inspecionar o que a base retorna. Por padrão traz até 10 resultados; ajuste com max_num_results (máximo 50). Cada resultado vem com os chunks relevantes, um score de similaridade e o arquivo de origem.

    + +
    +
    + + + +
    +
    +
    results = client.vector_stores.search(
    +    vector_store_id="vs_abc123",
    +    query="Quantas marmotas são permitidas por passageiro?",
    +    max_num_results=20,
    +    rewrite_query=True,
    +    ranking_options={
    +        "ranker": "auto",
    +        "score_threshold": 0.5,
    +    },
    +)
    +# O que a API de fato buscou (quando rewrite_query=True):
    +print(results.search_query)
    +for r in results.data:
    +    print(r.score, r.filename)
    +    for part in r.content:          # cada chunk recuperado
    +        print(part.text[:200])
    +
    +
    +
    const results = await client.vectorStores.search("vs_abc123", {
    +  query: "Quantas marmotas são permitidas por passageiro?",
    +  max_num_results: 20,
    +  rewrite_query: true,
    +  ranking_options: { ranker: "auto", score_threshold: 0.5 },
    +});
    +console.log(results.search_query); // query reescrita
    +for (const r of results.data) {
    +  console.log(r.score, r.filename);
    +}
    +
    +
    +
    curl https://api.openai.com/v1/vector_stores/vs_abc123/search \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "query": "Quantas marmotas são permitidas por passageiro?",
    +    "max_num_results": 20,
    +    "rewrite_query": true,
    +    "ranking_options": { "ranker": "auto", "score_threshold": 0.5 }
    +  }'
    +
    +
    + +
    Dica — rewrite_query: com rewrite_query: true, a API reescreve a consulta do usuário para uma forma mais eficaz de busca (ex.: transforma Gostaria de saber a altura do prédio principal em altura do prédio principal). A versão efetivamente buscada fica no campo search_query do resultado — logue esse campo para auditar por que uma busca trouxe (ou não) certo chunk.
    + +

    Ranking & hybrid search (ranking_options)

    +

    Se os resultados vierem pouco relevantes, ajuste ranking_options. O ranker aceita auto ou default-2024-08-21; score_threshold vai de 0.0 a 1.0 — quanto mais alto, mais a busca se restringe aos chunks realmente relevantes (descartando os de baixa relevância, ao custo de eventualmente cortar algum útil). Ao fornecer ranking_options.hybrid_search, você combina a correspondência semântica (embeddings) com a correspondência textual esparsa (palavra-chave) via reciprocal rank fusion (RRF), balanceando os dois lados com embedding_weight (o rrf_embedding_weight) e text_weight (o rrf_text_weight): suba o primeiro para privilegiar similaridade semântica, o segundo para privilegiar sobreposição literal de termos. Ao menos um dos pesos precisa ser maior que zero.

    + +
    + + + + + + + + + + +
    ParâmetroFaixa / valoresEfeito
    ranking_options.rankerauto · default-2024-08-21Estratégia de reranking dos resultados.
    ranking_options.score_threshold0.0 – 1.0Descarta chunks abaixo do score de relevância (maior = mais restritivo).
    hybrid_search.embedding_weight≥ 0 (peso RRF)Peso da busca semântica (embeddings) na fusão RRF.
    hybrid_search.text_weight≥ 0 (peso RRF)Peso da busca por palavra-chave (texto esparso) na fusão RRF.
    +
    + +

    Filtro por atributos (attribute_filter)

    +

    Cada arquivo do vector store carrega até 16 pares de metadados customizados (attributes). Na busca, use attribute_filter para restringir o corpus antes da fase semântica. Há filtros de comparação — eq, ne, gt, gte, lt, lte, in, nin — sobre uma key/value, e filtros compostos que combinam vários com and/or, inclusive intervalos de data via timestamp Unix e exclusão por nome de arquivo.

    +
    {
    +  "type": "and",
    +  "filters": [
    +    { "type": "eq", "key": "region", "value": "us" },
    +    { "type": "gte", "key": "published_at", "value": 1704067200 }
    +  ]
    +}
    + +

    Chunking (chunking_strategy)

    +

    Controla como cada arquivo é dividido em pedaços (chunks) antes de ser embeddado e indexado. Sem configuração, usa a estratégia auto: max_chunk_size_tokens = 800 e chunk_overlap_tokens = 400. Ao passar a estratégia static, respeite os limites documentados: max_chunk_size_tokens entre 100 e 4096 (inclusive) e chunk_overlap_tokens não-negativo que não exceda max_chunk_size_tokens / 2.

    +
    client.vector_stores.file_batches.create_and_poll(
    +    vector_store_id="vs_abc123",
    +    files=[
    +        {"file_id": "file_123", "attributes": {"department": "finance"}},
    +        {
    +            "file_id": "file_456",
    +            "chunking_strategy": {
    +                "type": "static",
    +                "static": {
    +                    "max_chunk_size_tokens": 1200,
    +                    "chunk_overlap_tokens": 200,
    +                },
    +            },
    +        },
    +    ],
    +)
    + +

    Ingestão: batches e create_and_poll

    +

    Para subir muitos arquivos de uma vez, prefira file_batches: cada requisição de batch aceita até 500 arquivos e reduz a contenção contra o limite de escrita. O helper create_and_poll — disponível tanto para arquivo único (files.create_and_poll) quanto para lote (file_batches.create_and_poll) — cria o recurso e faz polling até a indexação terminar, poupando você de escrever o loop de espera na mão.

    +
    # Arquivo único, bloqueando até a indexação terminar
    +client.vector_stores.files.create_and_poll(
    +    vector_store_id="vs_abc123",
    +    file_id="file_123",
    +)
    +
    +# Lote de até 500 arquivos, bloqueando até terminar
    +client.vector_stores.file_batches.create_and_poll(
    +    vector_store_id="vs_abc123",
    +    files=[{"file_id": "file_123"}, {"file_id": "file_456"}],
    +)
    + +
    Pegadinhas de ingestão: a criação de arquivo/batch é assíncrona — sem create_and_poll, um search logo em seguida pode não achar o conteúdo ainda não indexado. A adição de arquivos é rate-limited em 300 requisições/min compartilhadas por vector_store_id (o batch conta como 1), então lotes vencem N chamadas unitárias. Cada arquivo pode ter no máximo 512 MB e 5.000.000 de tokens. E a remoção é eventualmente consistente: resultados podem citar um arquivo recém-removido por um curto período.
    + +
    Armazenamento e custo (expires_after): os primeiros 1 GB de armazenamento (somando todos os vector stores da organização) são gratuitos; acima disso, $0,10/GB/dia, calculado sobre o tamanho dos chunks parseados e seus embeddings. Defina uma política de expiração com expires_after (único anchor suportado: last_active_at) para descartar stores ociosos e parar de pagar por eles.
    +
    client.vector_stores.update(
    +    vector_store_id="vs_abc123",
    +    expires_after={"anchor": "last_active_at", "days": 7},
    +)
    + +
    Search direto ≠ resposta gerada: vector_stores.search devolve os chunks (com score e arquivo de origem) para você montar o prompt — ela não redige resposta em linguagem natural nem cita fontes sozinha. Se quiser que o próprio modelo recupere, cite os arquivos e componha a resposta final dentro da Responses API, use o tool file_search descrito em §11.2.
    + + + +

    11.3 MCP & Connectors

    +

    Dê ao modelo novas capacidades via servidores MCP remotos (qualquer servidor que implemente o Model Context Protocol) e connectors (wrappers MCP mantidos pela OpenAI para serviços como Google Workspace ou Dropbox). Ambos usam o tipo de ferramenta mcp. MCP remoto exige server_url (e às vezes um token OAuth em authorization); connectors exigem connector_id e o token OAuth. As chamadas podem ser automáticas ou exigir aprovação (require_approval).

    +
    +
    + + + +
    +
    +
    resp = client.responses.create(
    +    model="gpt-5.5",
    +    tools=[{
    +        "type": "mcp",
    +        "server_label": "dmcp",
    +        "server_description": "Servidor MCP de D&D para rolagem de dados.",
    +        "server_url": "https://dmcp-server.deno.dev/sse",
    +        "require_approval": "never",
    +    }],
    +    input="Role 2d4+1",
    +)
    +print(resp.output_text)
    +
    +
    +
    const resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  tools: [{
    +    type: "mcp",
    +    server_label: "dmcp",
    +    server_description: "Servidor MCP de D&D para rolagem de dados.",
    +    server_url: "https://dmcp-server.deno.dev/sse",
    +    require_approval: "never",
    +  }],
    +  input: "Role 2d4+1",
    +});
    +console.log(resp.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "tools": [{
    +      "type": "mcp",
    +      "server_label": "dmcp",
    +      "server_description": "Servidor MCP de D&D para rolagem de dados.",
    +      "server_url": "https://dmcp-server.deno.dev/sse",
    +      "require_approval": "never"
    +    }],
    +    "input": "Role 2d4+1"
    +  }'
    +
    +
    +
    Cuidado: confie apenas em servidores MCP que você revisou. Um servidor malicioso pode exfiltrar qualquer dado que entre no contexto do modelo. Para servidores privados/on-premises, use o Secure MCP Tunnel em vez de expô-los à internet pública.
    + +

    11.4 Code Interpreter

    +

    Permite ao modelo escrever e executar Python num ambiente sandbox (o modelo o conhece como "python tool"). Use para análise de dados, geração de arquivos/gráficos, matemática e código iterativo. Requer um container: modo auto (cria ou reusa) ou explícito (via /v1/containers). O memory_limit padrão é 1 GB.

    +
    +
    + + + +
    +
    +
    resp = client.responses.create(
    +    model="gpt-5.5",
    +    tools=[{
    +        "type": "code_interpreter",
    +        "container": {"type": "auto", "memory_limit": "4g"},
    +    }],
    +    instructions="Use a python tool para resolver problemas de matemática.",
    +    input="Resolva 3x + 11 = 14.",
    +)
    +print(resp.output_text)
    +
    +
    +
    const resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  tools: [{
    +    type: "code_interpreter",
    +    container: { type: "auto", memory_limit: "4g" },
    +  }],
    +  instructions: "Use a python tool para resolver problemas de matemática.",
    +  input: "Resolva 3x + 11 = 14.",
    +});
    +console.log(resp.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "tools": [{ "type": "code_interpreter", "container": { "type": "auto", "memory_limit": "4g" } }],
    +    "instructions": "Use a python tool para resolver problemas de matemática.",
    +    "input": "Resolva 3x + 11 = 14."
    +  }'
    +
    +
    + +

    11.5 Computer use

    +

    Permite ao modelo operar software pela interface: ele inspeciona screenshots e devolve ações de UI (cliques, digitação, rolagem, pedidos de screenshot) que seu código executa. O gpt-5.4 recebeu treino específico para esse trabalho. Há três formatos de harness: o loop integrado (ferramenta computer), uma ferramenta/harness custom sobre Playwright/Selenium/VNC/MCP, ou um harness de execução de código.

    +
    Cuidado: rode Computer use em navegador/VM isolado, mantenha humano no loop para ações de alto impacto e trate todo conteúdo de tela como entrada não confiável. Passe um env vazio e desative extensões e acesso ao filesystem do host quando possível.
    + +

    11.6 Apply Patch

    +

    A ferramenta apply_patch deixa o modelo criar, atualizar e deletar arquivos no seu código via diffs estruturados (formato V4A), habilitando edição iterativa multi-arquivo. Por ser uma ferramenta nomeada (não uma função freeform que você descreve), está in-distribution para o pós-treino — o que reduz a taxa de falha de patch em cerca de 35% frente à abordagem freeform/JSON anterior. O fluxo: ative tools=[{"type":"apply_patch"}], o modelo emite itens apply_patch_call (operações create_file/update_file/delete_file, com path e diff), sua aplicação aplica os patches e devolve um apply_patch_call_output por call_id com status (completed/failed). Disponível só pela Responses API. Ótima combinada com a ferramenta shell para descoberta de arquivos.

    +
    Nota: o diff V4A é baseado em contexto, não em números de linha — usa âncoras @@ e o envelope *** Begin Patch / *** Add File: / *** Update File: / *** Delete File: / *** Move to: / *** End Patch, com prefixos de linha + (adição), - (remoção) e espaço (contexto). Aplicar a um arquivo divergente falha; devolva status: "failed" com output para o modelo se recuperar.
    +
    resp = client.responses.create(
    +    model="gpt-5.5",
    +    tools=[{"type": "apply_patch"}],
    +    input="Renomeie a função `parse` para `parse_input` em src/io.py.",
    +)
    +# Itere sobre resp.output procurando itens type == "apply_patch_call",
    +# aplique o diff no seu workspace e devolva apply_patch_call_output por call_id.
    +
    Atenção: no seu harness, valide caminhos (evite directory traversal), restrinja edições a diretórios permitidos, faça backup antes de aplicar e sempre devolva status: "failed" com um output claro quando um patch não aplicar — assim o modelo se recupera.
    + +

    11.7 Tool search

    +

    Tool search deixa o modelo buscar e carregar ferramentas no contexto sob demanda, evitando carregar todo o catálogo de uma vez — reduz tokens e custo. Só gpt-5.4 e modelos posteriores suportam. Para ativar: adicione {"type": "tool_search"} ao tools e marque as funções/MCP a adiar com defer_loading: true. As ferramentas carregadas são injetadas no fim do contexto, preservando o cache.

    +
    {
    +  "tools": [
    +    {
    +      "type": "namespace",
    +      "name": "crm",
    +      "description": "Ferramentas de CRM para busca de clientes e gestão de pedidos.",
    +      "tools": [
    +        {
    +          "type": "function",
    +          "name": "list_open_orders",
    +          "description": "Lista pedidos abertos por customer_id.",
    +          "defer_loading": true,
    +          "parameters": {
    +            "type": "object",
    +            "properties": { "customer_id": { "type": "string" } },
    +            "required": ["customer_id"],
    +            "additionalProperties": false
    +          }
    +        }
    +      ]
    +    },
    +    { "type": "tool_search" }
    +  ]
    +}
    +

    Há dois modos: hosted (a OpenAI busca entre as ferramentas declaradas e devolve o subconjunto carregado na mesma resposta, via itens tool_search_call e tool_search_output) e client-executed (execution: "client": o modelo emite tool_search_call, sua aplicação faz a busca e devolve um tool_search_output com as ferramentas a carregar). Prefira agrupar em namespaces ou servidores MCP, com até ~10 funções cada e descrições curtas e discriminativas.

    + +

    11.8 Local shell & Shell

    +

    A ferramenta shell dá ao modelo um ambiente de terminal completo, em container hospedado pela OpenAI (use environment: {"type": "container_auto"}) ou num runtime local que você executa. Disponível só pela Responses API.

    +
    +
    + + + +
    +
    +
    response = client.responses.create(
    +    model="gpt-5.5",
    +    tools=[{"type": "shell", "environment": {"type": "container_auto"}}],
    +    input=[{
    +        "type": "message",
    +        "role": "user",
    +        "content": [{
    +            "type": "input_text",
    +            "text": "Execute: ls -lah /mnt/data && python --version",
    +        }],
    +    }],
    +    tool_choice="auto",
    +)
    +print(response.output_text)
    +
    +
    +
    const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  tools: [{ type: "shell", environment: { type: "container_auto" } }],
    +  input: [{
    +    type: "message",
    +    role: "user",
    +    content: [{ type: "input_text", text: "Execute: ls -lah /mnt/data && python --version" }],
    +  }],
    +  tool_choice: "auto",
    +});
    +console.log(response.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "tools": [{ "type": "shell", "environment": { "type": "container_auto" } }],
    +    "input": [{
    +      "type": "message", "role": "user",
    +      "content": [{ "type": "input_text", "text": "Execute: ls -lah /mnt/data" }]
    +    }],
    +    "tool_choice": "auto"
    +  }'
    +
    +
    +

    O runtime hospedado é baseado em Debian 12, com diretório de trabalho /mnt/data (caminho suportado para artefatos baixáveis) e linguagens pré-instaladas (Python 3.11, Node.js 22, Java 17, PHP 8.2, Ruby 3.1, Go 1.23). Não há TTY interativo nem sudo. Para fluxos iterativos, crie um container reutilizável e referencie-o entre chamadas.

    +
    Cuidado: executar comandos arbitrários é perigoso. Sempre faça sandbox, aplique allowlists/denylists e registre a atividade da ferramenta para auditoria.
    + +

    11.9 Programmatic Tool Calling (PTC) gpt-5.6 · 2026-07-09

    +

    O Programmatic Tool Calling deixa o modelo escrever e executar JavaScript que coordena as tools de um request da Responses API: chamadas em paralelo, loops, condições e resultados intermediários mantidos no runtime hospedado — em vez de um round trip modelo↔tool por chamada. Vale quando uma etapa tem fluxo de controle previsível e o código pode devolver um resultado estruturado menor (filtrar/juntar/agregar N resultados antes de voltar ao contexto do modelo).

    +
      +
    • Runtime: cada programa roda em um V8 isolado e efêmero (JS com top-level await). Não há Node.js, instalação de pacotes, rede direta, filesystem geral, subprocessos, console nem estado persistente entre execuções. O programa só interage com o mundo via tools habilitadas no request e emite saída com text(...)/image(...).
    • +
    • Config: adicione a hosted tool {"type":"programmatic_tool_calling"} e marque cada tool elegível com allowed_callers: ["direct"] (só o modelo), ["programmatic"] (só código) ou ambos. Defina output_schema nas functions para o JS usar os campos com segurança. Suportadas em programa: function/custom, mcp (com require_approval pausando o programa), apply_patch, shell local/hosted e code_interpreter. tool_search roda só top-level — deferred tools precisam ser carregadas antes do programa começar.
    • +
    • Quem executa o quê: a OpenAI executa o JS gerado; sua aplicação continua executando as function calls client-owned que o programa dispara (itens function_call com caller.caller_id apontando para o program). Devolva cada resultado como function_call_output copiando o campo caller sem alterar — é ele que retoma o programa certo. O resultado final chega num item program_output (status completed/incomplete).
    • +
    • ZDR/store=false: PTC suporta ZDR sem container persistente de execução. Sob store:false, replaye todos os itens (program, reasoning, function calls/outputs, program_output) + include: ["reasoning.encrypted_content"].
    • +
    • Quando NÃO usar: uma única chamada; quando cada resultado precisa de julgamento fresco do modelo; ações com side-effect/aprovação (mantenha direct para preservar a fronteira de autorização); validação final de citações/artefatos nativos. Cheque as permissões de cada chamada na sua aplicação, mesmo vindo de programa hospedado — e meça contra baseline direct (tokens, latência, corretude) antes de adotar.
    • +
    + + +

    11.10 Receitas e exemplos oficiais (Cookbook)

    +

    O OpenAI Cookbook traz receitas executáveis para os padrões desta parte. As abaixo estão alinhadas à Responses API e aos modelos atuais; use-as como ponto de partida e adapte os IDs de modelo para gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano.

    +
    + + + + + + + + + + + + +
    ReceitaO que ensinaLink oficial
    GPT-5 prompting guideControle de eagerness/persistência, context gathering, preâmbulos de ferramenta e o ganho de qualidade ao encadear com previous_response_id.cookbook.openai.com/examples/gpt-5/gpt-5_prompting_guide
    GPT-5.1 prompting guidereasoning.effort: none com ferramentas, as ferramentas nomeadas apply_patch e shell, e atualizações de status (preâmbulos).cookbook.openai.com/examples/gpt-5/gpt-5-1_prompting_guide
    GPT-5 — novos parâmetros e ferramentasverbosity, custom tools de texto livre e gramáticas livres de contexto (CFG, Lark/regex).cookbook.openai.com/examples/gpt-5/gpt-5_new_params_and_tools
    Construindo um coding agent com GPT-5.1Loop de agente de código real fiando apply_patch + shell pela Responses API.cookbook.openai.com/examples/Build_a_coding_agent_with_GPT-5.1
    Structured Outputs — introduçãoJSON estrito por json_schema + helper Pydantic; regras de schema (todos os campos em required, additionalProperties: false, raiz objeto) e refusals.cookbook.openai.com/examples/structured_outputs_intro
    File Search com a Responses APIVector stores, a ferramenta file_search e citações de arquivo em RAG.cookbook.openai.com/examples/file_search_responses
    Guia da ferramenta MCPConfigurar o tool mcp, listar ferramentas remotas e tratar o fluxo de aprovação.cookbook.openai.com/examples/mcp/mcp_tool_guide
    Agents SDK (Python)Agent/Runner, @function_tool, handoffs vs agent.as_tool(), guardrails com tripwire e sessões de memória — sobre a Responses API.openai.github.io/openai-agents-python
    +
    +
    Atenção — receitas legadas: várias receitas mais antigas do Cookbook usam a Chat Completions API antiga e modelos descontinuados (ex.: How to format inputs to ChatGPT models, How to call functions with chat models, Orchestrating agents — um protótipo Swarm — e versões "with older completions API"). Aproveite delas só os conceitos atemporais (regras de schema, padrões de prompt); o equivalente moderno é sempre a Responses API com gpt-5.5 e, para multi-agentes, o Agents SDK (em vez de reimplementar o loop sobre Chat Completions).
    + +

    Exemplos executáveis (Python e JavaScript) das receitas-chave desta parte, adaptados à Responses API e modelos atuais:

    + +

    Structured Outputs (json_schema estrito) — cookbook.openai.com/examples/structured_outputs_intro

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +from pydantic import BaseModel
    +
    +client = OpenAI()
    +
    +# Schema estrito: campos tipados via Pydantic (vira json_schema com strict=true)
    +class Step(BaseModel):
    +    explanation: str
    +    output: str
    +
    +class MathReasoning(BaseModel):
    +    steps: list[Step]
    +    final_answer: str
    +
    +# responses.parse aplica o schema e devolve o objeto já tipado
    +response = client.responses.parse(
    +    model="gpt-5.5",
    +    input=[
    +        {"role": "system", "content": "Você é um tutor de matemática. Resolva passo a passo."},
    +        {"role": "user", "content": "Como resolvo 8x + 7 = -23?"},
    +    ],
    +    text_format=MathReasoning,
    +)
    +
    +for output in response.output:
    +    if output.type != "message":
    +        continue
    +    for item in output.content:
    +        if item.type == "refusal":
    +            # Recusa por segurança: não segue o schema; trate à parte
    +            print("Recusa:", item.refusal)
    +        elif item.parsed:
    +            print(item.parsed.final_answer)
    +
    +
    +
    import OpenAI from "openai";
    +import { z } from "zod";
    +import { zodTextFormat } from "openai/helpers/zod";
    +
    +const client = new OpenAI();
    +
    +// Schema estrito definido com Zod (vira json_schema com strict=true)
    +const Step = z.object({ explanation: z.string(), output: z.string() });
    +const MathReasoning = z.object({
    +  steps: z.array(Step),
    +  final_answer: z.string(),
    +});
    +
    +const response = await client.responses.parse({
    +  model: "gpt-5.5",
    +  input: [
    +    { role: "system", content: "Você é um tutor de matemática. Resolva passo a passo." },
    +    { role: "user", content: "Como resolvo 8x + 7 = -23?" },
    +  ],
    +  text: { format: zodTextFormat(MathReasoning, "math_reasoning") },
    +});
    +
    +for (const output of response.output) {
    +  if (output.type !== "message") continue;
    +  for (const item of output.content) {
    +    if (item.type === "refusal") {
    +      // Recusa por segurança: não segue o schema; trate à parte
    +      console.log("Recusa:", item.refusal);
    +    } else if (item.parsed) {
    +      console.log(item.parsed.final_answer);
    +    }
    +  }
    +}
    +
    +
    + +

    File Search / RAG (vector store + tool file_search) — cookbook.openai.com/examples/file_search_responses

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# 1) Cria o vector store e anexa um arquivo (a indexação roda no servidor)
    +vector_store = client.vector_stores.create(name="base_conhecimento")
    +# purpose="assistants" é o valor documentado para ingestão em vector store / file_search
    +file = client.files.create(file=open("manual.pdf", "rb"), purpose="assistants")
    +client.vector_stores.files.create(
    +    vector_store_id=vector_store.id,
    +    file_id=file.id,
    +)
    +
    +# 2) A Responses API chama o tool file_search e cita os arquivos
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    input="Qual é a política de reembolso?",
    +    tools=[{
    +        "type": "file_search",
    +        "vector_store_ids": [vector_store.id],
    +        "max_num_results": 5,
    +    }],
    +)
    +
    +# 3) output[0] = file_search_call; output[1] = message com texto + citações
    +print(response.output_text)
    +for item in response.output:
    +    if item.type == "message":
    +        for ann in item.content[0].annotations:
    +            print("Citação:", ann.filename)
    +
    +
    +
    import OpenAI from "openai";
    +import fs from "fs";
    +
    +const client = new OpenAI();
    +
    +// 1) Cria o vector store e anexa um arquivo (a indexação roda no servidor)
    +const vectorStore = await client.vectorStores.create({ name: "base_conhecimento" });
    +// purpose: "assistants" é o valor documentado para ingestão em vector store / file_search
    +const file = await client.files.create({
    +  file: fs.createReadStream("manual.pdf"),
    +  purpose: "assistants",
    +});
    +await client.vectorStores.files.create(vectorStore.id, { file_id: file.id });
    +
    +// 2) A Responses API chama o tool file_search e cita os arquivos
    +const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Qual é a política de reembolso?",
    +  tools: [{
    +    type: "file_search",
    +    vector_store_ids: [vectorStore.id],
    +    max_num_results: 5,
    +  }],
    +});
    +
    +// 3) output[0] = file_search_call; output[1] = message com texto + citações
    +console.log(response.output_text);
    +for (const item of response.output) {
    +  if (item.type === "message") {
    +    for (const ann of item.content[0].annotations) console.log("Citação:", ann.filename);
    +  }
    +}
    +
    +
    + +

    MCP remoto (tool mcp com fluxo de aprovação) — cookbook.openai.com/examples/mcp/mcp_tool_guide

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# require_approval="always" faz a API pedir aprovação antes de cada chamada
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    tools=[{
    +        "type": "mcp",
    +        "server_label": "dmcp",
    +        "server_description": "Servidor MCP de D&D para rolar dados.",
    +        "server_url": "https://dmcp-server.deno.dev/sse",
    +        "require_approval": "always",
    +    }],
    +    input="Role 2d4+1",
    +)
    +
    +# A saída traz um item mcp_approval_request; aprove encadeando a resposta
    +for item in resp.output:
    +    if item.type == "mcp_approval_request":
    +        resp = client.responses.create(
    +            model="gpt-5.5",
    +            previous_response_id=resp.id,
    +            input=[{
    +                "type": "mcp_approval_response",
    +                "approve": True,
    +                "approval_request_id": item.id,
    +            }],
    +        )
    +
    +print(resp.output_text)
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +
    +// require_approval: "always" faz a API pedir aprovação antes de cada chamada
    +let resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  tools: [{
    +    type: "mcp",
    +    server_label: "dmcp",
    +    server_description: "Servidor MCP de D&D para rolar dados.",
    +    server_url: "https://dmcp-server.deno.dev/sse",
    +    require_approval: "always",
    +  }],
    +  input: "Role 2d4+1",
    +});
    +
    +// A saída traz um item mcp_approval_request; aprove encadeando a resposta
    +for (const item of resp.output) {
    +  if (item.type === "mcp_approval_request") {
    +    resp = await client.responses.create({
    +      model: "gpt-5.5",
    +      previous_response_id: resp.id,
    +      input: [{
    +        type: "mcp_approval_response",
    +        approve: true,
    +        approval_request_id: item.id,
    +      }],
    +    });
    +  }
    +}
    +
    +console.log(resp.output_text);
    +
    +
    + + +
    + +
    +

    12. Streaming

    +

    Por padrão a API gera toda a saída antes de devolvê-la. Com stream=true, a Responses API transmite eventos semânticos via Server-Sent Events (SSE), permitindo processar/exibir o início da resposta enquanto ela é gerada. Em produção, lembre que transmitir a saída dificulta a moderação de conteúdo — conclusões parciais são mais difíceis de avaliar; considere isso nas suas políticas de uso aprovado.

    + +

    12.1 Eventos comuns

    +

    Cada evento é tipado. Os principais para streaming de texto:

    +
      +
    • response.created — a resposta começou.
    • +
    • response.output_text.delta — pedaços de texto à medida que são gerados.
    • +
    • response.completed — a resposta terminou.
    • +
    • error — falha durante o streaming.
    • +
    +

    Há ainda eventos para itens (response.output_item.added/done), partes de conteúdo, refusals, function_call_arguments.delta (argumentos de função em tempo real) e eventos específicos de file search / code interpreter.

    +
    +
    + + + +
    +
    +
    stream = client.responses.create(
    +    model="gpt-5.5",
    +    input="Escreva um conto curto sobre lontras no espaço.",
    +    stream=True,
    +)
    +
    +for event in stream:
    +    if event.type == "response.output_text.delta":
    +        print(event.delta, end="", flush=True)
    +    elif event.type == "response.completed":
    +        print("\n[fim]")
    +
    +
    +
    const stream = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Escreva um conto curto sobre lontras no espaço.",
    +  stream: true,
    +});
    +
    +for await (const event of stream) {
    +  if (event.type === "response.output_text.delta") process.stdout.write(event.delta);
    +  else if (event.type === "response.completed") console.log("\n[fim]");
    +}
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "Escreva um conto curto sobre lontras no espaço.",
    +    "stream": true
    +  }'
    +
    +
    + +

    12.2 WebSocket Mode

    +

    A Responses API também suporta um modo WebSocket para fluxos longos e tool-call-heavy: você mantém uma conexão persistente com /v1/responses e continua cada turno enviando só os itens novos mais o previous_response_id, via eventos response.create no mesmo socket. Os campos de transporte stream e background não são usados nesse modo.

    +

    Como a conexão fica aberta e cada turno envia só o incremento, o WebSocket Mode reduz o overhead de continuação e melhora a latência ponta a ponta — em rollouts de 20+ chamadas de ferramenta, ganhos de até ~40%. Uma conexão trata uma resposta por vez (sem multiplexação; paralelismo exige conexões adicionais) e expira em ~60 min; a continuação usa a mesma semântica de previous_response_id, com um cache local da conexão para a resposta mais recente. É compatível com Zero Data Retention e store=false (dados só em memória). As amostras oficiais usam websocket-client em Python e ws em JavaScript.

    + +
    HTTP é o padrão — e o fallback. Se o fluxo é uma requisição, uma resposta, fique no HTTP/SSE: o ganho do WebSocket só aparece em agentes de longa duração com muitas chamadas de ferramenta na mesma cadeia. O modo WebSocket é uma otimização de latência opt-in, não o transporte default da Responses API. No Agents SDK (Python) o mesmo transporte é controlado por set_default_openai_responses_transport("websocket") — ver guia_agents_sdk §8.4.
    + +
    WebSocket Mode não fornece resume de UX. Ele otimiza a conversa backend↔OpenAI dentro de uma conexão — a reconexão após queda/60 min abre novo socket e, sob store=false/ZDR, a cadeia se perde (previous_response_id=null + reenvio do contexto completo ou compactado). O usuário que fechou a aba e voltou é atendido por outra camada: event store durável + replay por cursor no SEU backend — arquitetura completa no guia Streaming Durável & Resumível.
    + + +
    + +
    +

    13. Estado de conversa

    +

    Cada geração é independente e stateless por padrão. Há três formas de manter contexto entre turnos.

    + +

    13.1 Manual

    +

    Inclua o histórico no input com mensagens user/assistant alternadas, ou anexe os itens de output da resposta anterior ao próximo input.

    + +

    13.2 previous_response_id

    +

    Encadeia respostas passando o id da anterior. O estado prévio (incluindo reasoning e contexto de ferramenta) é preservado automaticamente — o jeito mais simples de threading.

    +
    +
    + + + +
    +
    +
    first = client.responses.create(model="gpt-5.5", input="Conte uma piada.")
    +print(first.output_text)
    +
    +second = client.responses.create(
    +    model="gpt-5.5",
    +    previous_response_id=first.id,
    +    input=[{"role": "user", "content": "Explique por que tem graça."}],
    +)
    +print(second.output_text)
    +
    +
    +
    const first = await client.responses.create({ model: "gpt-5.5", input: "Conte uma piada." });
    +console.log(first.output_text);
    +
    +const second = await client.responses.create({
    +  model: "gpt-5.5",
    +  previous_response_id: first.id,
    +  input: [{ role: "user", content: "Explique por que tem graça." }],
    +});
    +console.log(second.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "previous_response_id": "resp_123",
    +    "input": [{ "role": "user", "content": "Explique por que tem graça." }]
    +  }'
    +
    +
    + +

    13.3 Conversations API e compaction

    +

    A Conversations API persiste o estado como um objeto durável (com id próprio) que você reusa entre sessões/dispositivos; passe-o no parâmetro conversation. Itens de uma conversa não têm o TTL de 30 dias das respostas avulsas.

    +

    Para agentes de longa duração, use compaction para reduzir o contexto preservando o estado necessário: deixe o servidor compactar (com previous_response_id + context_management e compact_threshold) ou chame client.responses.compact() e use a saída diretamente no próximo turno. Não edite a saída compactada — ela é estado de máquina, não um resumo humano.

    +
    Nota: mesmo com previous_response_id, todos os tokens de entrada da cadeia são cobrados como input a cada turno. Respostas são guardadas por 30 dias por padrão (desative com store=false).
    + + +
    + +
    +

    14. Background & webhooks

    +

    Tarefas de raciocínio podem levar minutos. O background mode executa de forma assíncrona, sem risco de timeout: faça a requisição com background: true e faça polling do objeto de resposta.

    + +

    14.1 background=true e polling

    +
    +
    + + + +
    +
    +
    from time import sleep
    +
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    input="Escreva um romance longo sobre lontras no espaço.",
    +    background=True,
    +)
    +
    +while resp.status in {"queued", "in_progress"}:
    +    sleep(2)
    +    resp = client.responses.retrieve(resp.id)
    +
    +print(resp.status, resp.output_text)
    +
    +
    +
    let resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Escreva um romance longo sobre lontras no espaço.",
    +  background: true,
    +});
    +
    +while (resp.status === "queued" || resp.status === "in_progress") {
    +  await new Promise((r) => setTimeout(r, 2000));
    +  resp = await client.responses.retrieve(resp.id);
    +}
    +console.log(resp.status, resp.output_text);
    +
    +
    +
    # Inicia em background
    +curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{ "model": "gpt-5.5", "input": "Escreva um romance longo...", "background": true }'
    +
    +# Polling pelo id
    +curl https://api.openai.com/v1/responses/resp_123 \
    +  -H "Authorization: Bearer $OPENAI_API_KEY"
    +
    +# Cancelar (idempotente)
    +curl -X POST https://api.openai.com/v1/responses/resp_123/cancel \
    +  -H "Authorization: Bearer $OPENAI_API_KEY"
    +
    +
    +

    Você pode combinar background com stream: true para começar a receber eventos imediatamente; guarde o sequence_number de cada evento como cursor e, se a conexão cair, retome com ?stream=true&starting_after=<cursor>. Cancelar é idempotente.

    +
    Atenção: background=true requer store=true (requisições stateless são rejeitadas) e não é compatível com Zero Data Retention, pois guarda dados por ~10 minutos para o polling. Você só pode iniciar um stream a partir de uma resposta em background se a criou com stream=true.
    + +

    14.2 Webhooks (assinatura e verificação)

    +

    Webhooks entregam notificações em tempo real de eventos (ex.: response.completed, conclusão de batch ou fine-tuning) a um endpoint HTTP seu, seguindo a especificação Standard Webhooks. Verifique sempre a assinatura: configure o OPENAI_WEBHOOK_SECRET e use client.webhooks.unwrap(...), que lança erro se a assinatura for inválida.

    +
    +
    + + +
    +
    +
    import os
    +from flask import Flask, request, Response
    +from openai import OpenAI, InvalidWebhookSignatureError
    +
    +app = Flask(__name__)
    +client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
    +
    +@app.route("/webhook", methods=["POST"])
    +def webhook():
    +    try:
    +        event = client.webhooks.unwrap(request.data, request.headers)
    +        if event.type == "response.completed":
    +            resp = client.responses.retrieve(event.data.id)
    +            print("Saída:", resp.output_text)
    +        return Response(status=200)
    +    except InvalidWebhookSignatureError as e:
    +        return Response("Assinatura inválida", status=400)
    +
    +
    +
    import OpenAI from "openai";
    +import express from "express";
    +
    +const app = express();
    +const client = new OpenAI({ webhookSecret: process.env.OPENAI_WEBHOOK_SECRET });
    +
    +// Use o corpo cru — a verificação de assinatura precisa do texto original
    +app.use(express.text({ type: "application/json" }));
    +
    +app.post("/webhook", async (req, res) => {
    +  try {
    +    const event = await client.webhooks.unwrap(req.body, req.headers);
    +    if (event.type === "response.completed") {
    +      const resp = await client.responses.retrieve(event.data.id);
    +      console.log("Saída:", resp.output_text);
    +    }
    +    res.status(200).send();
    +  } catch (error) {
    +    if (error instanceof OpenAI.InvalidWebhookSignatureError) {
    +      res.status(400).send("Assinatura inválida");
    +    } else throw error;
    +  }
    +});
    +
    +
    +
    Cuidado: use o corpo cru (raw body) na verificação — em Express, express.text(), não express.json(). Sem isso, a assinatura não confere.
    + + +
    + +
    +

    15. Prompt caching

    +

    O Prompt Caching roteia requisições para servidores que processaram recentemente o mesmo prefixo, reduzindo latência em até ~80% e custo de tokens de entrada em até ~90%. É automático (sem mudança de código, sem custo extra) para prompts de 1024 tokens ou mais, e os hits aparecem em usage.input_tokens_details.cached_tokens na Responses API (ou usage.prompt_tokens_details.cached_tokens em Chat Completions); prompts abaixo de 1024 tokens sempre reportam cached_tokens igual a 0.

    + +

    15.1 Estruturando para cache

    +

    Cache hits exigem prefixo idêntico. Coloque conteúdo estático (instruções, exemplos, schema, tools, imagens) no início do prompt e o conteúdo variável (dados do usuário) no fim. Pode ser cacheado: o array de mensagens completo, imagens (com detail idêntico), o array tools, e o schema de Structured Outputs.

    + +

    15.2 prompt_cache_key e retenção

    +

    Para tráfego repetido com prefixos comuns, use prompt_cache_key de forma consistente: ele é combinado ao hash do prefixo para melhorar o roteamento e a taxa de acerto. Mantenha cada par prefixo+chave abaixo de ~15 requisições por minuto para evitar overflow. Monitore usage.input_tokens_details.cached_tokens na Responses API (em Chat Completions, usage.prompt_tokens_details.cached_tokens). Em GPT-5.6+, o mesmo objeto de detalhes traz cache_write_tokens — a doc oficial recomenda logar os dois (Monitor cache reads and writes by logging cached_tokens and cache_write_tokens); modelos ≤5.5 não reportam esse campo.

    +
    {
    +  "model": "gpt-5.5",
    +  "input": "...",
    +  "prompt_cache_key": "checkout-v3",
    +  "prompt_cache_retention": "24h"
    +}
    +

    O parâmetro prompt_cache_retention aceita in_memory (cache em memória volátil, 5–10 min de inatividade até ~1h) e 24h (retenção estendida, até 24h, descarregando tensores key/value para storage GPU-local). Atual (confirmado no changelog oficial): o padrão é 24h para organizações sem ZDR (Zero Data Retention) em todos os modelos elegíveis de v1/responses, v1/chat/completions e v1/batch — antes, a maioria dos modelos usava in_memory por padrão. Para gpt-5.5, gpt-5.5-pro e modelos futuros, o padrão é 24h e in_memory não é mais suportado (retorna erro de request). Data UNVERIFIED A mudança consta na seção "May 2026" do changelog; o dia exato (citado antes como 2026-05-29) não foi confirmável linha a linha na fonte — o fato em si está confirmado.

    +
    Nota: caches não são compartilhados entre organizações; o caching não altera a saída gerada (só o prefixo é cacheado, a resposta é recalculada) nem isenta tokens dos limites de TPM. Não há limpeza manual de cache.
    + +

    15.3 Caching explícito (família gpt-5.6 e posteriores) 2026-07-09

    +

    A partir de gpt-5.6, o caching ficou mais previsível e controlável. Além do caching implícito (que detecta prefixos automaticamente), você pode marcar breakpoints explícitos no fim de um prefixo reutilizável:

    +
      +
    • prompt_cache_breakpoint: {"mode":"explicit"} em blocos de conteúdo suportados (input_text, input_image, input_file) na Responses API — marca onde termina o prefixo reaproveitável.
    • +
    • prompt_cache_options.mode: implicit (padrão — coloca um breakpoint automático na última mensagem, além dos explícitos que você adicionar) ou explicit (desativa o automático; só os breakpoints explícitos são usados para leitura/escrita de cache).
    • +
    • prompt_cache_options.ttl: define uma vida mínima do cache (piso, não teto). O único valor suportado é "30m" — o prefixo fica reutilizável por ao menos 30 minutos (a OpenAI pode mantê-lo ativo por mais).
    • +
    • prompt_cache_key passa a ser obrigatório para matching confiável (tanto no modo implícito quanto no explícito).
    • +
    • Limites: até 4 escritas de cache por request — no modo implicit, o breakpoint automático da última mensagem consome 1 dos 4 slots (sobram até 3 explícitos); no modo explicit, até 4 explícitos. Breakpoints de turnos anteriores são read-only (dão hit, mas não são re-escritos). A leitura considera os últimos 50 breakpoints da conversa; havendo vários matches, lê-se o prefixo mais longo.
    • +
    • prompt_cache_retention está deprecated para gpt-5.6+ — as semânticas são diferentes: retention (≤5.5) escolhe uma política de retenção máxima; ttl (5.6+) define uma vida mínima. Não misture os dois.
    • +
    +
    Política por workflow (a camada de decisão): chat comum → implicit puro; prefixo grande e estável (sistema+tools+KB) reusado por muitos requests → implicit + 1–3 breakpoints explícitos após os blocos estáveis; pipeline com prefixos controlados e tráfego previsível → mode:"explicit" (só cacheia o que você marcou — sem breakpoint, sem cobrança de write); upload one-shot / prompt que não repete → não marque breakpoint (write de 1,25× sem reuso é só +25% de custo perdido). Breakeven: o write custa 0,25× extra e cada read economiza 0,9× — um único reuso já paga a escrita (derivação na contagem de tokens). Sinais para revisar a política: cache_write_tokens alto com cached_tokens baixo (está pagando write sem colher read) ou hit rate caindo com >15 req/min por prompt_cache_key (particione as keys).
    +
    Mudança de custo: em gpt-5.6+, a escrita de cache passa a custar 1,25× a taxa de input não-cacheado (rastreada no campo cache_write_tokens) — antes as escritas eram gratuitas. A leitura de cache mantém o desconto de 90% (input cacheado = 10% do input padrão). Modelos gpt-5.5 e anteriores usam apenas o caching implícito com prompt_cache_retention e rejeitam prompt_cache_options / prompt_cache_breakpoint se enviados.
    + + +
    + +
    +

    16. Contagem de tokens (texto)

    +

    Tokens são a unidade de medida de entrada e saída. A janela de contexto é o total máximo de tokens por requisição, incluindo input, output e reasoning. Estouros podem truncar a saída — confira a janela na página de cada modelo.

    + +

    16.1 Como contar

    +

    Para texto puro, use o tiktoken ou a ferramenta de tokenizer da plataforma. Para entradas que incluem imagens, arquivos, tools ou conversas, estimativas locais (tipo caracteres / 4) são imprecisas — use o endpoint de contagem de tokens de entrada, que aceita o mesmo payload da Responses API e devolve a contagem exata que o modelo receberá.

    +
    POST /v1/responses/input_tokens
    +# Resposta: { "object": "response.input_tokens", "input_tokens": 1234 }
    +
    +
    + + +
    +
    +
    count = client.responses.input_tokens.count(
    +    model="gpt-5.5",
    +    input=[{"role": "user", "content": "Quantos tokens isto usa?"}],
    +)
    +print(count.input_tokens)
    +
    +
    +
    const count = await client.responses.inputTokens.count({
    +  model: "gpt-5.5",
    +  input: [{ role: "user", content: "Quantos tokens isto usa?" }],
    +});
    +console.log(count.input_tokens);
    +
    +
    + +

    16.2 Otimização e custos

    +

    Após a chamada, o objeto usage reporta o consumo real: input_tokens (com cached_tokens em input_tokens_details), output_tokens (com reasoning_tokens em output_tokens_details) e total_tokens. Os tokens de raciocínio são cobrados como saída. Para controlar custo, limite a geração com max_output_tokens, reduza o número de funções carregadas (ou use tool search) e aproveite o prompt caching.

    +
    Dica: use a contagem prévia de tokens para validar tamanho antes de enviar, estimar custo e rotear por tamanho (prompts menores para modelos mais rápidos como gpt-5.4-mini/gpt-5.4-nano).
    + + +
    + +

    Parte B — Imagem & Visão

    Geração e edição de imagens com gpt-image-2, entrada de imagens (visão) na Responses API e como a tokenização de imagem afeta custos.

    + +
    +

    17. Geração de imagens (gpt-image-2)

    +

    + O modelo de geração de imagens atual e estado da arte é o gpt-image-2 (snapshot fixável + gpt-image-2-2026-04-21): ele entende texto e imagens, usa conhecimento de mundo para criar cenas + realistas e tem forte aderência a instruções. Esse é o ID confirmado na página oficial de modelos e no guia de + geração de imagens. Há dois caminhos para gerar imagens: +

    +
    + + + + + + + + + + + + + + +
    CaminhoQuando usarModelo no campo model
    Image API
    /v1/images/generations
    Gerar/editar uma imagem a partir de um único prompt, sem conversa.gpt-image-2 (modelo de imagem direto)
    Responses API
    tool image_generation
    Experiências conversacionais e multi-turno, com edição iterativa e entrada de imagens por file_id.Um modelo mainline com texto (ex.: gpt-5.5) que chama a tool — o GPT Image roda por baixo.
    +
    + +
    Nota: na Responses API, o valor de model é sempre um modelo de texto (por exemplo gpt-5.5) com a tool image_generation habilitada — gpt-image-2 não é um valor válido em model nesse fluxo. Na Image API, ao contrário, você passa gpt-image-2 diretamente em model.
    + +
    Atenção: antes de usar GPT Image (incluindo gpt-image-2) sua organização pode precisar concluir a API Organization Verification no console de desenvolvedor.
    + +
    Nota — referência de API desatualizada: alguns exemplos na API Reference de /v1/images ainda mostram um ID de modelo de imagem anterior no campo model. Isso é apenas texto de exemplo desatualizado — o ID canônico e recomendado para geração e edição é gpt-image-2.
    + +
    Nota — família de modelos de imagem (2026-06-29): o default e SOTA é gpt-image-2 — use sempre ele em novos projetos. Os demais estão todos depreciados: gpt-image-1-mini, gpt-image-1.5 e chatgpt-image-latest têm sunset em 2026-12-01 (anunciado 2026-06-02); gpt-image-1 tem sunset em 2026-10-23. dall-e-2/dall-e-3 já foram removidos da API (2026-05-12). Em todos os casos migre para gpt-image-2. Fonte: developers.openai.com/api/docs/deprecations.
    + +

    17.1 Gerar e salvar a imagem

    +

    + Os dois caminhos retornam a imagem em base64. Na Image API o conteúdo vem em + result.data[0].b64_json; na Responses API ele aparece no item de saída do tipo + image_generation_call, no campo result. Decodifique o base64 e grave os bytes em disco. +

    + +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +import base64
    +
    +client = OpenAI()
    +
    +# Caminho 1 — Image API (modelo de imagem direto)
    +result = client.images.generate(
    +    model="gpt-image-2",
    +    prompt="Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
    +    size="1024x1024",
    +    quality="high",
    +)
    +image_bytes = base64.b64decode(result.data[0].b64_json)
    +with open("gato_lontra.png", "wb") as f:
    +    f.write(image_bytes)
    +
    +# Caminho 2 — Responses API (tool image_generation; modelo mainline)
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    input="Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
    +    tools=[{"type": "image_generation"}],
    +)
    +image_data = [
    +    out.result
    +    for out in response.output
    +    if out.type == "image_generation_call"
    +]
    +if image_data:
    +    with open("gato_lontra_resp.png", "wb") as f:
    +        f.write(base64.b64decode(image_data[0]))
    +
    +
    +
    import OpenAI from "openai";
    +import fs from "fs";
    +
    +const client = new OpenAI();
    +
    +// Caminho 1 — Image API
    +const result = await client.images.generate({
    +  model: "gpt-image-2",
    +  prompt: "Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
    +  size: "1024x1024",
    +  quality: "high",
    +});
    +fs.writeFileSync("gato_lontra.png", Buffer.from(result.data[0].b64_json, "base64"));
    +
    +// Caminho 2 — Responses API (tool image_generation)
    +const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
    +  tools: [{ type: "image_generation" }],
    +});
    +const imageData = response.output
    +  .filter((o) => o.type === "image_generation_call")
    +  .map((o) => o.result);
    +if (imageData.length > 0) {
    +  fs.writeFileSync("gato_lontra_resp.png", Buffer.from(imageData[0], "base64"));
    +}
    +
    +
    +
    curl -X POST "https://api.openai.com/v1/images/generations" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "gpt-image-2",
    +    "prompt": "Um gato tabby cinza abraçando uma lontra com um cachecol laranja",
    +    "n": 1,
    +    "size": "1024x1024",
    +    "quality": "high"
    +  }' | jq -r '.data[0].b64_json' | base64 --decode > gato_lontra.png
    +
    +
    + +
    Nota: a resposta inclui usage com input_tokens, output_tokens e total_tokens (mais input_tokens_details separando text_tokens de image_tokens). Use esses campos para medir custo real — ver a seção 20.
    + +

    17.2 Parâmetros de saída

    +

    Tanto a Image API quanto a tool da Responses API aceitam as mesmas opções de saída:

    +
    + + + + + + + + + + + + + + +
    ParâmetroValoresDescrição
    promptstringDescrição da imagem desejada.
    size1024x1024, 1536x1024, 1024x1536, 2048x2048, 3840x2160, … ou autoDimensões. O gpt-image-2 aceita resoluções flexíveis dentro das restrições da seção 17.3. auto deixa o modelo escolher.
    qualitylow, medium, high, auto padrão: autolow é o mais rápido (rascunhos, miniaturas); suba para medium/high nos finais.
    backgroundopaque, autoFundo opaco ou automático. O gpt-image-2 não suporta fundo transparente; background: "transparent" falha.
    output_format / formatopng (padrão), jpeg, webpFormato do arquivo de saída. jpeg é mais rápido que png — prefira-o se latência importa.
    output_compression0–100Nível de compressão para jpeg/webp. Ex.: 50 comprime ~50%.
    ninteiroNúmero de imagens por requisição (padrão 1).
    moderationauto (padrão), lowRigor de moderação de conteúdo. low é menos restritivo.
    partial_images0–3Quantas imagens parciais receber em streaming (ver 17.4).
    action toolauto (padrão), generate, editSó na tool da Responses API: força gerar nova imagem ou editar uma já no contexto.
    +
    +
    Dica: na Responses API você força a chamada da tool com tool_choice = {"type": "image_generation"}. As opções de saída acima entram dentro do objeto da tool, ex.: tools=[{"type": "image_generation", "quality": "high", "partial_images": 2}].
    + +

    17.3 Resoluções suportadas e prompt revisado

    +

    O gpt-image-2 aceita milhares de resoluções, desde que respeitem:

    +
    + + + + + + + + +
    Restrição de sizeRegra
    Borda máximaLado mais longo ≤ 3840px
    MúltiploAmbos os lados múltiplos de 16px
    ProporçãoRazão lado longo : lado curto ≤ 3:1
    Pixels totais≥ 655.360 e ≤ 8.294.400
    +
    +

    + Saídas acima de 2560x1440 (~3,69 MP, o "2K") são consideradas experimentais. + Imagens quadradas costumam ser as mais rápidas de gerar. +

    +

    + Ao usar a tool na Responses API, o modelo mainline (ex.: gpt-5.5) reescreve automaticamente seu prompt + para melhorar o resultado. Você lê o texto final em revised_prompt dentro do image_generation_call: +

    +
    {
    +  "id": "ig_123",
    +  "type": "image_generation_call",
    +  "status": "completed",
    +  "revised_prompt": "A gray tabby cat hugging an otter wearing an orange scarf...",
    +  "result": "...base64..."
    +}
    + +

    17.4 Streaming de imagens parciais

    +

    + Para feedback visual mais rápido, ative partial_images (1–3). Com 0 você recebe apenas a imagem final; + com valores maiores você pode receber menos parciais do que pediu, caso a imagem fique pronta antes. +

    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +import base64
    +
    +client = OpenAI()
    +
    +# Image API: evento image_generation.partial_image / b64_json
    +stream = client.images.generate(
    +    model="gpt-image-2",
    +    prompt="Um rio feito de penas brancas de coruja serpenteando por uma paisagem de inverno",
    +    stream=True,
    +    partial_images=2,
    +)
    +for event in stream:
    +    if event.type == "image_generation.partial_image":
    +        idx = event.partial_image_index
    +        with open(f"rio_{idx}.png", "wb") as f:
    +            f.write(base64.b64decode(event.b64_json))
    +
    +# Responses API: evento response.image_generation_call.partial_image / partial_image_b64
    +resp_stream = client.responses.create(
    +    model="gpt-5.5",
    +    input="Desenhe um rio feito de penas brancas de coruja numa paisagem de inverno serena",
    +    stream=True,
    +    tools=[{"type": "image_generation", "partial_images": 2}],
    +)
    +for event in resp_stream:
    +    if event.type == "response.image_generation_call.partial_image":
    +        idx = event.partial_image_index
    +        with open(f"rio_resp_{idx}.png", "wb") as f:
    +            f.write(base64.b64decode(event.partial_image_b64))
    +
    +
    +
    import OpenAI from "openai";
    +import fs from "fs";
    +
    +const client = new OpenAI();
    +
    +// Image API
    +const stream = await client.images.generate({
    +  model: "gpt-image-2",
    +  prompt: "Um rio feito de penas brancas de coruja numa paisagem de inverno",
    +  stream: true,
    +  partial_images: 2,
    +});
    +for await (const event of stream) {
    +  if (event.type === "image_generation.partial_image") {
    +    const idx = event.partial_image_index;
    +    fs.writeFileSync(`rio_${idx}.png`, Buffer.from(event.b64_json, "base64"));
    +  }
    +}
    +
    +// Responses API
    +const respStream = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Desenhe um rio feito de penas brancas de coruja numa paisagem de inverno",
    +  stream: true,
    +  tools: [{ type: "image_generation", partial_images: 2 }],
    +});
    +for await (const event of respStream) {
    +  if (event.type === "response.image_generation_call.partial_image") {
    +    const idx = event.partial_image_index;
    +    fs.writeFileSync(`rio_resp_${idx}.png`, Buffer.from(event.partial_image_b64, "base64"));
    +  }
    +}
    +
    +
    +
    curl -s -N -X POST "https://api.openai.com/v1/images/generations" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "gpt-image-2",
    +    "prompt": "Um rio feito de penas brancas de coruja numa paisagem de inverno",
    +    "size": "1024x1024",
    +    "stream": true,
    +    "partial_images": 2
    +  }'
    +# Eventos SSE: image_generation.partial_image (com b64_json e partial_image_index)
    +# e image_generation.completed (com b64_json final e usage)
    +
    +
    +
    Atenção: cada imagem parcial em streaming custa +100 tokens de imagem de saída. Use partial_images com parcimônia em produção de alto volume.
    + +
    Nota — proveniência: a OpenAI declara, fora da referência de API, que imagens geradas por GPT Image carregam metadados de proveniência no padrão C2PA. A referência de API consultada não documenta esse comportamento, então trate o detalhe como UNVERIFIED e não dependa dele em fluxos críticos sem confirmar na documentação atual.
    + + +
    + +
    +

    18. Edição & inpainting

    +

    + O endpoint de edições (/v1/images/edits) e a tool image_generation na Responses API permitem três coisas: + editar uma imagem existente, gerar uma nova usando outras como referência, e substituir uma região específica via máscara (inpainting). +

    + +

    18.1 Editar e combinar imagens de referência

    +

    + Passe uma ou mais imagens de entrada. Com várias referências, o modelo combina os elementos no resultado. + Na Image API você envia os bytes (multipart/form-data); na Responses API você pode referenciar por + file_id da Files API. +

    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +import base64
    +
    +client = OpenAI()
    +
    +prompt = (
    +    "Gere uma imagem fotorrealista de uma cesta de presentes em fundo branco, "
    +    "rotulada 'Relax & Unwind', contendo todos os itens das imagens de referência."
    +)
    +
    +result = client.images.edit(
    +    model="gpt-image-2",
    +    image=[
    +        open("body-lotion.png", "rb"),
    +        open("bath-bomb.png", "rb"),
    +        open("incense-kit.png", "rb"),
    +        open("soap.png", "rb"),
    +    ],
    +    prompt=prompt,
    +)
    +with open("cesta.png", "wb") as f:
    +    f.write(base64.b64decode(result.data[0].b64_json))
    +
    +
    +
    import fs from "fs";
    +import OpenAI, { toFile } from "openai";
    +
    +const client = new OpenAI();
    +
    +const files = ["bath-bomb.png", "body-lotion.png", "incense-kit.png", "soap.png"];
    +const images = await Promise.all(
    +  files.map((file) => toFile(fs.createReadStream(file), null, { type: "image/png" }))
    +);
    +
    +const response = await client.images.edit({
    +  model: "gpt-image-2",
    +  image: images,
    +  prompt: "Gere uma cesta de presentes fotorrealista em fundo branco com todos os itens das referências.",
    +});
    +fs.writeFileSync("cesta.png", Buffer.from(response.data[0].b64_json, "base64"));
    +
    +
    +
    curl -s -X POST "https://api.openai.com/v1/images/edits" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -F "model=gpt-image-2" \
    +  -F "image[]=@body-lotion.png" \
    +  -F "image[]=@bath-bomb.png" \
    +  -F "image[]=@incense-kit.png" \
    +  -F "image[]=@soap.png" \
    +  -F 'prompt=Gere uma cesta de presentes fotorrealista em fundo branco com todos os itens das referências' \
    +  | jq -r '.data[0].b64_json' | base64 --decode > cesta.png
    +
    +
    +
    Dica: a geração funciona melhor com verbos como desenhe ou edite. Para combinar imagens, em vez de "combine" ou "mescle", peça algo como "edite a primeira imagem adicionando este elemento da segunda imagem".
    + +

    18.2 Inpainting com máscara

    +

    + A máscara indica qual região da imagem deve ser substituída. Na Image API, passe mask junto com image; + na Responses API, use input_image_mask dentro da tool, apontando para o file_id da máscara. + Se você fornecer várias imagens de entrada, a máscara é aplicada à primeira. +

    +
    Nota: o mascaramento no GPT Image é guiado por prompt. O modelo usa a máscara como orientação, mas pode não seguir o contorno exato com precisão absoluta.
    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +import base64
    +
    +client = OpenAI()
    +
    +# Image API: image + mask (mesmo formato/tamanho; máscara com canal alfa)
    +result = client.images.edit(
    +    model="gpt-image-2",
    +    image=open("sunlit_lounge.png", "rb"),
    +    mask=open("mask.png", "rb"),
    +    prompt="Uma sala de estar iluminada pelo sol com uma piscina contendo um flamingo",
    +)
    +with open("lounge.png", "wb") as f:
    +    f.write(base64.b64decode(result.data[0].b64_json))
    +
    +# Responses API: input_image_mask por file_id, dentro da tool
    +file_id = create_file("sunlit_lounge.png")  # purpose="vision"
    +mask_id = create_file("mask.png")
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    input=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "input_text", "text": "Mesma sala iluminada, mas a piscina deve conter um flamingo"},
    +            {"type": "input_image", "file_id": file_id},
    +        ],
    +    }],
    +    tools=[{
    +        "type": "image_generation",
    +        "quality": "high",
    +        "input_image_mask": {"file_id": mask_id},
    +    }],
    +)
    +data = [o.result for o in response.output if o.type == "image_generation_call"]
    +if data:
    +    with open("lounge_resp.png", "wb") as f:
    +        f.write(base64.b64decode(data[0]))
    +
    +
    +
    import fs from "fs";
    +import OpenAI, { toFile } from "openai";
    +
    +const client = new OpenAI();
    +
    +// Image API
    +const rsp = await client.images.edit({
    +  model: "gpt-image-2",
    +  image: await toFile(fs.createReadStream("sunlit_lounge.png"), null, { type: "image/png" }),
    +  mask: await toFile(fs.createReadStream("mask.png"), null, { type: "image/png" }),
    +  prompt: "Uma sala iluminada pelo sol com uma piscina contendo um flamingo",
    +});
    +fs.writeFileSync("lounge.png", Buffer.from(rsp.data[0].b64_json, "base64"));
    +
    +// Responses API com input_image_mask
    +const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: [{
    +    role: "user",
    +    content: [
    +      { type: "input_text", text: "Mesma sala iluminada, mas a piscina deve conter um flamingo" },
    +      { type: "input_image", file_id: fileId },
    +    ],
    +  }],
    +  tools: [{ type: "image_generation", quality: "high", input_image_mask: { file_id: maskId } }],
    +});
    +
    +
    +
    curl -s -X POST "https://api.openai.com/v1/images/edits" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -F "model=gpt-image-2" \
    +  -F "image[]=@sunlit_lounge.png" \
    +  -F "mask=@mask.png" \
    +  -F 'prompt=Uma sala iluminada pelo sol com uma piscina contendo um flamingo' \
    +  | jq -r '.data[0].b64_json' | base64 --decode > lounge.png
    +
    +
    + +

    Requisitos da máscara

    +
      +
    • A imagem a editar e a máscara devem ter o mesmo formato e tamanho (cada uma com menos de 50 MB).
    • +
    • A máscara precisa ter um canal alfa — a transparência define a área a substituir. Salve a máscara preservando o alfa.
    • +
    • É possível converter uma máscara preto e branco em RGBA por código, usando a própria máscara para preencher o canal alfa:
    • +
    +
    from PIL import Image
    +from io import BytesIO
    +
    +mask = Image.open("mask_pb.png").convert("L")   # 1. carrega como tons de cinza
    +mask_rgba = mask.convert("RGBA")                  # 2. espaço para canal alfa
    +mask_rgba.putalpha(mask)                          # 3. usa a própria máscara como alfa
    +
    +buf = BytesIO()
    +mask_rgba.save(buf, format="PNG")                 # 4. serializa em PNG
    +with open("mask_alpha.png", "wb") as f:           # 5. salva
    +    f.write(buf.getvalue())
    + +

    18.3 input_fidelity e edição multi-turno

    +

    + O parâmetro input_fidelity controla quão fortemente o modelo preserva os detalhes das imagens de entrada + durante edições e fluxos com referência. Para gpt-image-2, omita esse parâmetro: a API não + permite alterá-lo porque o modelo já processa toda imagem de entrada em alta fidelidade automaticamente. +

    +
    Atenção: como o gpt-image-2 sempre trata entradas em alta fidelidade, requisições de edição que incluem imagens de referência podem consumir mais tokens de imagem de entrada. Considere isso no custo (seção 20).
    +

    + Na Responses API a edição é naturalmente multi-turno: você continua a conversa referenciando o + previous_response_id ou reinjetando o item image_generation_call (pelo id) num turno seguinte. + Use action: "edit" para forçar edição de uma imagem já no contexto (forçar edit sem imagem em contexto retorna erro); + action: "generate" força criar uma nova; auto deixa o modelo decidir. +

    +
    from openai import OpenAI
    +client = OpenAI()
    +
    +# Turno 1 — gera
    +r1 = client.responses.create(
    +    model="gpt-5.5",
    +    input="Gere um gato tabby cinza abraçando uma lontra com cachecol laranja",
    +    tools=[{"type": "image_generation"}],
    +)
    +
    +# Turno 2 — refina referenciando o turno anterior
    +r2 = client.responses.create(
    +    model="gpt-5.5",
    +    previous_response_id=r1.id,
    +    input="Agora deixe a imagem realista",
    +    tools=[{"type": "image_generation"}],
    +)
    + + +
    + +
    +

    19. Visão (entrada de imagens)

    +

    + Visão é a capacidade do modelo de "enxergar" e entender imagens — objetos, formas, cores, texturas e até + texto contido nelas. Na Responses API você envia imagens como conteúdo do tipo input_image, ao lado de + input_text, dentro de uma mensagem de usuário. +

    + +

    19.1 Três formas de passar a imagem

    +
    + + + + + + + +
    FormaCampo em input_imageQuando usar
    URL públicaimage_url (URL http(s))Imagem já hospedada e acessível publicamente.
    Base64 (data URL)image_url com data:image/jpeg;base64,...Imagem local, sem upload prévio; embute os bytes na requisição.
    File IDfile_idImagem enviada à Files API (purpose="vision"), reutilizável entre chamadas.
    +
    +

    Você pode passar várias imagens na mesma requisição, incluindo múltiplos itens input_image no array content — lembrando que cada imagem conta como tokens (seção 20).

    + +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +import base64
    +
    +client = OpenAI()
    +
    +def encode_image(path):
    +    with open(path, "rb") as f:
    +        return base64.b64encode(f.read()).decode("utf-8")
    +
    +b64 = encode_image("foto.jpg")
    +
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    input=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "input_text", "text": "O que há nestas imagens? Compare-as."},
    +            # 1) por URL pública
    +            {"type": "input_image",
    +             "image_url": "https://exemplo.com/imagem.jpg",
    +             "detail": "high"},
    +            # 2) por base64 (data URL)
    +            {"type": "input_image",
    +             "image_url": f"data:image/jpeg;base64,{b64}"},
    +            # 3) por file_id (Files API, purpose="vision")
    +            {"type": "input_image", "file_id": "file-abc123", "detail": "auto"},
    +        ],
    +    }],
    +)
    +print(response.output_text)
    +
    +
    +
    import fs from "fs";
    +import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +const b64 = fs.readFileSync("foto.jpg", "base64");
    +
    +const response = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: [{
    +    role: "user",
    +    content: [
    +      { type: "input_text", text: "O que há nestas imagens? Compare-as." },
    +      { type: "input_image", image_url: "https://exemplo.com/imagem.jpg", detail: "high" },
    +      { type: "input_image", image_url: `data:image/jpeg;base64,${b64}` },
    +      { type: "input_image", file_id: "file-abc123", detail: "auto" },
    +    ],
    +  }],
    +});
    +console.log(response.output_text);
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": [
    +      {
    +        "role": "user",
    +        "content": [
    +          {"type": "input_text", "text": "O que há nesta imagem?"},
    +          {
    +            "type": "input_image",
    +            "image_url": "https://exemplo.com/imagem.jpg",
    +            "detail": "high"
    +          }
    +        ]
    +      }
    +    ]
    +  }'
    +
    +
    +
    Dica: para subir a imagem à Files API antes de usar por file_id, crie o arquivo com client.files.create(file=open("foto.jpg","rb"), purpose="vision") e use o id retornado.
    + +

    19.2 Nível de detalhe (detail)

    +

    + O parâmetro detail diz ao modelo o nível de detalhe ao processar a imagem. Vale tanto na Responses API quanto na Chat Completions. + Se omitido, o padrão é auto. No gpt-5.5, auto e o comportamento padrão omitido equivalem a original. +

    +
    + + + + + + + + +
    NívelMelhor para
    lowEntendimento rápido e barato quando o detalhe fino não importa. O modelo recebe uma versão de 512px × 512px.
    highCompreensão de alta fidelidade padrão.
    originalImagens grandes, densas, espacialmente sensíveis ou de uso de computador. Disponível em gpt-5.4 e modelos futuros.
    autoSeleção automática. No gpt-5.5, equivale a original.
    +
    +

    Para uso de computador, localização e precisão de clique nos modelos gpt-5.4 e futuros, recomenda-se "detail": "original".

    + +
    Dica — detail ≠ raciocínio: detail resolve percepção (deixar a imagem legível). Depois que a imagem está legível, o gargalo costuma ser raciocínio, não percepção — jogar detail: "original" numa falha de raciocínio não ajuda. Para gráficos, tabelas, plantas e leitura composicional, aumente reasoning.effort (ex.: reasoning={"effort": "high"}) em vez de só subir o detail.
    + +

    19.3 Requisitos da imagem e comportamento de redimensionamento

    +
    + + + + + + + + +
    RequisitoValor
    Formatos suportadosPNG (.png), JPEG (.jpeg/.jpg), WEBP (.webp), GIF não animado (.gif)
    Tamanho do payloadAté 512 MB de payload total por requisição
    QuantidadeAté 1.500 imagens individuais por requisição
    OutrosSem marcas d'água/logos, sem conteúdo NSFW, nítida o bastante para um humano entender
    +
    +

    + Modelos diferentes redimensionam antes de tokenizar. Em gpt-5.5 e gpt-5.4: high permite até + 2.500 patches ou dimensão máxima de 2048px; original permite até 10.000 patches ou 6000px. + Se algum limite é excedido, a imagem é reduzida preservando a proporção até caber. Em gpt-5.4-mini e gpt-5.4-nano, + high permite até 1.536 patches ou 2048px (sem original). Detalhes da matemática na seção 20. +

    +
    Nota — limitações conhecidas de visão: imagens médicas especializadas (ex.: tomografias) não são adequadas; texto em alfabetos não latinos pode ter desempenho menor; texto pequeno deve ser ampliado (e "detail": "original" ajuda); imagens rotacionadas, panorâmicas ou olho-de-peixe confundem o modelo; contagens podem ser aproximadas; metadados e nomes de arquivo não são processados; e CAPTCHAs são bloqueados por segurança.
    + +

    19.4 Entradas de arquivo (input_file): PDF, documentos e planilhas

    +

    Além de imagens, a Responses API aceita arquivos como itens de conteúdo do tipo input_file — passados de três formas: URL externa (file_url), ID da Files API (file_id, após upload com purpose="user_data") ou base64 (file_data + filename). É o caminho para Q&A direto sobre um documento, sem montar um pipeline de RAG.

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +client = OpenAI()
    +
    +# (a) Arquivo por URL externa — sem upload
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    input=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "input_text", "text": "Resuma os pontos-chave deste relatório."},
    +            {"type": "input_file", "file_url": "https://exemplo.com/relatorio.pdf"},
    +        ],
    +    }],
    +)
    +print(resp.output_text)
    +
    +# (b) Upload pela Files API e referência por file_id
    +f = client.files.create(file=open("contrato.pdf", "rb"), purpose="user_data")
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    input=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "input_file", "file_id": f.id},
    +            {"type": "input_text", "text": "Quais são as cláusulas de rescisão?"},
    +        ],
    +    }],
    +)
    +print(resp.output_text)
    +
    +
    +
    import OpenAI from "openai";
    +import fs from "fs";
    +const client = new OpenAI();
    +
    +// (a) Arquivo por URL externa — sem upload
    +let resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: [{
    +    role: "user",
    +    content: [
    +      { type: "input_text", text: "Resuma os pontos-chave deste relatório." },
    +      { type: "input_file", file_url: "https://exemplo.com/relatorio.pdf" },
    +    ],
    +  }],
    +});
    +console.log(resp.output_text);
    +
    +// (b) Upload pela Files API e referência por file_id
    +const f = await client.files.create({
    +  file: fs.createReadStream("contrato.pdf"),
    +  purpose: "user_data",
    +});
    +resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: [{
    +    role: "user",
    +    content: [
    +      { type: "input_file", file_id: f.id },
    +      { type: "input_text", text: "Quais são as cláusulas de rescisão?" },
    +    ],
    +  }],
    +});
    +console.log(resp.output_text);
    +
    +
    +
    Como cada tipo é processado: PDF — o modelo recebe o texto extraído e uma imagem de cada página (importa para layout/diagramas), então PDFs consomem mais tokens; documentos de texto (.txt/.md/.docx/.pptx/.html) — só o texto; planilhas (.csv/.xlsx) — augmentação específica que lê as primeiras 1.000 linhas. Para arquivos grandes ou muitos documentos, prefira File Search (RAG) em vez de despejar tudo como input_file.
    + + +
    + +
    +

    20. Tokenização & custos de imagem

    +

    + Imagens de entrada são medidas e cobradas em tokens, como o texto, e contam para o limite de tokens por minuto (TPM). + A forma de converter pixels em tokens depende da geração do modelo: os modelos gpt-5.x atuais usam o método + patch-based (por blocos de 32px); as gerações anteriores usavam o + método tile-based. Apresentamos o patch como principal e o tile apenas como nota de cálculo/migração. +

    + +

    20.1 Patch-based (método atual)

    +

    + O modelo cobre a imagem com patches de 32px × 32px e define um orçamento máximo de patches. O custo em tokens segue 4 passos: +

    +

    A. Conte quantos patches de 32px cobrem a imagem original (um patch pode ultrapassar a borda):

    +
    original_patch_count = ceil(width / 32) * ceil(height / 32)
    +

    B. Se exceder o orçamento de patches do modelo, reduza proporcionalmente até caber, ajustando a escala para que as dimensões inteiras finais permaneçam dentro do orçamento:

    +
    shrink_factor = sqrt((32**2 * patch_budget) / (width * height))
    +adjusted_shrink_factor = shrink_factor * min(
    +    floor(width  * shrink_factor / 32) / (width  * shrink_factor / 32),
    +    floor(height * shrink_factor / 32) / (height * shrink_factor / 32),
    +)
    +

    C. Converta a escala ajustada em pixels inteiros e reconte os patches. Esse é o número de tokens de imagem antes do multiplicador, limitado pelo orçamento:

    +
    resized_patch_count = ceil(resized_width / 32) * ceil(resized_height / 32)
    +

    D. Aplique o multiplicador do modelo para obter os tokens finais:

    +
    + + + + + + +
    ModeloMultiplicador
    gpt-5.4-mini1.62
    gpt-5.4-nano2.46
    +
    +
    Nota — gpt-5.5: o gpt-5.5 (frontier) não aparece na tabela de multiplicadores acima, o que significa multiplicador efetivo de ×1,0 — a contagem de patches já é a contagem de tokens de imagem. Seu orçamento de patches por nível de detalhe é maior: high = 2.500 patches (ou 2048px); original = 10.000 patches (ou 6000px); auto e o detalhe omitido equivalem a original. Para gpt-5.4-mini/gpt-5.4-nano, high = 1.536 patches.
    + +

    Exemplo (orçamento de 1.536 patches)

    +
      +
    • Imagem 1024 × 1024: ceil(1024/32) × ceil(1024/32) = 32 × 32 = 1024 patches. Está abaixo de 1.536, então não há redimensionamento. Tokens antes do multiplicador = 1024.
    • +
    • Imagem 1800 × 2400: original = 57 × 75 = 4275 patches (excede 1.536). shrink_factor ≈ 0,603 → adjusted ≈ 0,586 → redimensiona para 1056 × 1408 → 33 × 44 = 1452 patches. Tokens antes do multiplicador = 1452.
    • +
    +

    Em ambos, multiplique o resultado pelo fator do modelo (tabela acima) para obter as unidades de token cobradas.

    + +

    20.2 Tile-based (legado)

    +

    + Nas gerações anteriores ao gpt-5.x, o custo dependia de tamanho e detail — nenhum modelo SOTA atual + usa este método, mantido aqui apenas como referência de migração. + Com detail: "low" o custo era um número-base fixo de tokens. Com detail: "high": +

    +
      +
    1. Escala para caber num quadrado de 2048px × 2048px, mantendo a proporção.
    2. +
    3. Escala para que o menor lado fique com 768px.
    4. +
    5. Conta os quadrados de 512px; cada quadrado custava um valor fixo de tokens.
    6. +
    7. Soma os tokens-base ao total: tokens = base + (tokens_por_tile × nº de tiles).
    8. +
    +
    Nota: os valores de tokens-base e tokens por tile variavam por geração de modelo legado e não se aplicam a nenhum modelo atual. O método patch-based dos modelos gpt-5.x substitui inteiramente essa contagem por tiles; consulte a calculadora oficial para qualquer integração ativa.
    + +

    20.3 Custo de saída do gpt-image-2

    +

    + Para o gpt-image-2, o custo de saída depende de quality e size. Como ele aceita milhares de + resoluções, o caminho recomendado é estimar os tokens de saída pela calculadora oficial (a partir de + quality + size); a tabela abaixo lista os tamanhos clássicos confirmados, para comparação. O custo total de + uma requisição é a soma de: tokens de texto de entrada + tokens de imagem de entrada (se editando referências) + + tokens de imagem de saída. +

    +
    + + + + + + + +
    Qualidade1024×10241024×15361536×1024
    LowUS$ 0,006US$ 0,005US$ 0,005
    MediumUS$ 0,053US$ 0,041US$ 0,041
    HighUS$ 0,211US$ 0,165US$ 0,165
    +
    +
    Dica: uma resolução não quadrada maior às vezes gera menos tokens de saída do que uma menor/quadrada na mesma qualidade. E cada imagem parcial em streaming adiciona +100 tokens de saída.
    +
    Atenção — entradas em edição: como o gpt-image-2 processa toda imagem de entrada em alta fidelidade, edições com referências consomem mais tokens de imagem de entrada. Inclua isso ao estimar o custo. Preços são perecíveis — confirme sempre na calculadora e na página de preços oficiais.
    + +

    20.4 Receitas e exemplos oficiais (Cookbook)

    +

    + O OpenAI Cookbook traz receitas práticas de imagem e visão. Use as marcadas como atual como + referência: elas já usam gpt-image-2 para geração/edição e visão gpt-5.x pela Responses API. + Algumas receitas mais antigas continuam no ar com stack legado (modelos de imagem anteriores, + visão por Chat Completions); para essas, prefira o equivalente moderno indicado. +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ReceitaO que ensinaStatus
    GPT Image Models Prompting GuidePrompting de geração e edição com gpt-image-2 (estrutura cena→sujeito→detalhes→constraints, texto na imagem, multi-imagem por índice, iteração).atual
    Document & Multimodal Understanding TipsVisão de documentos com gpt-5.4 na Responses API: detail="original", reasoning.effort, bounding boxes em grade 0–999, code_interpreter para crop/zoom.atual
    Grounded Spatial Reasoning & LayoutsRaciocínio espacial com gpt-5.5 + render gpt-image-2: separar semântica (modelo) de geometria (validação determinística); saída como spec JSON.atual
    Image EvalsAvaliar imagem geradas com padrão Gate → Grade → Tag e juiz multimodal gpt-5.x via Responses API (gates hard pass/fail antes de pontuar; nunca usar média para contornar um gate).atual
    Image Gen 1.5 Prompting GuidePrompting de geração em um modelo de imagem anterior. Equivalente moderno: trocar por gpt-image-2 e remover input_fidelity (no gpt-image-2 é automático).legado
    GPT-4 Vision with Function CallingVisão + tool calling via Chat Completions e biblioteca externa. Equivalente moderno: Responses API com input_image nativo + tools de função + Structured Outputs, em modelo gpt-5.x.legado
    Vision RAG com PineconeRAG sobre PDF com visão via Chat Completions. Equivalente moderno: Responses API com input_image/Files API nativo e visão gpt-5.x.legado
    Custom Image Embedding SearchBusca por similaridade com embedding de imagem local + QA por um modelo de visão anterior. Equivalente moderno: visão gpt-5.x pela Responses API; não tratar como padrão atual.legado
    +
    +
    Dica — padrão de edição que evita "drift": ao editar, descreva exatamente o que muda e o que permanece: "mude APENAS X; mantenha todo o resto exatamente igual" (rosto, pose, fundo, proporções). Repita a lista de preservação a cada iteração — isso reduz o desvio acumulado em edições multi-turno.
    + +

    + A seguir, três receitas mínimas em Python e JavaScript, fiéis aos exemplos oficiais da documentação: + geração de imagem, edição com máscara (inpainting) e visão. Todas usam gpt-image-2 para imagem e a Responses API + com input_image para visão — sem stacks legados e sem parâmetros inventados (no gpt-image-2, + input_fidelity é automático e não deve ser enviado). +

    + +

    Receita 1 — Geração de imagem com gpt-image-2 · via tool image_generation (Responses API) ou images.generate · image-generation#generate-images

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +import base64
    +
    +client = OpenAI()
    +
    +# Caminho A — Responses API: tool image_generation no modelo mainline
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    input="Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
    +    tools=[{"type": "image_generation"}],
    +)
    +
    +# Coleta os resultados das chamadas de geração de imagem
    +image_data = [
    +    output.result
    +    for output in response.output
    +    if output.type == "image_generation_call"
    +]
    +
    +if image_data:
    +    image_base64 = image_data[0]
    +    with open("lontra.png", "wb") as f:
    +        f.write(base64.b64decode(image_base64))
    +
    +# Caminho B — Image API: modelo de imagem direto (retorna b64_json)
    +result = client.images.generate(
    +    model="gpt-image-2",
    +    prompt="Desenho de livro infantil: um veterinario auscultando uma lontra bebe",
    +)
    +image_bytes = base64.b64decode(result.data[0].b64_json)
    +with open("lontra_direto.png", "wb") as f:
    +    f.write(image_bytes)
    +
    +
    +
    +
    import OpenAI from "openai";
    +import fs from "fs";
    +
    +const openai = new OpenAI();
    +
    +// Caminho A — Responses API: tool image_generation no modelo mainline
    +const response = await openai.responses.create({
    +  model: "gpt-5.5",
    +  input: "Gere uma imagem de um gato tabby cinza abraçando uma lontra com cachecol laranja",
    +  tools: [{ type: "image_generation" }],
    +});
    +
    +// Coleta os resultados das chamadas de geração de imagem
    +const imageData = response.output
    +  .filter((output) => output.type === "image_generation_call")
    +  .map((output) => output.result);
    +
    +if (imageData.length > 0) {
    +  const imageBase64 = imageData[0];
    +  fs.writeFileSync("lontra.png", Buffer.from(imageBase64, "base64"));
    +}
    +
    +// Caminho B — Image API: modelo de imagem direto (retorna b64_json)
    +const result = await openai.images.generate({
    +  model: "gpt-image-2",
    +  prompt: "Desenho de livro infantil: um veterinario auscultando uma lontra bebe",
    +});
    +const imageBytes = Buffer.from(result.data[0].b64_json, "base64");
    +fs.writeFileSync("lontra_direto.png", imageBytes);
    +
    +
    +
    + +

    Receita 2 — Edição / inpainting com gpt-image-2 · images.edit com imagem + máscara (a máscara precisa de canal alfa) · image-generation#edit-images

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +import base64
    +
    +client = OpenAI()
    +
    +# A máscara marca a área a substituir; imagem e máscara devem ter
    +# o mesmo formato e tamanho, e a máscara precisa de canal alfa.
    +result = client.images.edit(
    +    model="gpt-image-2",
    +    image=open("sunlit_lounge.png", "rb"),
    +    mask=open("mask.png", "rb"),
    +    prompt="Uma sala de estar ensolarada com uma piscina contendo um flamingo",
    +)
    +
    +image_bytes = base64.b64decode(result.data[0].b64_json)
    +with open("lounge_editado.png", "wb") as f:
    +    f.write(image_bytes)
    +
    +
    +
    +
    import fs from "fs";
    +import OpenAI, { toFile } from "openai";
    +
    +const client = new OpenAI();
    +
    +// A máscara marca a área a substituir; imagem e máscara devem ter
    +// o mesmo formato e tamanho, e a máscara precisa de canal alfa.
    +const rsp = await client.images.edit({
    +  model: "gpt-image-2",
    +  image: await toFile(fs.createReadStream("sunlit_lounge.png"), null, {
    +    type: "image/png",
    +  }),
    +  mask: await toFile(fs.createReadStream("mask.png"), null, {
    +    type: "image/png",
    +  }),
    +  prompt: "Uma sala de estar ensolarada com uma piscina contendo um flamingo",
    +});
    +
    +const imageBytes = Buffer.from(rsp.data[0].b64_json, "base64");
    +fs.writeFileSync("lounge_editado.png", imageBytes);
    +
    +
    +
    + +

    Receita 3 — Visão: analisar uma imagem com gpt-5.5 · Responses API com input_image (URL ou base64) · images-vision#analyze-images

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +import base64
    +
    +client = OpenAI()
    +
    +# Opção 1 — imagem por URL pública
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    input=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "input_text", "text": "O que há nesta imagem?"},
    +            {
    +                "type": "input_image",
    +                "image_url": "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
    +            },
    +        ],
    +    }],
    +)
    +print(response.output_text)
    +
    +# Opção 2 — imagem local em base64 (data URL)
    +def encode_image(path):
    +    with open(path, "rb") as f:
    +        return base64.b64encode(f.read()).decode("utf-8")
    +
    +base64_image = encode_image("foto.jpg")
    +response = client.responses.create(
    +    model="gpt-5.5",
    +    input=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "input_text", "text": "Descreva esta imagem."},
    +            {
    +                "type": "input_image",
    +                "image_url": f"data:image/jpeg;base64,{base64_image}",
    +            },
    +        ],
    +    }],
    +)
    +print(response.output_text)
    +
    +
    +
    +
    import fs from "fs";
    +import OpenAI from "openai";
    +
    +const openai = new OpenAI();
    +
    +// Opção 1 — imagem por URL pública
    +const response = await openai.responses.create({
    +  model: "gpt-5.5",
    +  input: [{
    +    role: "user",
    +    content: [
    +      { type: "input_text", text: "O que há nesta imagem?" },
    +      {
    +        type: "input_image",
    +        image_url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
    +      },
    +    ],
    +  }],
    +});
    +console.log(response.output_text);
    +
    +// Opção 2 — imagem local em base64 (data URL)
    +const base64Image = fs.readFileSync("foto.jpg", "base64");
    +const response2 = await openai.responses.create({
    +  model: "gpt-5.5",
    +  input: [{
    +    role: "user",
    +    content: [
    +      { type: "input_text", text: "Descreva esta imagem." },
    +      {
    +        type: "input_image",
    +        image_url: `data:image/jpeg;base64,${base64Image}`,
    +      },
    +    ],
    +  }],
    +});
    +console.log(response2.output_text);
    +
    +
    +
    + + +
    + +

    Parte C — Áudio & Realtime

    Fala em tempo real (gpt-realtime-2.1), tradução e transcrição ao vivo, transcrição de arquivos (gpt-4o-transcribe), síntese de voz (gpt-4o-mini-tts) e áudio no chat (gpt-audio-1.5).

    + +
    +

    21. Visão geral de áudio

    +

    Os modelos de áudio da OpenAI sabem entender fala, gerar fala ou fazer as duas coisas na mesma interação. Antes de escrever código, vale fixar o vocabulário comum e, principalmente, decidir entre duas grandes arquiteturas: APIs baseadas em requisição (você envia um arquivo ou um texto e recebe uma resposta delimitada) e sessões em tempo real (uma conexão aberta por onde fluem áudio e eventos com baixa latência). Essa escolha define endpoint, transporte, modelo e complexidade do cliente.

    + +

    21.1 Modalidades de áudio

    +

    Uma aplicação de áudio combina uma ou mais destas modalidades. Pense nelas como "peças" que você liga ou desliga conforme a tarefa.

    +
    + + + + + + + + +
    ModalidadeO que éUsos comuns
    Entrada de áudioO modelo recebe som do usuário ou da aplicação.Agentes de voz, transcrição, tradução.
    Saída de áudioO modelo ou a API devolve áudio falado.Agentes de voz, text-to-speech, respostas faladas.
    Transcrição em textoA fala vira texto.Legendas, análise de chamadas, busca, registros.
    Prompt de textoTexto controla o que o modelo diz ou faz.Geração de fala, fluxos de voz roteirizados, prompts.
    +
    + +

    21.2 Tarefas comuns de fala

    +
      +
    • Speech-to-text (STT) — converte fala em texto. Para legendas, notas, transcrições, analytics, busca e acessibilidade. Pode ser baseada em requisição (arquivos) ou em streaming (áudio ao vivo).
    • +
    • Text-to-speech (TTS) — converte texto em áudio falado. Para narração, assistentes, acessibilidade e respostas geradas. A geração pode transmitir o áudio em streaming à medida que é produzido.
    • +
    • Speech-to-speech (S2S) — um único modelo escuta, raciocina e fala em uma sessão de baixa latência. Para agentes de voz conversacionais que respondem, chamam tools e mantêm estado de sessão.
    • +
    • Tradução de fala — escuta fala em um idioma e devolve áudio/transcrição traduzidos em outro idioma. Use uma sessão de tradução em tempo real quando a tradução deve começar continuamente conforme o áudio chega.
    • +
    + +

    21.3 Streaming e latência

    +

    Streaming significa que cliente e serviço trocam entrada ou saída parcial enquanto a interação ainda está ativa — essencial quando o usuário espera feedback imediato (legendas ao vivo, chamadas, agentes de voz, tradução). Latência mais baixa exige uma conexão em tempo real, manejo cuidadoso de mídia e um modelo de sessão capaz de emitir eventos parciais. As APIs baseadas em requisição são mais simples para upload de arquivos e trabalho não interativo, mas não suportam os mesmos padrões de interação ao vivo.

    + +

    21.4 APIs baseadas em requisição vs. sessões realtime

    +

    A OpenAI oferece três arquiteturas de áudio. Comece pelo resultado desejado e deixe ele escolher a arquitetura:

    +
    + + + + + + + +
    ArquiteturaUse quandoExemplos / endpoints
    APIs de áudio por requisiçãoVocê tem um arquivo, um texto ou uma requisição delimitada.Speech-to-text (/v1/audio/transcriptions), text-to-speech (/v1/audio/speech).
    Sessões em tempo realO áudio é ao vivo e o app precisa de eventos de baixa latência.Agentes de voz, tradução, transcrição — sobre /v1/realtime e endpoints irmãos.
    Chat multimodalVocê está estendendo um fluxo de chat existente com áudio.Entrada/saída de áudio em Chat Completions com gpt-audio-1.5.
    +
    + +

    21.5 Escolha de modelo por tarefa

    +

    Cada tarefa de áudio tem um modelo recomendado. Esta tabela é o mapa de toda a Parte C — as seções seguintes detalham cada linha.

    +
    + + + + + + + + + + + +
    ObjetivoModeloOnde detalhar
    Agente de voz de baixa latência (fala↔fala)gpt-realtime-2.1 realtimeSeções 22 e 28
    Traduzir fala ao vivo para outro idiomagpt-realtime-translateSeção 23
    Transcrever áudio ao vivo em texto contínuogpt-realtime-whisperSeção 24
    Transcrever arquivos / requisições delimitadasgpt-4o-transcribe, gpt-4o-mini-transcribe, gpt-4o-transcribe-diarizeSeção 25
    Tradução de áudio→inglês e timestamps/word-levelwhisper-1Seção 25
    Gerar fala a partir de textogpt-4o-mini-ttsSeção 26
    Adicionar áudio a um app de Chat Completionsgpt-audio-1.5Seção 27
    +
    +
    Nota: gpt-realtime-2.1 e gpt-audio-1.5 são nativamente multimodais — entendem e geram áudio e texto como entrada e saída. A diferença prática é o transporte: gpt-realtime-2.1 vive em uma sessão de streaming bidirecional; gpt-audio-1.5 responde a uma requisição de chat delimitada.
    + + +
    + +
    +

    22. Realtime API (gpt-realtime-2.1)

    +

    A Realtime API mantém uma conexão aberta enquanto sua aplicação envia áudio, recebe eventos e atualiza o estado da sessão. O modelo principal atual é o gpt-realtime-2.1 (jul/2026), que atualiza o gpt-realtime-2 — modelo anterior distinto — com melhor reconhecimento alfanumérico, tratamento de silêncio/ruído e comportamento de interrupção, mantendo fala↔fala com reasoning effort configurável, obediência a instruções e uso de tools para fluxos de agente complexos. Há também o gpt-realtime-2.1-mini, versão destilada mais rápida e barata. Para um modelo fala↔fala rápido e sem reasoning, há o gpt-realtime-1.5 (speech-to-speech rápido e confiável, sem reasoning; tem guia de prompting dedicado na doc oficial). O SDK Agents (Python e TS) já usa gpt-realtime-2.1 como default do RealtimeAgent.

    + +
    Dica: em produção, comece com reasoning.effort: "low" na maioria dos agentes de voz e suba só se a tarefa exigir — reasoning maior aumenta latência e tokens de saída.
    + +

    22.1 Tipos de sessão realtime

    +

    Uma sessão em tempo real é uma interação stateful. Existem três tipos, cada um com um propósito distinto:

    +
    + + + + + + + +
    Tipo de sessãoUse quandoEndpoint / padrão
    Sessão de agente de vozO modelo deve responder ao usuário, chamar tools e gerenciar o estado da conversa.Sessão de conversa em /v1/realtime
    Sessão de traduçãoO app deve traduzir fala continuamente conforme chega.Sessão contínua em /v1/realtime/translations (Seção 23)
    Sessão de transcriçãoO app precisa de deltas de transcrição sem resposta falada do modelo.Sessão type: "transcription" (Seção 24)
    +
    +

    Esta seção foca na sessão de agente de voz (fala↔fala). Os componentes do estado são: o objeto Session (modelo, voz, configuração), a Conversation (itens de entrada do usuário e de saída do modelo) e as Responses (itens de áudio/texto gerados que entram na conversa). A duração máxima de uma sessão Realtime é de 60 minutos.

    + +

    22.2 Transportes: WebRTC, WebSocket e SIP

    +

    Escolha o transporte pelo lugar onde sua aplicação captura e toca o áudio:

    +
    + + + + + + + +
    TransporteUse quandoCaracterística
    WebRTCCliente em navegador/mobile captura ou toca áudio diretamente.Mais robusto sob redes incertas; o WebRTC cuida da mídia (microfone via getUserMedia, saída via track remota).
    WebSocketSeu servidor já recebe áudio cru de um pipeline de mídia, sistema de chamadas ou worker.Interface de mais baixo nível: você envia e recebe chunks Base64 de áudio manualmente sobre o socket.
    SIPAgentes de voz por telefonia (PSTN via SIP trunking, ex.: Twilio).Webhook realtime.call.incoming → você aceita/rejeita a chamada e monitora via WebSocket. Confirme suporte do modelo antes de usar SIP para tradução/transcrição.
    +
    +
    Atenção: ao conectar de um cliente (navegador ou mobile), prefira WebRTC a WebSocket — desempenho mais consistente. Use WebSocket para integração servidor↔servidor, onde a chave de API fica segura no backend.
    + +

    22.2.1 WebRTC: interface unificada e token efêmero

    +

    Há dois mecanismos para conectar do navegador via WebRTC: a interface unificada (seu servidor encaminha o SDP e fica no caminho crítico da inicialização) ou tokens efêmeros (seu servidor emite um client secret de curta duração e o navegador conecta direto). Em ambos, a chave de API padrão só existe no servidor. A negociação WebRTC é feita contra POST /v1/realtime/calls (SDP), e o token efêmero vem de POST /v1/realtime/client_secrets.

    +
    +
    + + + +
    +
    +
    # Servidor: emite um client secret efêmero (Python + SDK oficial)
    +from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# O client secret de curta duração que o navegador usará para conectar via WebRTC.
    +secret = client.realtime.client_secrets.create(
    +    session={
    +        "type": "realtime",
    +        "model": "gpt-realtime-2.1",
    +        "audio": {"output": {"voice": "marin"}},
    +    },
    +)
    +
    +print(secret.value)  # ek_... -> devolva ao navegador (NUNCA exponha a chave de API)
    +
    +
    +
    +
    // Navegador: conecta ao Realtime via WebRTC usando o token efêmero do servidor
    +const tokenResponse = await fetch("/token");
    +const { value: EPHEMERAL_KEY } = await tokenResponse.json();
    +
    +const pc = new RTCPeerConnection();
    +
    +// Toca o áudio remoto vindo do modelo
    +const audioEl = document.createElement("audio");
    +audioEl.autoplay = true;
    +pc.ontrack = (e) => (audioEl.srcObject = e.streams[0]);
    +
    +// Microfone local como track de entrada
    +const ms = await navigator.mediaDevices.getUserMedia({ audio: true });
    +pc.addTrack(ms.getTracks()[0]);
    +
    +// Canal de dados para eventos cliente/servidor
    +const dc = pc.createDataChannel("oai-events");
    +dc.addEventListener("message", (e) => console.log(JSON.parse(e.data)));
    +
    +// Negociação SDP contra /v1/realtime/calls
    +const offer = await pc.createOffer();
    +await pc.setLocalDescription(offer);
    +const sdpResponse = await fetch("https://api.openai.com/v1/realtime/calls", {
    +  method: "POST",
    +  body: offer.sdp,
    +  headers: {
    +    Authorization: `Bearer ${EPHEMERAL_KEY}`,
    +    "Content-Type": "application/sdp",
    +  },
    +});
    +await pc.setRemoteDescription({ type: "answer", sdp: await sdpResponse.text() });
    +
    +
    +
    +
    # Servidor: mintar um client secret efêmero para o navegador
    +curl https://api.openai.com/v1/realtime/client_secrets \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -H "OpenAI-Safety-Identifier: hashed-user-id" \
    +  -d '{
    +    "session": {
    +      "type": "realtime",
    +      "model": "gpt-realtime-2.1",
    +      "audio": { "output": { "voice": "marin" } }
    +    }
    +  }'
    +
    +
    +
    + +

    22.2.2 WebSocket: servidor↔servidor

    +

    Para integração de backend, conecte direto via WebSocket com a chave de API padrão (segura no servidor). Inclua, quando aplicável, o cabeçalho OpenAI-Safety-Identifier com um identificador estável e que preserve privacidade (ex.: hash do ID interno do usuário).

    +
    +
    + + + +
    +
    +
    # pip install websocket-client
    +import os, json, websocket
    +
    +url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1"
    +headers = [
    +    "Authorization: Bearer " + os.environ["OPENAI_API_KEY"],
    +    "OpenAI-Safety-Identifier: hashed-user-id",
    +]
    +
    +def on_open(ws):
    +    ws.send(json.dumps({
    +        "type": "session.update",
    +        "session": {"type": "realtime", "instructions": "Seja claro e breve."},
    +    }))
    +
    +def on_message(ws, message):
    +    print(json.loads(message))
    +
    +ws = websocket.WebSocketApp(url, header=headers, on_open=on_open, on_message=on_message)
    +ws.run_forever()
    +
    +
    +
    +
    import WebSocket from "ws";
    +
    +const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";
    +const ws = new WebSocket(url, {
    +  headers: {
    +    Authorization: "Bearer " + process.env.OPENAI_API_KEY,
    +    "OpenAI-Safety-Identifier": "hashed-user-id",
    +  },
    +});
    +
    +ws.on("open", () => {
    +  ws.send(JSON.stringify({
    +    type: "session.update",
    +    session: { type: "realtime", instructions: "Seja claro e breve." },
    +  }));
    +});
    +
    +ws.on("message", (message) => console.log(JSON.parse(message.toString())));
    +
    +
    +
    +
    # WebSocket não é um verbo HTTP simples; o handshake é um GET com upgrade.
    +# A URL e os cabeçalhos de autenticação são:
    +#   wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1
    +#   Authorization: Bearer $OPENAI_API_KEY
    +#   OpenAI-Safety-Identifier: hashed-user-id
    +# Use um cliente WebSocket (ws / websocket-client) — ver abas Python e JavaScript.
    +echo "Conecte com um cliente WebSocket; veja as abas Python/JavaScript."
    +
    +
    +
    + +

    22.2.3 SIP: telefonia

    +

    Com SIP você direciona chamadas telefônicas para a Realtime API via um provedor de SIP trunking. Aponte seu trunk para sip:$PROJECT_ID@sip.api.openai.com;transport=tls. Cada chamada dispara um webhook realtime.call.incoming; a partir dele você aceita (configurando modelo, voz, instruções e tools) ou rejeita a chamada e depois monitora a sessão por WebSocket.

    +
    +
    + + +
    +
    +
    from flask import Flask, request, Response
    +from openai import OpenAI, InvalidWebhookSignatureError
    +import os, json, asyncio, threading, requests, websockets
    +
    +app = Flask(__name__)
    +client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
    +AUTH = {"Authorization": "Bearer " + os.environ["OPENAI_API_KEY"]}
    +
    +async def monitor(call_id):
    +    async with websockets.connect(
    +        "wss://api.openai.com/v1/realtime?call_id=" + call_id,
    +        additional_headers=AUTH,
    +    ) as ws:
    +        await ws.send(json.dumps({"type": "response.create"}))
    +        while True:
    +            print(await ws.recv())
    +
    +@app.route("/", methods=["POST"])
    +def webhook():
    +    try:
    +        event = client.webhooks.unwrap(request.data, request.headers)
    +        if event.type == "realtime.call.incoming":
    +            # Aceita a chamada e configura a sessão Realtime que a atenderá
    +            requests.post(
    +                f"https://api.openai.com/v1/realtime/calls/{event.data.call_id}/accept",
    +                headers={**AUTH, "Content-Type": "application/json"},
    +                json={
    +                    "type": "realtime",
    +                    "model": "gpt-realtime-2.1",
    +                    "instructions": "Você é o Alex, concierge da Example Corp.",
    +                },
    +            )
    +            threading.Thread(
    +                target=lambda: asyncio.run(monitor(event.data.call_id)), daemon=True
    +            ).start()
    +            return Response(status=200)
    +    except InvalidWebhookSignatureError:
    +        return Response("Invalid signature", status=400)
    +
    +
    +
    +
    # Aceitar a chamada recebida (mesmos parâmetros de criar um client secret)
    +curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/accept" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{ "type": "realtime", "model": "gpt-realtime-2.1",
    +        "instructions": "Você é o Alex, concierge da Example Corp." }'
    +
    +# Rejeitar (ex.: 486 = ocupado), transferir (refer) ou encerrar (hangup):
    +curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/reject" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" \
    +  -d '{"status_code": 486}'
    +curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/refer" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" \
    +  -d '{"target_uri": "tel:+14155550123"}'
    +curl -X POST "https://api.openai.com/v1/realtime/calls/$CALL_ID/hangup" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY"
    +
    +
    +
    + +

    22.3 Ciclo de eventos cliente/servidor

    +

    A sessão é gerida por eventos do cliente (que você emite) e eventos do servidor (que a API emite para indicar mudanças de estado). Ao conectar, o servidor envia session.created; você ajusta a configuração com session.update (e recebe session.updated). A maioria das propriedades pode mudar a qualquer momento — exceto a voice, que não pode ser alterada depois que o modelo já emitiu áudio na sessão.

    +

    Para gerar uma resposta: crie um item com conversation.item.create e dispare response.create. Durante a geração, o servidor emite uma sequência de eventos de ciclo de vida que você pode usar para feedback em tempo real:

    +
    + + + + + + + + + + +
    FaseEventos do servidor (ordem aproximada)
    Item adicionadoconversation.item.added → conversation.item.done
    Resposta iniciadaresponse.created → response.output_item.added → response.content_part.added
    Áudio (saída)response.output_audio.delta (bytes Base64) → response.output_audio.done
    Transcrição do áudio geradoresponse.output_audio_transcript.delta → response.output_audio_transcript.done
    Texto (quando há modalidade de texto)response.output_text.delta → response.output_text.done
    Encerramentoresponse.content_part.done → response.output_item.done → response.done → rate_limits.updated
    +
    +
    Atenção: os eventos response.output_audio.done e response.done não carregam os bytes do áudio — apenas a transcrição. Para obter o áudio real, escute os response.output_audio.delta e bufferize/transmita os chunks Base64.
    + +

    22.4 Áudio de entrada e saída

    +

    Em WebRTC, a mídia é praticamente automática: adicione o track local do microfone e o usuário já pode falar; o áudio do modelo chega como track remoto. Você ainda recebe eventos de ciclo de vida (input_audio_buffer.speech_started/speech_stopped, deltas de transcrição, response.done).

    +

    Em WebSocket, você controla o input audio buffer manualmente: envie chunks Base64 com input_audio_buffer.append (cada chunk ≤ 15 MB). Formatos configuráveis por sessão (session.audio.input.format / output.format) — PCM 24 kHz mono (audio/pcm) é a base; há também audio/pcmu para telefonia.

    +

    Vozes disponíveis na sessão Realtime: alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin e cedar. Para melhor qualidade, prefira marin ou cedar. gpt-realtime-2.1 também aceita entrada de imagem como content part de uma mensagem do usuário.

    +
    +
    + + +
    +
    +
    // session.update define modalidade de saída, formatos, voz e VAD
    +const update = {
    +  type: "session.update",
    +  session: {
    +    type: "realtime",
    +    model: "gpt-realtime-2.1",
    +    output_modalities: ["audio"], // use ["text"] para texto sem áudio
    +    audio: {
    +      input: {
    +        format: { type: "audio/pcm", rate: 24000 },
    +        turn_detection: { type: "semantic_vad" },
    +      },
    +      output: { format: { type: "audio/pcm" }, voice: "marin" },
    +    },
    +    instructions: "Confirme entendimento antes de agir.",
    +  },
    +};
    +dataChannel.send(JSON.stringify(update)); // WebRTC ou WebSocket: ambos têm .send()
    +
    +// Em WebSocket: streamar áudio cru e disparar a resposta
    +ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: base64Pcm16 }));
    +ws.send(JSON.stringify({ type: "input_audio_buffer.commit" })); // quando VAD está off
    +ws.send(JSON.stringify({ type: "response.create" }));
    +
    +// Coletar os bytes de saída
    +ws.on("message", (m) => {
    +  const ev = JSON.parse(m.toString());
    +  if (ev.type === "response.output_audio.delta") bufferAudio(ev.delta); // Base64
    +});
    +
    +
    +
    +
    import base64, json
    +
    +# session.update equivalente (dicionário enviado como JSON pelo socket)
    +update = {
    +    "type": "session.update",
    +    "session": {
    +        "type": "realtime",
    +        "model": "gpt-realtime-2.1",
    +        "output_modalities": ["audio"],
    +        "audio": {
    +            "input": {
    +                "format": {"type": "audio/pcm", "rate": 24000},
    +                "turn_detection": {"type": "semantic_vad"},
    +            },
    +            "output": {"format": {"type": "audio/pcm"}, "voice": "marin"},
    +        },
    +        "instructions": "Confirme entendimento antes de agir.",
    +    },
    +}
    +ws.send(json.dumps(update))
    +
    +# Streamar áudio cru e disparar a resposta
    +ws.send(json.dumps({"type": "input_audio_buffer.append", "audio": base64_pcm16}))
    +ws.send(json.dumps({"type": "input_audio_buffer.commit"}))   # quando VAD está off
    +ws.send(json.dumps({"type": "response.create"}))
    +
    +def on_message(ws, message):
    +    ev = json.loads(message)
    +    if ev["type"] == "response.output_audio.delta":
    +        chunk = base64.b64decode(ev["delta"])   # bytes de áudio
    +
    +
    +
    + +

    22.5 Tools na sessão

    +

    Você pode anexar tools para o modelo consultar dados ou agir durante a conversa. A configuração usa o mesmo conjunto de eventos em WebRTC e WebSocket, e pode ser feita no nível da sessão (session.tools em session.update, disponível pela sessão inteira) ou no nível da resposta (response.tools em response.create, só para um turno).

    +
    + + + + + + + +
    Tipo de toolUse quandoQuem executa
    functionSua aplicação detém a lógica de negócio, checagens de aprovação ou acesso privado.Seu cliente/servidor recebe a chamada e devolve function_call_output.
    mcp com server_urlO modelo deve chamar tools expostas por um servidor MCP remoto.A própria Realtime API chama o servidor MCP.
    mcp com connector_idVocê quer um connector embutido (ex.: Google Calendar).A Realtime API chama o connector com a autorização fornecida.
    +
    +
    +
    + + +
    +
    +
    import json
    +
    +# 1) Registrar uma function tool na sessão
    +ws.send(json.dumps({
    +    "type": "session.update",
    +    "session": {
    +        "type": "realtime",
    +        "model": "gpt-realtime-2.1",
    +        "tools": [{
    +            "type": "function",
    +            "name": "lookup_order",
    +            "description": "Busca um pedido pelo número.",
    +            "parameters": {
    +                "type": "object",
    +                "properties": {"order_number": {"type": "string"}},
    +                "required": ["order_number"],
    +            },
    +        }],
    +        "tool_choice": "auto",
    +    },
    +}))
    +
    +# 2) Quando o modelo chamar a function, execute e devolva o resultado
    +ws.send(json.dumps({
    +    "type": "conversation.item.create",
    +    "item": {
    +        "type": "function_call_output",
    +        "call_id": function_call["call_id"],
    +        "output": json.dumps({"status": "shipped", "delivery_date": "2026-05-09"}),
    +    },
    +}))
    +ws.send(json.dumps({"type": "response.create"}))
    +
    +
    +
    +
    // 1) Registrar a function tool
    +ws.send(JSON.stringify({
    +  type: "session.update",
    +  session: {
    +    type: "realtime",
    +    model: "gpt-realtime-2.1",
    +    tools: [{
    +      type: "function",
    +      name: "lookup_order",
    +      description: "Busca um pedido pelo número.",
    +      parameters: {
    +        type: "object",
    +        properties: { order_number: { type: "string" } },
    +        required: ["order_number"],
    +      },
    +    }],
    +    tool_choice: "auto",
    +  },
    +}));
    +
    +// 2) Devolver o resultado da function
    +ws.send(JSON.stringify({
    +  type: "conversation.item.create",
    +  item: {
    +    type: "function_call_output",
    +    call_id: functionCall.call_id,
    +    output: JSON.stringify({ status: "shipped", delivery_date: "2026-05-09" }),
    +  },
    +}));
    +ws.send(JSON.stringify({ type: "response.create" }));
    +
    +
    +
    + +

    22.6 Configuração de VAD na sessão

    +

    Por padrão, sessões fala↔fala têm voice activity detection (VAD) ligada — a API decide quando o usuário começou/parou de falar e responde sozinha (server_vad é o default). Configure em session.audio.input.turn_detection. Detalhes dos modos server_vad e semantic_vad estão na Seção 28. Para controle granular (ex.: push-to-talk), desligue a VAD com turn_detection: null e emita manualmente input_audio_buffer.commit e response.create.

    + +

    22.7 Custos e truncation

    +

    O faturamento da Realtime API depende do tipo de sessão. Sessões de agente de voz acumulam tokens de entrada e saída (texto, áudio e imagem) por Response; tradução e transcrição em streaming são cobradas por duração do áudio (não pelo ciclo de Response). Os preços variam por modelo (veja a página de cada modelo).

    +
      +
    • Tokens de áudio: mensagens do usuário = 1 token por 100 ms de áudio; mensagens do assistente = 1 token por 50 ms. Há pequenos tokens especiais além do conteúdo, então as contagens variam um pouco.
    • +
    • Conversa inteira por turno: a cada Response, toda a Conversation é enviada ao modelo; turnos mais tardios na sessão custam mais. Leia o uso real no campo usage do evento response.done.
    • +
    • Caching automático: o prompt caching é aplicado automaticamente e reduz muito o custo de entrada em sessões multiturno (melhor esforço). Mantenha o histórico, as instructions e as definições de tools estáticos — alterá-los no meio da sessão "quebra" o cache dali em diante.
    • +
    • Transcrição de entrada: se habilitada, é cobrada à parte (modelo de transcrição próprio, ex.: whisper-1 ou gpt-4o-transcribe); o uso vem em conversation.item.input_audio_transcription.completed.
    • +
    • Modelo mini: os modelos speech-to-speech têm uma versão "mini" bem mais barata — refine no modelo maior e só então tente otimizar custo migrando para o mini.
    • +
    +

    Quando os tokens excedem o limite de contexto do modelo, a Conversation é truncada (itens mais antigos são descartados). Você pode definir uma janela menor e controlar o trade-off custo × memória com session.truncation: token_limits.post_instructions limita os tokens de entrada por Response (exceto as instructions), e retention_ratio (default 1.0) faz a truncation descartar mais que o necessário para estender a folga antes da próxima truncation — útil porque truncar a cada turno derruba o cache. Também é possível "truncation": "disabled" para gerenciar a Conversation manualmente.

    +
    +
    + +
    +
    +
    # Reduzir custo por sessão: limitar tokens e reter 80% antes de truncar de novo
    +{
    +  "event": "session.update",
    +  "session": {
    +    "truncation": {
    +      "type": "retention_ratio",
    +      "retention_ratio": 0.8,
    +      "token_limits": { "post_instructions": 8000 }
    +    }
    +  }
    +}
    +
    +
    +
    +
    Dica: outra estratégia é editar a Conversation manualmente — remova itens antigos com conversation.item.delete (ou substitua por um resumo via conversation.item.create) para reduzir o tamanho da entrada. Estime custos rodando prompts representativos no Realtime Playground e medindo o uso de tokens por sessão.
    + + +
    + +
    +

    23. Tradução em tempo real (gpt-realtime-translate)

    +

    A tradução em tempo real transmite áudio de origem para uma sessão dedicada e devolve áudio traduzido + deltas de transcrição enquanto a pessoa ainda fala. Casos de uso: interpretação ao vivo, chamadas multilíngues, transmissões, reuniões, aulas e salas de vídeo. Use gpt-realtime-translate quando o app deve traduzir o que um humano diz; se precisa de um assistente que responde, chama tools e gerencia conversa, use gpt-realtime-2.1 (Seção 22).

    + +

    23.1 Como a sessão de tradução difere

    +
    + + + + + + + + + +
    Sessão de agente de vozSessão de tradução
    Conecta a /v1/realtime.Conecta a /v1/realtime/translations.
    O modelo age como assistente.O modelo age como intérprete.
    Usa ciclo de conversa e resposta.Transmite continuamente a partir do áudio de entrada.
    Pode chamar tools e produzir turnos do assistente.Produz áudio traduzido e deltas de transcrição.
    Você pode chamar response.create.Você não chama response.create.
    +
    +
    Nota: a tradução parte do próprio fluxo de áudio. Continue dando append no áudio — inclusive os silêncios entre frases — e trate os eventos de saída conforme chegam. O modelo emite áudio traduzido em chunks PCM16 de ~200 ms, além de deltas de transcrição no idioma de destino. Use WebRTC para mídia de navegador e WebSockets para pipelines de servidor (Twilio Media Streams, mídia SIP, ingest de broadcast).
    + +

    23.2 Fluxo, configuração e eventos

    +

    Conecte ao endpoint dedicado selecionando o modelo na URL, configure o idioma de destino com session.update (em audio.output.language) e então faça append de áudio continuamente. Escute os eventos de saída: session.output_audio.delta (áudio traduzido), session.output_transcript.delta (transcrição de destino) e session.input_transcript.delta (transcrição da origem).

    +
    +
    + + +
    +
    +
    # pip install websocket-client
    +import os, json, websocket
    +
    +ws = websocket.WebSocket()
    +ws.connect(
    +    "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
    +    header=[
    +        f"Authorization: Bearer {os.environ['OPENAI_API_KEY']}",
    +        "OpenAI-Safety-Identifier: hashed-user-id",
    +    ],
    +)
    +
    +# Idioma de destino (ex.: espanhol)
    +ws.send(json.dumps({
    +    "type": "session.update",
    +    "session": {"audio": {"output": {"language": "es"}}},
    +}))
    +
    +# Streamar áudio de origem continuamente (incluindo silêncios)
    +ws.send(json.dumps({
    +    "type": "session.input_audio_buffer.append",
    +    "audio": base64_pcm16,
    +}))
    +
    +while True:
    +    ev = json.loads(ws.recv())
    +    if ev["type"] == "session.output_audio.delta":
    +        play_pcm16(ev["delta"])              # áudio traduzido (Base64)
    +    elif ev["type"] == "session.output_transcript.delta":
    +        print(ev["delta"], end="", flush=True)  # legenda no idioma de destino
    +    elif ev["type"] == "session.input_transcript.delta":
    +        update_source_transcript(ev["delta"])   # legenda na origem
    +
    +
    +
    +
    import WebSocket from "ws";
    +
    +const ws = new WebSocket(
    +  "wss://api.openai.com/v1/realtime/translations?model=gpt-realtime-translate",
    +  { headers: {
    +      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
    +      "OpenAI-Safety-Identifier": "hashed-user-id",
    +  } }
    +);
    +
    +ws.on("open", () => {
    +  ws.send(JSON.stringify({
    +    type: "session.update",
    +    session: { audio: { output: { language: "es" } } },
    +  }));
    +});
    +
    +// Áudio de origem (incluindo silêncios entre frases)
    +ws.send(JSON.stringify({
    +  type: "session.input_audio_buffer.append",
    +  audio: base64Pcm16,
    +}));
    +
    +ws.on("message", (data) => {
    +  const ev = JSON.parse(data);
    +  if (ev.type === "session.output_audio.delta") playPcm16(ev.delta);
    +  if (ev.type === "session.output_transcript.delta") process.stdout.write(ev.delta);
    +  if (ev.type === "session.input_transcript.delta") updateSourceTranscript(ev.delta);
    +});
    +
    +
    +
    + +

    23.3 Encerrar o stream de origem

    +

    Quando o áudio de origem termina, envie session.close antes de fechar o WebSocket. Esse evento (suportado apenas em sessões de tradução) faz o serviço esvaziar o áudio de entrada pendente, emitir o áudio/transcrição traduzidos restantes e então enviar session.closed. Pare de dar append e continue lendo eventos no seu loop normal até receber session.closed — fechar o socket imediatamente descarta a saída ainda em drenagem.

    +
    +
    + + +
    +
    +
    import json
    +
    +closing = False
    +
    +def close_translation_session():
    +    global closing
    +    if closing:
    +        return
    +    closing = True
    +    ws.send(json.dumps({"type": "session.close"}))
    +
    +close_translation_session()  # chame quando o stream de origem terminar
    +
    +while True:
    +    ev = json.loads(ws.recv())
    +    if ev["type"] == "session.output_audio.delta":
    +        play_pcm16(ev["delta"])
    +    elif ev["type"] == "session.output_transcript.delta":
    +        print(ev["delta"], end="", flush=True)
    +    elif ev["type"] == "session.closed":
    +        ws.close()
    +        break
    +
    +
    +
    +
    let closing = false;
    +function closeTranslationSession() {
    +  if (closing) return;
    +  closing = true;
    +  ws.send(JSON.stringify({ type: "session.close" }));
    +}
    +
    +ws.on("message", (data) => {
    +  const ev = JSON.parse(data);
    +  if (ev.type === "session.output_audio.delta") playPcm16(ev.delta);
    +  if (ev.type === "session.output_transcript.delta") process.stdout.write(ev.delta);
    +  if (ev.type === "session.closed") ws.close();
    +});
    +
    +closeTranslationSession(); // chame quando o stream de origem terminar
    +
    +
    +
    +
    Dica: use uma sessão por idioma de destino. Para uma chamada entre duas pessoas, crie uma sessão por direção (A→idioma de B, B→idioma de A). Em salas de grupo, o número de sessões ≈ falantes de origem ativos × idiomas de destino distintos. Mantenha os tracks de cada falante separados.
    + + +
    + +
    +

    24. Transcrição em streaming (gpt-realtime-whisper)

    +

    Use transcrição em tempo real quando o app precisa de speech-to-text ao vivo sem resposta falada do modelo. A sessão transmite deltas de transcrição conforme o áudio chega, de modo que o usuário vê texto antes do enunciado terminar. Para o caminho de menor latência, use gpt-realtime-whisper, projetado para ser nativamente em streaming dentro de sessões Realtime com latência controlável.

    + +

    24.1 Escolha do modelo de transcrição

    +
    + + + + + + + +
    ModeloMelhor paraNotas
    gpt-realtime-whisperÁudio ao vivo, deltas de transcrição, latência ajustável.Nativamente em streaming, feito para sessões realtime.
    gpt-4o-transcribeSTT de maior acurácia quando streaming não é necessário.Para fluxos de arquivo e requisição-resposta (Seção 25).
    gpt-4o-mini-transcribeTranscrição de menor custo.Quando custo importa mais que acurácia máxima.
    +
    +
    Atenção: gpt-realtime-whisper é uma alternativa para transcrição ao vivo, não um substituto universal. Teste contra seu áudio, idiomas, vocabulário e requisitos de latência antes de migrar tráfego de produção.
    + +

    24.2 Sessão de transcrição, deltas e uso

    +

    A transcrição em tempo real usa uma sessão type: "transcription". Conecte via WebSocket (pipeline de servidor) ou WebRTC (áudio de navegador). Campos de sessão relevantes:

    +
    + + + + + + + + + + +
    CampoDescrição
    typeDefina como transcription para sessões só de transcrição.
    audio.input.formatEncoding do áudio adicionado ao buffer. Use PCM mono 24 kHz para audio/pcm.
    audio.input.transcription.modelUse gpt-realtime-whisper para streaming.
    audio.input.transcription.languageDica opcional de idioma (ex.: pt, en).
    audio.input.transcription.delayTrade-off latência/acurácia. Valores: minimal, low, medium, high, xhigh.
    audio.input.turn_detectionVAD opcional. Para gpt-realtime-whisper, omita ou defina null e faça commit manual.
    +
    +

    Escute conversation.item.input_audio_transcription.delta (texto incremental) e conversation.item.input_audio_transcription.completed (transcrição final do item). Como a ordem entre turnos diferentes não é garantida, use item_id para casar e reconciliar os resultados.

    +
    +
    + + +
    +
    +
    // 1) Abrir uma sessão de transcrição
    +ws.send(JSON.stringify({
    +  type: "session.update",
    +  session: {
    +    type: "transcription",
    +    audio: {
    +      input: {
    +        format: { type: "audio/pcm", rate: 24000 },
    +        transcription: {
    +          model: "gpt-realtime-whisper",
    +          language: "pt",
    +          delay: "low",        // minimal | low | medium | high | xhigh
    +        },
    +        turn_detection: null,  // gpt-realtime-whisper: commit manual
    +      },
    +    },
    +  },
    +}));
    +
    +// 2) Streamar áudio e (sem VAD) commitar quando quiser iniciar a transcrição
    +ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: base64Pcm16 }));
    +ws.send(JSON.stringify({ type: "input_audio_buffer.commit" }));
    +
    +// 3) Consumir os deltas e o evento final
    +ws.on("message", (data) => {
    +  const ev = JSON.parse(data);
    +  if (ev.type === "conversation.item.input_audio_transcription.delta")
    +    process.stdout.write(ev.delta);
    +  if (ev.type === "conversation.item.input_audio_transcription.completed")
    +    console.log("\nFinal:", ev.transcript, "(item", ev.item_id + ")");
    +});
    +
    +
    +
    +
    # Forma do session.update enviado pelo socket (JSON):
    +{
    +  "type": "session.update",
    +  "session": {
    +    "type": "transcription",
    +    "audio": {
    +      "input": {
    +        "format": { "type": "audio/pcm", "rate": 24000 },
    +        "transcription": { "model": "gpt-realtime-whisper", "language": "pt" }
    +      }
    +    },
    +    "include": ["item.input_audio_transcription.logprobs"]
    +  }
    +}
    +
    +
    +
    +
    Nota: ajuste a latência por delay — minimal/low para legendas ao vivo, medium equilibrado, high/xhigh quando a acurácia importa mais que a exibição imediata. Faça benchmark com áudio representativo (microfones reais, telefonia, sotaques, ruído, código-troca). Em sessões GA com gpt-realtime-whisper, o parâmetro prompt não é suportado; logprobs podem ser pedidos via include quando disponíveis. Sempre confirme suporte de timestamps/diarização/confiança antes do lançamento e tenha fallback.
    + + +
    + +
    +

    25. Speech-to-text (arquivos)

    +

    A Audio API oferece dois endpoints de speech-to-text: transcriptions (transcreve no idioma do áudio) e translations (transcreve traduzindo para inglês). Use esta via para uploads de arquivos e requisições delimitadas; para deltas ao vivo de microfone/chamada, use a Seção 24. Uploads são limitados a 25 MB e aceitam mp3, mp4, mpeg, mpga, m4a, wav e webm.

    + +

    25.1 Endpoint /v1/audio/transcriptions

    +

    O endpoint transcriptions aceita os modelos de maior qualidade gpt-4o-transcribe e gpt-4o-mini-transcribe, além de gpt-4o-transcribe-diarize e do whisper-1. Cada um suporta um conjunto diferente de response_format:

    +
    + + + + + + + + +
    Modeloresponse_format suportadoOutros parâmetros
    gpt-4o-transcribejson, textAceita prompt, logprobs, stream.
    gpt-4o-mini-transcribejson, textAceita prompt, logprobs, stream.
    gpt-4o-transcribe-diarizejson, text, diarized_jsonExige chunking_strategy > 30 s; não aceita prompt, logprobs nem timestamp_granularities[].
    whisper-1json, text, srt, verbose_json, vttÚnico com timestamp_granularities[] e subtítulos srt/vtt; sem streaming.
    +
    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +with open("audio.mp3", "rb") as audio_file:
    +    transcription = client.audio.transcriptions.create(
    +        model="gpt-4o-transcribe",
    +        file=audio_file,
    +        response_format="text",
    +        prompt="Termos de domínio: DALL·E, GPT, OpenAI.",  # melhora reconhecimento
    +    )
    +
    +print(transcription.text)
    +
    +
    +
    +
    import fs from "fs";
    +import OpenAI from "openai";
    +
    +const openai = new OpenAI();
    +
    +const transcription = await openai.audio.transcriptions.create({
    +  file: fs.createReadStream("audio.mp3"),
    +  model: "gpt-4o-transcribe",
    +  response_format: "text",
    +  prompt: "Termos de domínio: DALL·E, GPT, OpenAI.",
    +});
    +
    +console.log(transcription.text);
    +
    +
    +
    +
    curl https://api.openai.com/v1/audio/transcriptions \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: multipart/form-data" \
    +  -F file=@audio.mp3 \
    +  -F model=gpt-4o-transcribe \
    +  -F response_format=text
    +
    +
    +
    + +

    25.2 Diarização de falantes (gpt-4o-transcribe-diarize)

    +

    gpt-4o-transcribe-diarize produz transcrições com identificação de falante. Peça response_format: "diarized_json" para receber um array de segmentos com speaker, start e end. Defina chunking_strategy ("auto" recomendado, ou uma config de VAD) — obrigatório quando o áudio passa de 30 s. Opcionalmente, mapeie até quatro falantes conhecidos com known_speaker_names[] e known_speaker_references[] (clipes de 2–10 s, codificados como data URLs no multipart).

    +
    +
    + + + +
    +
    +
    import base64
    +from openai import OpenAI
    +
    +client = OpenAI()
    +
    +def to_data_url(path: str) -> str:
    +    with open(path, "rb") as fh:
    +        return "data:audio/wav;base64," + base64.b64encode(fh.read()).decode("utf-8")
    +
    +with open("meeting.wav", "rb") as audio_file:
    +    transcript = client.audio.transcriptions.create(
    +        model="gpt-4o-transcribe-diarize",
    +        file=audio_file,
    +        response_format="diarized_json",
    +        chunking_strategy="auto",  # obrigatório se > 30 s
    +        extra_body={
    +            "known_speaker_names": ["agente"],
    +            "known_speaker_references": [to_data_url("agente.wav")],
    +        },
    +    )
    +
    +for seg in transcript.segments:
    +    print(seg.speaker, seg.text, seg.start, seg.end)
    +
    +
    +
    +
    import fs from "fs";
    +import OpenAI from "openai";
    +
    +const openai = new OpenAI();
    +const agentRef = fs.readFileSync("agente.wav").toString("base64");
    +
    +const transcript = await openai.audio.transcriptions.create({
    +  file: fs.createReadStream("meeting.wav"),
    +  model: "gpt-4o-transcribe-diarize",
    +  response_format: "diarized_json",
    +  chunking_strategy: "auto", // obrigatório se > 30 s
    +  extra_body: {
    +    known_speaker_names: ["agente"],
    +    known_speaker_references: ["data:audio/wav;base64," + agentRef],
    +  },
    +});
    +
    +for (const seg of transcript.segments) {
    +  console.log(`${seg.speaker}: ${seg.text}`, seg.start, seg.end);
    +}
    +
    +
    +
    +
    curl https://api.openai.com/v1/audio/transcriptions \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: multipart/form-data" \
    +  -F file=@meeting.wav \
    +  -F model=gpt-4o-transcribe-diarize \
    +  -F response_format=diarized_json \
    +  -F chunking_strategy=auto \
    +  -F 'known_speaker_names[]=agente' \
    +  -F 'known_speaker_references[]=data:audio/wav;base64,AAA...'
    +
    +
    +
    +
    Nota: com stream=true, respostas diarizadas emitem transcript.text.segment quando cada segmento é finalizado. gpt-4o-transcribe-diarize está disponível apenas em /v1/audio/transcriptions e ainda não é suportado na Realtime API.
    + +

    25.3 whisper-1: timestamps/word-level e /v1/audio/translations

    +

    whisper-1 é o modelo da OpenAI para dois trabalhos específicos: timestamps em nível de segmento ou palavra e tradução de áudio→inglês. Para timestamps, use response_format: "verbose_json" com timestamp_granularities[] ("word", "segment" ou ambos) — esse parâmetro é suportado somente pelo whisper-1. Ele também é o único que gera legendas srt/vtt.

    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# (a) Timestamps em nível de palavra
    +with open("speech.mp3", "rb") as audio_file:
    +    transcription = client.audio.transcriptions.create(
    +        model="whisper-1",
    +        file=audio_file,
    +        response_format="verbose_json",
    +        timestamp_granularities=["word"],   # só whisper-1
    +    )
    +print(transcription.words)
    +
    +# (b) Tradução de áudio para inglês (endpoint translations)
    +with open("german.mp3", "rb") as audio_file:
    +    translation = client.audio.translations.create(
    +        model="whisper-1",                  # único modelo do endpoint translations
    +        file=audio_file,
    +    )
    +print(translation.text)
    +
    +
    +
    +
    import fs from "fs";
    +import OpenAI from "openai";
    +
    +const openai = new OpenAI();
    +
    +// (a) Timestamps em nível de palavra
    +const transcription = await openai.audio.transcriptions.create({
    +  file: fs.createReadStream("speech.mp3"),
    +  model: "whisper-1",
    +  response_format: "verbose_json",
    +  timestamp_granularities: ["word"], // só whisper-1
    +});
    +console.log(transcription.words);
    +
    +// (b) Tradução de áudio para inglês
    +const translation = await openai.audio.translations.create({
    +  file: fs.createReadStream("german.mp3"),
    +  model: "whisper-1", // único modelo do endpoint translations
    +});
    +console.log(translation.text);
    +
    +
    +
    +
    # (a) Timestamps em nível de palavra
    +curl https://api.openai.com/v1/audio/transcriptions \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: multipart/form-data" \
    +  -F file=@speech.mp3 \
    +  -F model=whisper-1 \
    +  -F response_format=verbose_json \
    +  -F "timestamp_granularities[]=word"
    +
    +# (b) Tradução de áudio para inglês
    +curl https://api.openai.com/v1/audio/translations \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: multipart/form-data" \
    +  -F file=@german.mp3 \
    +  -F model=whisper-1
    +
    +
    +
    + +

    25.4 Streaming e arquivos longos

    +

    Para uma gravação já concluída, passe stream=True nos modelos gpt-4o-transcribe/gpt-4o-mini-transcribe e receba eventos transcript.text.delta seguidos de transcript.text.done. Streaming não é suportado no whisper-1; para áudio ao vivo de microfone/chamada, use a transcrição em tempo real (Seção 24).

    +

    Para arquivos longos (acima de 25 MB), divida em pedaços de ≤ 25 MB ou use um formato comprimido — evite cortar no meio de uma frase para não perder contexto. O prompt (até 224 tokens no whisper-1) ajuda a corrigir grafias e acrônimos.

    + + +
    + +
    +

    26. Text-to-speech (gpt-4o-mini-tts)

    +

    O endpoint /v1/audio/speech transforma texto em áudio falado usando o modelo gpt-4o-mini-tts, o modelo de TTS mais recente e confiável da OpenAI. Os três insumos principais são: model, input (o texto, máximo de 4096 caracteres) e voice. Um diferencial do gpt-4o-mini-tts é o parâmetro instructions, que controla como o modelo fala (sotaque, faixa emocional, entonação, velocidade, tom, sussurro).

    +
    Atenção: as políticas de uso exigem que você informe claramente aos usuários finais que a voz TTS é gerada por IA e não é uma voz humana.
    + +
    Nota — modelos TTS (2026-06-29): além do gpt-4o-mini-tts, está disponível o gpt-4o-tts (modelo TTS completo, maior qualidade). Atenção: o snapshot gpt-4o-mini-tts-2025-03-20 encerra em 2026-07-23 — migre para o snapshot gpt-4o-mini-tts-2025-12-15 ou use o alias gpt-4o-mini-tts. Fonte: developers.openai.com/api/docs/deprecations.
    + +

    26.1 Gerar fala

    +
    +
    + + + +
    +
    +
    from pathlib import Path
    +from openai import OpenAI
    +
    +client = OpenAI()
    +speech_file = Path("speech.mp3")
    +
    +with client.audio.speech.with_streaming_response.create(
    +    model="gpt-4o-mini-tts",
    +    voice="coral",
    +    input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
    +    instructions="Fale em tom alegre e positivo.",
    +) as response:
    +    response.stream_to_file(speech_file)
    +
    +
    +
    +
    import fs from "fs";
    +import path from "path";
    +import OpenAI from "openai";
    +
    +const openai = new OpenAI();
    +const speechFile = path.resolve("./speech.mp3");
    +
    +const mp3 = await openai.audio.speech.create({
    +  model: "gpt-4o-mini-tts",
    +  voice: "coral",
    +  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    +  instructions: "Fale em tom alegre e positivo.",
    +});
    +
    +const buffer = Buffer.from(await mp3.arrayBuffer());
    +await fs.promises.writeFile(speechFile, buffer);
    +
    +
    +
    +
    curl https://api.openai.com/v1/audio/speech \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "gpt-4o-mini-tts",
    +    "input": "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    +    "voice": "coral",
    +    "instructions": "Fale em tom alegre e positivo."
    +  }' \
    +  --output speech.mp3
    +
    +
    +
    + +

    26.2 Vozes, instructions e formatos

    +

    O endpoint de fala oferece 13 vozes embutidas no gpt-4o-mini-tts: alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, verse, marin e cedar. Para melhor qualidade, prefira marin ou cedar. As vozes são otimizadas para inglês, mas você pode gerar áudio em vários idiomas fornecendo o texto no idioma desejado. Ouça as vozes em OpenAI.fm.

    +
    Atenção: existem três conjuntos de vozes distintos — não os misture. (1) gpt-4o-mini-tts: as 13 acima. (2) tts-1 / tts-1-hd: apenas 9 (alloy, ash, coral, echo, fable, onyx, nova, sage, shimmer) — e não aceitam instructions. (3) Realtime API: 10 vozes (alloy, ash, ballad, coral, echo, sage, shimmer, verse, marin, cedar) — sem fable, nova nem onyx.
    +
    + + + + + + + + + +
    ParâmetroValoresDescrição
    inputtexto (≤ 4096 caracteres)O texto a sintetizar.
    voiceuma das 13 embutidas, ou { "id": "voice_..." }Voz embutida ou voz personalizada (custom voice).
    instructionsstring livreControla estilo (tom, emoção, velocidade, sotaque, sussurro).
    response_formatmp3 (default), opus, aac, flac, wav, pcmFormato do áudio de saída.
    speed0.25 a 4.0 (default 1.0)Velocidade da fala gerada.
    +
    +

    Formatos por uso: MP3 (uso geral, default), Opus (streaming/baixa latência), AAC (YouTube, Android, iOS), FLAC (lossless), WAV (PCM com cabeçalho), PCM (amostras cruas 24 kHz, 16-bit signed little-endian).

    + +

    26.3 Streaming de áudio em tempo real

    +

    O endpoint suporta streaming via chunk transfer encoding: o áudio pode tocar antes do arquivo inteiro ser gerado. Para as menores latências de resposta, use wav ou pcm como response_format.

    +
    +
    + + + +
    +
    +
    import asyncio
    +from openai import AsyncOpenAI
    +from openai.helpers import LocalAudioPlayer
    +
    +openai = AsyncOpenAI()
    +
    +async def main() -> None:
    +    async with openai.audio.speech.with_streaming_response.create(
    +        model="gpt-4o-mini-tts",
    +        voice="coral",
    +        input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
    +        instructions="Fale em tom alegre e positivo.",
    +        response_format="pcm",   # pcm/wav para menor latência
    +    ) as response:
    +        await LocalAudioPlayer().play(response)
    +
    +asyncio.run(main())
    +
    +
    +
    +
    import OpenAI from "openai";
    +import { playAudio } from "openai/helpers/audio";
    +
    +const openai = new OpenAI();
    +
    +const response = await openai.audio.speech.create({
    +  model: "gpt-4o-mini-tts",
    +  voice: "coral",
    +  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    +  instructions: "Fale em tom alegre e positivo.",
    +  response_format: "wav", // wav/pcm para menor latência
    +});
    +
    +await playAudio(response);
    +
    +
    +
    +
    curl https://api.openai.com/v1/audio/speech \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "gpt-4o-mini-tts",
    +    "input": "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    +    "voice": "coral",
    +    "instructions": "Fale em tom alegre e positivo.",
    +    "response_format": "wav"
    +  }' | ffplay -i -
    +
    +
    +
    +
    Nota: tanto a referência da API quanto a seção "Voice options" do guia confirmam 13 vozes embutidas no gpt-4o-mini-tts (incluindo marin e cedar) — a contagem oficial é 13. O parâmetro instructions controla estilo (tom, emoção, velocidade, sotaque, sussurro) e está documentado como disponível no gpt-4o-mini-tts (não funciona em tts-1/tts-1-hd). Custom voices (voz personalizada via { "id": "voice_..." }) exigem habilitação para clientes elegíveis e gravação de consentimento; até 20 vozes por organização.
    + + +
    + +
    +

    27. Áudio no chat (gpt-audio-1.5)

    +

    Quando você já tem um app baseado em Chat Completions e quer adicionar áudio sem montar uma sessão em tempo real, use o modelo nativamente multimodal gpt-audio-1.5. Ele aceita entrada de áudio e produz saída de áudio em uma única requisição de chat: basta incluir "audio" no array modalities e configurar audio: { voice, format }.

    +
    Nota: esse padrão de áudio no chat usa Chat Completions com um modelo de áudio. A documentação da Responses API descreve, hoje, entradas de texto e imagem com saída de texto; para entrada/saída de áudio direta no modelo, use Chat Completions com gpt-audio-1.5.
    + +

    27.1 Entrada e saída de áudio

    +
    +
    + + + +
    +
    +
    import base64
    +from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# Saída de áudio: pergunta em texto, resposta falada
    +completion = client.chat.completions.create(
    +    model="gpt-audio-1.5",
    +    modalities=["text", "audio"],
    +    audio={"voice": "alloy", "format": "wav"},
    +    messages=[{"role": "user", "content": "Golden retriever é um bom cão de família?"}],
    +)
    +
    +print(completion.choices[0].message)
    +wav_bytes = base64.b64decode(completion.choices[0].message.audio.data)
    +with open("dog.wav", "wb") as f:
    +    f.write(wav_bytes)
    +
    +# Entrada de áudio: enviar gravação como content part input_audio
    +with open("pergunta.wav", "rb") as fh:
    +    audio_b64 = base64.b64encode(fh.read()).decode("utf-8")
    +
    +resp = client.chat.completions.create(
    +    model="gpt-audio-1.5",
    +    modalities=["text", "audio"],
    +    audio={"voice": "alloy", "format": "wav"},
    +    messages=[{
    +        "role": "user",
    +        "content": [
    +            {"type": "text", "text": "O que há nesta gravação?"},
    +            {"type": "input_audio", "input_audio": {"data": audio_b64, "format": "wav"}},
    +        ],
    +    }],
    +)
    +print(resp.choices[0].message)
    +
    +
    +
    +
    import { writeFileSync, readFileSync } from "node:fs";
    +import OpenAI from "openai";
    +
    +const openai = new OpenAI();
    +
    +// Saída de áudio
    +const response = await openai.chat.completions.create({
    +  model: "gpt-audio-1.5",
    +  modalities: ["text", "audio"],
    +  audio: { voice: "alloy", format: "wav" },
    +  messages: [{ role: "user", content: "Golden retriever é um bom cão de família?" }],
    +});
    +writeFileSync("dog.wav",
    +  Buffer.from(response.choices[0].message.audio.data, "base64"));
    +
    +// Entrada de áudio
    +const audioB64 = readFileSync("pergunta.wav").toString("base64");
    +const resp = await openai.chat.completions.create({
    +  model: "gpt-audio-1.5",
    +  modalities: ["text", "audio"],
    +  audio: { voice: "alloy", format: "wav" },
    +  messages: [{
    +    role: "user",
    +    content: [
    +      { type: "text", text: "O que há nesta gravação?" },
    +      { type: "input_audio", input_audio: { data: audioB64, format: "wav" } },
    +    ],
    +  }],
    +});
    +console.log(resp.choices[0].message);
    +
    +
    +
    +
    curl https://api.openai.com/v1/chat/completions \
    +  -H "Content-Type: application/json" \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "model": "gpt-audio-1.5",
    +    "modalities": ["text", "audio"],
    +    "audio": { "voice": "alloy", "format": "wav" },
    +    "messages": [
    +      { "role": "user", "content": [
    +        { "type": "text", "text": "O que há nesta gravação?" },
    +        { "type": "input_audio",
    +          "input_audio": { "data": "<base64 do áudio>", "format": "wav" } }
    +      ] }
    +    ]
    +  }'
    +
    +
    +
    + +

    27.2 Quando usar áudio no chat vs. Realtime/STT/TTS

    +
    + + + + + + + + +
    CenárioUsePor quê
    Conversa ao vivo, baixa latência, barge-in, tools em tempo realgpt-realtime-2.1 (Realtime, Seção 22)Sessão de streaming bidirecional; o modelo escuta e fala continuamente.
    Estender um app de chat com perguntas/respostas faladas e turnos delimitadosgpt-audio-1.5 (Chat Completions)Requisição única; sem gerenciar sessão, buffers ou eventos.
    Só transcrever áudio (sem resposta falada)gpt-4o-transcribe / gpt-realtime-whisperSTT puro de arquivo (Seção 25) ou ao vivo (Seção 24).
    Só converter texto em falagpt-4o-mini-tts (Seção 26)Geração de fala com controle de estilo via instructions.
    +
    + + +
    + +
    +

    28. Voice agents & VAD

    +

    Agentes de voz levam os conceitos de agente para interações faladas de baixa latência. A decisão de arquitetura mais importante é: o modelo deve trabalhar diretamente com áudio ao vivo, ou sua aplicação deve encadear explicitamente speech-to-text, raciocínio em texto e text-to-speech?

    + +

    28.1 Arquitetura: fala↔fala vs. pipeline encadeado

    +
    + + + + + + +
    ArquiteturaMelhor paraPor quê
    Fala↔fala (sessão de áudio ao vivo)Conversas naturais e de baixa latência.O modelo lida com entrada e saída de áudio diretamente (gpt-realtime-2.1).
    Pipeline de voz encadeadoFluxos previsíveis ou extensão de um agente de texto existente.Seu app mantém controle explícito sobre transcrição, raciocínio em texto e geração de fala.
    +
    +

    No fluxo fala↔fala em navegador: (1) seu servidor cria um client secret efêmero; (2) o frontend cria uma RealtimeSession; (3) a sessão conecta por WebRTC (navegador) ou WebSocket (servidor); (4) o agente trata turnos de áudio, tools, interrupções e handoffs dentro da sessão. No pipeline encadeado, seu app gerencia explicitamente STT → workflow do agente → TTS — melhor para fluxos de suporte, com aprovações, ou quando você quer transcrições duráveis e lógica determinística entre as etapas. A regra prática: escolha a arquitetura de áudio primeiro, depois desenhe o resto do agente como faria para texto. Anexe tools, handoffs e guardrails ao RealtimeAgent do mesmo jeito que faria com um agente de texto.

    +
    Nota: as bibliotecas expõem helpers diferentes: em TypeScript, o caminho mais rápido para voz no navegador é RealtimeAgent + RealtimeSession; em Python, a via simples para estender um agente de texto é um VoicePipeline encadeado.
    + +

    28.2 VAD: server_vad e semantic_vad

    +

    Voice activity detection (VAD) detecta automaticamente quando o usuário começou/parou de falar. É ligada por padrão em sessões fala↔fala (default server_vad); em sessões de transcrição, depende do modelo (e o gpt-realtime-whisper exige turn_detection omitido ou null). Configure em session.audio.input.turn_detection. Quando ligada, a API emite input_audio_buffer.speech_started e input_audio_buffer.speech_stopped.

    +
    + + + + + + +
    ModoComo decide o fim do turnoParâmetros
    server_vad (default)Períodos de silêncio para fatiar o áudio automaticamente.threshold (0–1), prefix_padding_ms, silence_duration_ms.
    semantic_vadUm classificador semântico estima, pelas palavras ditas, se o usuário terminou (um "ummm..." gera timeout maior).eagerness: low | medium | high | auto (default ≈ medium).
    +
    +

    Em conversa fala↔fala, os campos create_response e interrupt_response (só do modo conversa) controlam se a VAD dispara a resposta e se interrompe a fala em andamento. Em sessões de transcrição, a VAD apenas controla como o áudio é fatiado. eagerness: "high" faz o modelo responder/chunkar mais rápido; "low" deixa o usuário falar sem interrupção.

    +
    +
    + + +
    +
    +
    {
    +  "type": "session.update",
    +  "session": {
    +    "type": "realtime",
    +    "audio": {
    +      "input": {
    +        "turn_detection": {
    +          "type": "server_vad",
    +          "threshold": 0.5,
    +          "prefix_padding_ms": 300,
    +          "silence_duration_ms": 500,
    +          "create_response": true,
    +          "interrupt_response": true
    +        }
    +      }
    +    }
    +  }
    +}
    +
    +
    +
    +
    // semantic_vad: o modelo decide o fim do turno pelas palavras
    +const event = {
    +  type: "session.update",
    +  session: {
    +    type: "realtime",
    +    audio: {
    +      input: {
    +        turn_detection: {
    +          type: "semantic_vad",
    +          eagerness: "low",          // low | medium | high | auto
    +          create_response: true,     // só em modo conversa
    +          interrupt_response: true,  // só em modo conversa
    +        },
    +      },
    +    },
    +  },
    +};
    +dataChannel.send(JSON.stringify(event));
    +
    +
    +
    + +

    28.3 Boas práticas de prompt de voz

    +
      +
    • Reasoning effort: comece com low na maioria dos agentes e ajuste pela tolerância de latência e complexidade da tarefa.
    • +
    • Captura exata de entidades: peça ao modelo para confirmar números, nomes e datas antes de agir; valide entidades de alto valor manualmente.
    • +
    • Áudio incerto: instrua o agente a pedir repetição quando o áudio for ambíguo, em vez de adivinhar.
    • +
    • Barge-in e turnos: use semantic_vad com eagerness baixo quando quiser deixar o usuário concluir frases; server_vad ajustado quando o ambiente é ruidoso (suba o threshold).
    • +
    • Tools e preâmbulos: defina políticas de uso de tools e mensagens de preâmbulo curtas; mantenha lógica de negócio na definição do agente e o transporte na camada de sessão.
    • +
    • Segurança: inclua um OpenAI-Safety-Identifier estável (hash do ID do usuário) nas requisições Realtime; ao usar token efêmero, defina o cabeçalho no request que cria o client secret.
    • +
    + + + +

    28.4 Receitas e exemplos oficiais (Cookbook)

    +

    Exemplos oficiais de áudio e tempo real, lidos e classificados em 2026-05-24 quanto a aderência ao estado da arte. Em produção, prefira os modelos atuais (gpt-realtime-2.1, gpt-realtime-translate, gpt-realtime-whisper, gpt-4o-mini-tts, gpt-audio-1.5).

    +
    + + + + + + + + + + +
    Receita / repositórioO que ensinaStatus
    Build Live Translation Apps (gpt-realtime-translate)Tradução fala→fala ao vivo no endpoint dedicado, em 3 transportes (aba do navegador, Twilio, LiveKit); voz dinâmica.SOTA
    openai-realtime-consoleTemplate mínimo de Realtime via WebRTC (data channel oai-events), com function calling no cliente.SOTA
    ElatoAI — Realtime no ESP32Fala→fala em hardware de borda (ESP32-S3, Opus 12 kbps, Server VAD, relay edge).SOTA
    openai-realtime-agentsPadrões de voice agents (chat-supervisor, handoff sequencial, guardrails) com o Agents SDK.Padrões SOTA · trocar IDs
    One-way translationUm locutor → muitos ouvintes (uma sessão por idioma).Legado
    Steering TTSDirigir tom/estilo da voz.Legado
    +
    +
    Sinais de receita legada (substituir ao portar): IDs de áudio/realtime com sufixo *-preview de gerações anteriores, TTS apenas por um modelo legado dedicado, steering de voz por system message e arquitetura turn-based para tradução. Equivalentes modernos: tradução ao vivo → gpt-realtime-translate (endpoint dedicado); estilo de voz → gpt-4o-mini-tts + instructions; áudio in/out no chat → gpt-audio-1.5; voz em tempo real → gpt-realtime-2.1 (com reasoning.effort).
    + +

    Os três exemplos abaixo são extraídos e adaptados da documentação oficial (verificados em 2026-06-10), já com os modelos atuais. Use a aba para alternar entre Python e JavaScript.

    + +

    1. Transcrição de arquivo com gpt-4o-transcribe — upload de áudio e leitura do texto. · guides/speech-to-text

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()  # usa a variável de ambiente OPENAI_API_KEY
    +
    +# Abre o arquivo de áudio em modo binário (mp3, wav, m4a, webm... até 25 MB)
    +with open("/caminho/audio.mp3", "rb") as audio_file:
    +    transcription = client.audio.transcriptions.create(
    +        model="gpt-4o-transcribe",
    +        file=audio_file,
    +        response_format="text",   # gpt-4o-transcribe aceita "json" ou "text"
    +        # prompt opcional melhora termos/siglas do domínio
    +        prompt="Transcrição de uma reunião sobre a API da OpenAI.",
    +    )
    +
    +print(transcription.text)
    +
    +
    +
    +
    import fs from "fs";
    +import OpenAI from "openai";
    +
    +const openai = new OpenAI(); // usa OPENAI_API_KEY do ambiente
    +
    +// Envia o arquivo como stream de leitura
    +const transcription = await openai.audio.transcriptions.create({
    +  file: fs.createReadStream("/caminho/audio.mp3"),
    +  model: "gpt-4o-transcribe",
    +  response_format: "text",
    +  prompt: "Transcrição de uma reunião sobre a API da OpenAI.",
    +});
    +
    +console.log(transcription.text);
    +
    +
    +
    + +

    2. Texto→fala com gpt-4o-mini-tts — estilo dirigido por instructions, voz marin, salvando um mp3. · guides/text-to-speech

    +
    +
    + + +
    +
    +
    from pathlib import Path
    +from openai import OpenAI
    +
    +client = OpenAI()
    +speech_file_path = Path(__file__).parent / "fala.mp3"
    +
    +# instructions controla tom/sotaque/emoção; voz "marin" é uma das recomendadas
    +with client.audio.speech.with_streaming_response.create(
    +    model="gpt-4o-mini-tts",
    +    voice="marin",
    +    input="Hoje é um ótimo dia para construir algo que as pessoas amem!",
    +    instructions="Fale em tom animado, acolhedor e com ritmo tranquilo.",
    +) as response:
    +    response.stream_to_file(speech_file_path)  # grava o mp3 em disco
    +
    +print(f"Áudio salvo em {speech_file_path}")
    +
    +
    +
    +
    import fs from "fs";
    +import path from "path";
    +import OpenAI from "openai";
    +
    +const openai = new OpenAI();
    +const speechFile = path.resolve("./fala.mp3");
    +
    +// instructions dirige o estilo; voz "marin" é uma das recomendadas
    +const mp3 = await openai.audio.speech.create({
    +  model: "gpt-4o-mini-tts",
    +  voice: "marin",
    +  input: "Hoje é um ótimo dia para construir algo que as pessoas amem!",
    +  instructions: "Fale em tom animado, acolhedor e com ritmo tranquilo.",
    +});
    +
    +// O default já é mp3; converte o ArrayBuffer em Buffer e grava
    +const buffer = Buffer.from(await mp3.arrayBuffer());
    +await fs.promises.writeFile(speechFile, buffer);
    +console.log(`Áudio salvo em ${speechFile}`);
    +
    +
    +
    + +

    3. Sessão Realtime com gpt-realtime-2.1 — no navegador via WebRTC (aba JavaScript: RTCPeerConnection + data channel oai-events + token efêmero) e no servidor via WebSocket (aba Python). Cada aba mostra session.update e o envio/recebimento de eventos no transporte natural de cada ambiente. · realtime-webrtc · realtime-websocket

    +
    +
    + + +
    +
    +
    # servidor→servidor: pip install websocket-client
    +import os
    +import json
    +import websocket
    +
    +# A chave padrão fica só no backend seguro; nunca no navegador.
    +url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1"
    +headers = [
    +    "Authorization: Bearer " + os.environ["OPENAI_API_KEY"],
    +    "OpenAI-Safety-Identifier: hash-do-id-do-usuario",
    +]
    +
    +
    +def on_open(ws):
    +    print("Conectado ao servidor.")
    +    # Configura a sessão (session.update) e envia uma mensagem do usuário
    +    ws.send(json.dumps({
    +        "type": "session.update",
    +        "session": {
    +            "type": "realtime",
    +            "instructions": "Você é um assistente de voz objetivo e gentil.",
    +        },
    +    }))
    +    ws.send(json.dumps({
    +        "type": "conversation.item.create",
    +        "item": {
    +            "type": "message",
    +            "role": "user",
    +            "content": [{"type": "input_text", "text": "Olá! Me dê uma dica rápida."}],
    +        },
    +    }))
    +    ws.send(json.dumps({"type": "response.create"}))
    +
    +
    +def on_message(ws, message):
    +    event = json.loads(message)
    +    print("Evento recebido:", event.get("type"))
    +
    +
    +ws = websocket.WebSocketApp(
    +    url, header=headers, on_open=on_open, on_message=on_message,
    +)
    +ws.run_forever()
    +
    +
    +
    +
    // Navegador: busca um token efêmero gerado pelo SEU backend (/token),
    +// que chama POST /v1/realtime/client_secrets com a chave padrão.
    +const tokenResponse = await fetch("/token");
    +const data = await tokenResponse.json();
    +const EPHEMERAL_KEY = data.value; // ex.: "ek_..." (nunca a chave padrão!)
    +
    +// Conexão peer WebRTC
    +const pc = new RTCPeerConnection();
    +
    +// Toca o áudio remoto do modelo
    +const audioEl = document.createElement("audio");
    +audioEl.autoplay = true;
    +pc.ontrack = (e) => (audioEl.srcObject = e.streams[0]);
    +
    +// Microfone local como faixa de entrada
    +const ms = await navigator.mediaDevices.getUserMedia({ audio: true });
    +pc.addTrack(ms.getTracks()[0]);
    +
    +// Data channel para enviar/receber eventos JSON
    +const dc = pc.createDataChannel("oai-events");
    +dc.addEventListener("open", () => {
    +  // session.update logo após abrir o canal
    +  dc.send(JSON.stringify({
    +    type: "session.update",
    +    session: { type: "realtime", instructions: "Seja gentil e direto." },
    +  }));
    +});
    +dc.addEventListener("message", (e) => {
    +  const event = JSON.parse(e.data); // eventos do servidor
    +  console.log("Evento:", event.type);
    +});
    +
    +// Oferta SDP → troca com a Realtime API usando o token efêmero
    +const offer = await pc.createOffer();
    +await pc.setLocalDescription(offer);
    +const sdpResponse = await fetch("https://api.openai.com/v1/realtime/calls", {
    +  method: "POST",
    +  body: offer.sdp,
    +  headers: {
    +    Authorization: `Bearer ${EPHEMERAL_KEY}`,
    +    "Content-Type": "application/sdp",
    +  },
    +});
    +await pc.setRemoteDescription({ type: "answer", sdp: await sdpResponse.text() });
    +
    +
    +
    + + +
    + +

    Parte D — Embeddings, Moderation, Operação & Referência

    Embeddings e moderation, preços e limites por modelo, processamento em lote/flex/priority, Admin APIs, erros, checklist de produção e referência rápida.

    + +
    +

    29. Embeddings

    +

    Embeddings transformam texto em vetores de ponto flutuante cuja distância mede a relação semântica entre dois trechos: distâncias pequenas indicam alta relação, distâncias grandes indicam baixa relação. São a base de busca semântica, RAG, clustering, recomendação, detecção de anomalias e classificação. O endpoint é POST /v1/embeddings e a cobrança é por token de entrada.

    + +

    29.1 Modelos e dimensões

    +

    OpenAI oferece dois modelos de embedding de terceira geração (sufixo -3). O comprimento padrão do vetor é 1536 para text-embedding-3-small e 3072 para text-embedding-3-large. Ambos aceitam até 8192 tokens por entrada.

    +
    + + + + + + +
    ModeloDimensões padrãoMáx. entrada (tokens)Uso recomendado
    text-embedding-3-small15368192Maior volume e custo baixo; busca/RAG de larga escala.
    text-embedding-3-large30728192Maior qualidade de recuperação quando precisão importa mais que custo.
    +
    +
    Nota: a entrada pode ser uma string ou um array (lote) de strings/arrays de tokens. Cada array é limitado a 2048 elementos e o request inteiro a no máximo 300.000 tokens somados em todas as entradas.
    + +

    29.2 Reduzir dimensões com dimensions

    +

    O parâmetro dimensions (suportado nos modelos text-embedding-3 e posteriores) encurta o vetor sem perder as propriedades de representação de conceito — útil para caber em bancos vetoriais com limite de dimensão, reduzindo memória e custo de armazenamento com pequena perda de acurácia. Ao encurtar manualmente após a geração, é preciso renormalizar (L2) o vetor; ao passar dimensions na chamada, a normalização já vem aplicada — esta é a abordagem recomendada.

    + +

    29.3 Gerar embeddings

    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +resp = client.embeddings.create(
    +    model="text-embedding-3-large",
    +    input="O texto que você quer indexar para busca semântica.",
    +    dimensions=1024,           # encurta de 3072 para 1024 (já normalizado)
    +    encoding_format="float",
    +)
    +
    +vetor = resp.data[0].embedding
    +print(len(vetor), resp.usage.total_tokens)
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +
    +const resp = await client.embeddings.create({
    +  model: "text-embedding-3-large",
    +  input: "O texto que você quer indexar para busca semântica.",
    +  dimensions: 1024,
    +  encoding_format: "float",
    +});
    +
    +const vetor = resp.data[0].embedding;
    +console.log(vetor.length, resp.usage.total_tokens);
    +
    +
    +
    +
    curl https://api.openai.com/v1/embeddings \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "text-embedding-3-large",
    +    "input": "O texto que você quer indexar para busca semântica.",
    +    "dimensions": 1024,
    +    "encoding_format": "float"
    +  }'
    +
    +
    +
    + +

    29.4 Uso em busca e RAG

    +

    Para recuperar os documentos mais relevantes, gere o embedding da consulta com o mesmo modelo usado para indexar e calcule a similaridade de cosseno entre o vetor da consulta e os vetores dos documentos, ordenando do maior para o menor. Coloque os trechos mais relevantes no contexto do modelo de geração para compor a resposta (RAG). Como o endpoint é estável e elegível a Zero Data Retention, embeddings podem ser pré-computados e persistidos em um banco vetorial. Para grandes coleções, prefira gerar os vetores via Batch API com 50% de desconto.

    + + +
    + +
    +

    30. Uploads API — envio multipart de arquivos grandes

    +

    A Uploads API envia arquivos grandes em múltiplas partes (multipart), contornando o limite do upload direto de arquivo único da Files API (POST /v1/files). Você cria um objeto intermediário Upload, adiciona uma ou mais Parts (pedaços de bytes), e então completa o Upload — o que gera um objeto File comum, utilizável no resto da plataforma — ou o cancela. Um Upload aceita no máximo 8 GB no total e expira 1 hora após a criação se não for completado antes.

    + +
    Quando usar Uploads vs. files.create single-shot: use o upload direto (client.files.create(...)) para arquivos que cabem confortavelmente em uma requisição HTTP. Use a Uploads API para arquivos grandes — datasets de fine-tuning, arquivos batch, documentos para Assistants/visão — especialmente em redes instáveis, onde reenviar só a Part que falhou é mais barato que reenviar o arquivo inteiro. O objeto File resultante é idêntico ao de um upload direto.
    + +

    30.1 Limites de tamanho e expiração

    +
    + + + + + + + + +
    LimiteValorDetalhe
    Tamanho máx. por Part64 MBCada chamada a POST /uploads/{id}/parts aceita no máximo 64 MB no campo data. Some quantas Parts forem necessárias até o teto do Upload.
    Tamanho total do Upload8 GBTeto absoluto do Upload. O total de bytes de todas as Parts deve bater com o valor de bytes declarado na criação.
    Expiração do Upload1 horaO próprio objeto Upload expira 1h após a criação se não for completado antes; então passa a status: expired.
    expires_after.seconds3600–2 592 000Política de expiração opcional do arquivo resultante: mínimo 3600 (1 hora), máximo 2 592 000 (30 dias). anchor só aceita "created_at".
    +
    +
    Ordem de montagem: as Parts podem ser enviadas em paralelo. A ordem final do arquivo não é a ordem de envio — ela é definida pelo array part_ids passado ao completar o Upload.
    + +

    30.2 Fluxo completo (create → parts → complete)

    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# 1) Criar o Upload (declara tamanho total, filename, mime_type e purpose)
    +upload = client.uploads.create(
    +    purpose="fine-tune",
    +    filename="training_examples.jsonl",
    +    bytes=2_147_483_648,        # 2 GB, deve bater com a soma das Parts
    +    mime_type="text/jsonl",
    +)
    +
    +# 2) Adicionar Parts (cada uma <= 64 MB); podem ser enviadas em paralelo
    +part1 = client.uploads.parts.create(
    +    upload_id=upload.id,
    +    data=open("chunk_1.bin", "rb"),
    +)
    +part2 = client.uploads.parts.create(
    +    upload_id=upload.id,
    +    data=open("chunk_2.bin", "rb"),
    +)
    +
    +# 3) Completar — a ordem de montagem vem de part_ids, não do envio
    +completed = client.uploads.complete(
    +    upload_id=upload.id,
    +    part_ids=[part1.id, part2.id],
    +)
    +
    +file_id = completed.file.id   # objeto File pronto para uso (ex.: fine-tuning)
    +
    +
    +
    +
    # 1) Criar o Upload (expires_after é opcional — rege o File resultante)
    +curl https://api.openai.com/v1/uploads \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "purpose": "fine-tune",
    +    "filename": "training_examples.jsonl",
    +    "bytes": 2147483648,
    +    "mime_type": "text/jsonl",
    +    "expires_after": { "anchor": "created_at", "seconds": 3600 }
    +  }'
    +
    +# 2) Adicionar uma Part (multipart/form-data, campo data, <= 64 MB)
    +curl https://api.openai.com/v1/uploads/upload_abc123/parts \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -F data=@chunk_1.bin
    +
    +# 3) Completar o Upload (ordem definida por part_ids)
    +curl https://api.openai.com/v1/uploads/upload_abc123/complete \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -d '{
    +    "part_ids": ["part_def456", "part_ghi789"]
    +  }'
    +
    +# Cancelar (se necessário) — sem body; nenhuma Part após o cancelamento
    +curl https://api.openai.com/v1/uploads/upload_abc123/cancel \
    +  -H "Authorization: Bearer $OPENAI_API_KEY"
    +
    +
    +
    + +

    30.3 Referência dos 4 endpoints

    +
    + + + + + + + + +
    EndpointDescriçãoCampos principais
    POST /v1/uploadsCria o Upload (status inicial pending).Request (todos obrigatórios): filename, purpose (assistants, batch, fine-tune, vision), bytes, mime_type. Opcional: expires_after (anchor=created_at, seconds).
    POST /v1/uploads/{id}/partsAdiciona um pedaço de bytes (multipart/form-data).Request: data (arquivo/chunk, obrigatório, máx. 64 MB). Resposta: objeto upload.part com id, object, created_at, upload_id.
    POST /v1/uploads/{id}/completeFinaliza o Upload e gera o File.Request: part_ids (array ordenado, obrigatório), md5 (string, opcional — checksum para verificar o conteúdo). O total de bytes deve bater com bytes da criação.
    POST /v1/uploads/{id}/cancelCancela o Upload (status cancelled).Sem body. Nenhuma Part pode ser adicionada depois.
    +
    + +

    O objeto Upload retornado contém id, object (sempre "upload"), bytes, created_at, expires_at, filename, purpose, status e — após completar — a propriedade file com o objeto File criado (id, bytes, created_at, filename, purpose, object="file").

    + +
    Pegadinha — bytes e conclusão são imutáveis: o status do Upload é um de quatro valores — pending, completed, cancelled ou expired. O total de bytes enviado precisa bater com o bytes declarado na criação, senão o complete falha. Depois de completar ou cancelar, nenhuma Part pode ser adicionada. Um Upload não completado dentro de 1h vira expired e precisa ser recriado do zero — Parts de um Upload não são reaproveitáveis em outro.
    + + +
    + +
    +

    31. Moderation

    +

    Há dois fluxos de moderação: o endpoint standalone POST /v1/moderations, que classifica um texto ou imagem isoladamente, e os scores inline, que voltam junto da geração na Responses API e no Chat Completions (ver §31.5). O endpoint standalone verifica se um texto ou imagem é potencialmente nocivo, retornando categorias sinalizadas e pontuações de confiança. É gratuito. Com ele você pode filtrar conteúdo, intervir em contas abusivas ou bloquear entradas antes de chegar ao modelo. Arquivos de imagem são limitados a 20 MB.

    + +

    31.1 Modelo atual

    +

    O modelo recomendado é omni-moderation-latest: suporta entradas multimodais (texto e imagem) e mais categorias de classificação. A entrada pode ser uma string simples ou um array de conteúdo com objetos text e image_url.

    + +

    31.2 Estrutura da resposta

    +
    + + + + + + + + +
    CampoDescrição
    flaggedtrue se o modelo classifica o conteúdo como potencialmente nocivo.
    categoriesDicionário com um flag booleano por categoria.
    category_scoresPontuação de 0 a 1 por categoria (confiança do modelo). Políticas que dependem desses scores podem precisar de recalibração ao longo do tempo.
    category_applied_input_typesQuais tipos de entrada ("text", "image") dispararam cada categoria. Disponível apenas nos modelos omni.
    +
    + +

    31.3 Categorias

    +
    + + + + + + + + + + + + + + + + + +
    CategoriaDescriçãoEntradas
    harassmentAssédio dirigido a qualquer alvo.Texto
    harassment/threateningAssédio com violência ou dano grave.Texto
    hateÓdio baseado em grupo protegido (raça, gênero, religião etc.).Texto
    hate/threateningConteúdo de ódio com violência ou dano grave.Texto
    illicitInstruções para cometer atos ilícitos. OmniTexto
    illicit/violentIlícito com referência a violência ou obtenção de arma. OmniTexto
    self-harmPromove, encoraja ou retrata automutilação.Texto e imagem
    self-harm/intentExpressa intenção/engajamento em automutilação.Texto e imagem
    self-harm/instructionsEncoraja ou instrui automutilação.Texto e imagem
    sexualConteúdo sexual (exclui educação/bem-estar).Texto e imagem
    sexual/minorsConteúdo sexual com menor de 18 anos.Texto
    violenceMorte, violência ou lesão física.Texto e imagem
    violence/graphicMorte, violência ou lesão em detalhe gráfico.Texto e imagem
    +
    +
    Nota: categorias marcadas como apenas texto retornam score 0 quando só há imagem na entrada.
    + +

    31.4 Moderar texto e imagem

    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +resp = client.moderations.create(
    +    model="omni-moderation-latest",
    +    input=[
    +        {"type": "text", "text": "Descreva esta imagem."},
    +        {"type": "image_url",
    +         "image_url": {"url": "https://exemplo.com/imagem.jpg"}},
    +    ],
    +)
    +
    +resultado = resp.results[0]
    +if resultado.flagged:
    +    print("Conteúdo sinalizado:", resultado.categories)
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +
    +const resp = await client.moderations.create({
    +  model: "omni-moderation-latest",
    +  input: [
    +    { type: "text", text: "Descreva esta imagem." },
    +    { type: "image_url", image_url: { url: "https://exemplo.com/imagem.jpg" } },
    +  ],
    +});
    +
    +const r = resp.results[0];
    +if (r.flagged) console.log("Conteúdo sinalizado:", r.categories);
    +
    +
    +
    +
    curl https://api.openai.com/v1/moderations \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "omni-moderation-latest",
    +    "input": [
    +      { "type": "text", "text": "Descreva esta imagem." },
    +      { "type": "image_url", "image_url": { "url": "https://exemplo.com/imagem.jpg" } }
    +    ]
    +  }'
    +
    +
    +
    + +

    31.5 Scores de moderação inline (Responses e Chat Completions)

    +

    Desde jun/2026 é possível pedir os scores de moderação no mesmo fluxo da geração, sem requisição separada: passe um objeto moderation no topo da requisição (Responses API ou Chat Completions) com o modelo de moderação em moderation.model. A resposta volta com response.moderation.input (moderação da entrada) e response.moderation.output (moderação da saída gerada) — cada um é um moderation_result com os mesmos campos de §31.2 (flagged, categories, category_scores). Suporte tipado no SDK Python a partir de openai 2.41.0.

    +
    +
    + + + +
    +
    +
    resp = client.responses.create(
    +    model="gpt-5.5",
    +    input="Escreva uma resposta para este e-mail de cliente: ...",
    +    moderation={"model": "omni-moderation-latest"},
    +)
    +
    +# Revise os scores ANTES de exibir a saída ou agir sobre ela.
    +for lado, resultado in (("input", resp.moderation.input), ("output", resp.moderation.output)):
    +    if getattr(resultado, "flagged", False):
    +        enviar_para_fila_de_revisao(lado, resultado.categories, resp.id)
    +
    +
    +
    +
    const resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Escreva uma resposta para este e-mail de cliente: ...",
    +  moderation: { model: "omni-moderation-latest" },
    +});
    +
    +for (const [lado, resultado] of [["input", resp.moderation.input], ["output", resp.moderation.output]]) {
    +  if (resultado?.flagged) enviarParaFilaDeRevisao(lado, resultado.categories, resp.id);
    +}
    +
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "Escreva uma resposta para este e-mail de cliente: ...",
    +    "moderation": { "model": "omni-moderation-latest" }
    +  }'
    +
    +
    +
    +
      +
    • A geração acontece normalmente. Os scores são sinal para a sua política (logging, roteamento, fila de revisão humana, bloqueio) — não um bloqueio automático. Uma recusa ou resposta safety-aware ainda pode vir sinalizada se discute conteúdo nocivo.
    • +
    • Streaming: os scores chegam só depois que a saída completa está disponível — eles não vêm nos deltas parciais.
    • +
    • Tool calling: a moderação cobre argumentos de tool calls e outputs de tools quando aparecem no conteúdo da conversa; não cobre nomes, descriptions e schemas de tools, nem schemas de response_format.
    • +
    • Falhas: se a etapa de moderação não completar, o campo correspondente (input ou output) pode conter um erro em vez de scores — cheque o tipo do resultado antes de ler flagged.
    • +
    + + +
    + +
    +

    32. Preços

    +

    Os preços abaixo são por 1 milhão de tokens (USD) no tier Standard, salvo quando indicado por minuto/unidade/chamada. Preços são perecíveis: confira sempre a página oficial. Conferência feita em 2026-06-10 direto na tabela oficial (fonte ao final).

    +
    Modelos sem linha própria na tabela oficial. Alguns modelos de áudio — gpt-audio-1.5, gpt-4o-mini-tts, gpt-4o-transcribe-diarize e whisper-1 — não aparecem como linha de preço na página oficial (verificado: a página tem só as seções Realtime and audio generation models e Transcription models, e não há seção de TTS). Eles são cobrados por token nas taxas do endpoint/modelo correspondente. Onde a tabela mostra por token, é esse o regime — não um preço fixo por minuto/caractere publicado.
    + +

    31.1 Modelos de texto / reasoning (Standard)

    +
    + + + + + + + + + + + + +
    ModeloEntradaEntrada em cacheSaída
    gpt-5.6-sol (≤272K; long: 2× in / 1,5× out)$5,00$0,50$30,00
    gpt-5.6-terra$2,50$0,25$15,00
    gpt-5.6-luna$1,00$0,10$6,00
    gpt-5.5 (<272K contexto)$5,00$0,50$30,00
    gpt-5.5-pro (<272K contexto)$30,00—$180,00
    gpt-5.4-mini$0,75$0,075$4,50
    gpt-5.4-nano$0,20$0,02$1,25
    gpt-5.4-pro (<272K contexto)$30,00—$180,00
    +
    +
    Nota: endpoints de processamento regional (residência de dados) têm acréscimo de 10% para modelos lançados a partir de 05/03/2026 elegíveis a data residency (critério oficial do rodapé de pricing — inclui a família gpt-5.6 e os gpt-5.4-mini/-nano, cujas páginas de modelo citam o uplift explicitamente). Tarifas de Batch e Flex equivalem a 50% da tarifa Standard — inclusive para a família 5.6 (Sol $2,50/$15 · Terra $1,25/$7,50 · Luna $0,50/$3).
    + +

    31.2 Priority processing

    +

    O tier Priority oferece latência mais baixa e consistente, cobrado com prêmio sobre o Standard (descontos de cache continuam valendo).

    +
    + + + + + + + + + +
    ModeloEntradaEntrada em cacheSaída
    gpt-5.6-sol$10,00$1,00$60,00
    gpt-5.6-terra$5,00$0,50$30,00
    gpt-5.6-luna$2,00$0,20$12,00
    gpt-5.5$12,50$1,25$75,00
    gpt-5.4-mini$1,50$0,15$9,00
    +
    + +

    31.3 Imagem, realtime e áudio

    +

    Preços por 1M tokens, salvo quando indicado por minuto. Modalidades cobradas separadamente por modelo realtime.

    +
    + + + + + + + + + + + + + +
    ModeloModalidadeEntradaCacheSaída
    gpt-image-2Imagem / textoEstimado por quality+size na calculadora oficial (tabela por imagem na §20). Ex. 1024×1024: low ~$0,006 · medium ~$0,053 · high ~$0,211. Tokens de imagem: $8 entrada / $2 cache / $30 saída.
    gpt-realtime-2.1Áudio$32,00$0,40$64,00
    Texto$4,00$0,40$24,00
    Imagem$5,00$0,50—
    gpt-realtime-2.1-miniÁudio$10,00$0,30$20,00
    Texto$0,60$0,06$2,40
    Imagem$0,80$0,08—
    gpt-realtime-translateÁudio——$0,034 / min
    gpt-audio-1.5Áudio no chatCobrado por token (áudio + texto de entrada/saída) às taxas do modelo — sem linha própria na tabela oficial.
    +
    + +

    31.4 Transcrição e fala

    +
    + + + + + + + + + +
    ModeloEntrada (texto)Saída (texto)Áudio
    gpt-4o-transcribe$2,50$10,00$0,006 / min
    gpt-4o-mini-transcribe$1,25$5,00$0,003 / min
    gpt-4o-transcribe-diarizeCobrado como transcrição (tokens de entrada/saída) — sem linha própria: a tabela Transcription models oficial lista só gpt-4o-transcribe e gpt-4o-mini-transcribe.
    gpt-4o-mini-ttsCobrado por token (texto de entrada + áudio de saída) — sem linha própria: a página oficial não tem seção de TTS.
    whisper-1——$0,006 / min (tarifa histórica; não consta na tabela atual)
    +
    + +

    31.5 Embeddings e moderation

    +
    + + + + + + + +
    ModeloPreço
    text-embedding-3-small$0,02 / 1M tokens
    text-embedding-3-large$0,13 / 1M tokens
    omni-moderation-latestGratuito
    +
    + +

    31.6 Ferramentas integradas

    +
    + + + + + + + + + + +
    FerramentaPreço
    Web search (modelos de reasoning gpt-5.x)$10,00 / 1k chamadas + tokens de conteúdo à taxa do modelo
    Web search (modelos não-reasoning)$25,00 / 1k chamadas (conteúdo gratuito)
    File search — armazenamento$0,10 / GB por dia (1 GB grátis)
    File search — chamada$2,50 / 1k chamadas (somente Responses API)
    Containers (Hosted Shell + Code Interpreter)1 GB $0,03 · 4 GB $0,12 · 16 GB $0,48 · 64 GB $1,92 por 20 min (base de preço) — desde 2026-06-02 a cobrança é por minuto, com mínimo de 5 min por sessão (não se cobra mais o bloco de 20 min inteiro)
    computer-use-preview (modelo dedicado de Computer Use, atual — usado só na Responses API; o gpt-5.x não o substitui para a tool de computer use)$3,00 entrada / $12,00 saída por 1M tokens
    +
    +
    Nota: tokens usados pelas ferramentas integradas são cobrados às taxas por token do modelo escolhido. Responses, Chat Completions, Realtime, Batch e Assistants não são cobradas à parte — você paga apenas os tokens.
    + + +
    + +
    +

    33. Rate limits & tiers

    +

    Rate limits restringem quantas requisições e tokens você pode usar por janela de tempo. São aplicados no nível de organização e de projeto (não por usuário), variam por modelo e podem ser atingidos por qualquer métrica — o que vier primeiro.

    + +

    32.1 Métricas

    +
    + + + + + + + + +
    SiglaSignificado
    RPM / RPDRequisições por minuto / por dia.
    TPM / TPDTokens por minuto / por dia.
    IPMImagens por minuto.
    ÁudioMinutos de áudio por minuto, em alguns modelos de streaming.
    +
    +
    Nota: algumas famílias compartilham limite (qualquer chamada conta para o mesmo pool). Modelos de contexto longo têm limite separado. A ingestão em vector store compartilha 300 RPM por vector_store_id.
    + +

    32.2 Tiers de uso

    +

    À medida que o gasto na API sobe, a organização é promovida automaticamente de tier, aumentando os limites na maioria dos modelos.

    +
    + + + + + + + + + + +
    TierQualificaçãoLimite de gasto
    FreeGeografia permitida$100 / mês
    Tier 1$5 pagos$100 / mês
    Tier 2$50 pagos$500 / mês
    Tier 3$100 pagos$1.000 / mês
    Tier 4$250 pagos$5.000 / mês
    Tier 5$1.000 pagos$200.000 / mês
    +
    + +

    32.3 Headers de limite

    +

    Cada resposta HTTP traz o estado atual do seu limite, útil para implementar backoff proativo:

    +
    + + + + + + + + + + +
    HeaderExemploSignificado
    x-ratelimit-limit-requests60Máximo de requisições permitidas.
    x-ratelimit-limit-tokens150000Máximo de tokens permitidos.
    x-ratelimit-remaining-requests59Requisições restantes.
    x-ratelimit-remaining-tokens149984Tokens restantes.
    x-ratelimit-reset-requests1sTempo até resetar o limite de requisições.
    x-ratelimit-reset-tokens6m0sTempo até resetar o limite de tokens.
    +
    + +

    32.4 Estratégia de backoff/retry

    +

    Para se recuperar de 429 sem falhas, faça retry com backoff exponencial e jitter aleatório (para evitar que retries colidam ao mesmo tempo). Lembre que requisições malsucedidas também contam para o limite, então reenviar em loop não resolve. Outras táticas: reduzir max_tokens para perto do tamanho esperado da resposta; juntar várias tarefas por requisição quando o gargalo é RPM (mas há TPM sobrando); e usar a Batch API para cargas que não precisam de resposta imediata.

    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +from tenacity import retry, stop_after_attempt, wait_random_exponential
    +
    +client = OpenAI()
    +
    +@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
    +def responder(**kwargs):
    +    return client.responses.create(**kwargs)
    +
    +resp = responder(model="gpt-5.5", input="Olá!")
    +print(resp.output_text)
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +// O SDK oficial já aplica retries com backoff automaticamente.
    +const client = new OpenAI({ maxRetries: 6 });
    +
    +const resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Olá!",
    +});
    +console.log(resp.output_text);
    +
    +
    +
    +
    # Inspecione os headers de limite antes de decidir o ritmo das chamadas:
    +curl -i https://api.openai.com/v1/responses \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{ "model": "gpt-5.5", "input": "Olá!" }' \
    +  | grep -i "x-ratelimit"
    +
    +
    +
    + + +
    + +
    +

    34. Batch, Flex & Priority

    +

    O parâmetro service_tier controla o regime de processamento, trocando latência por custo. Além dele, a Batch API oferece um caminho assíncrono de maior throughput.

    + +

    33.1 Batch API

    +

    A Batch API processa grandes grupos de requisições de forma assíncrona com 50% de desconto, um pool de rate limits separado (não consome o limite síncrono por modelo) e prazo de até 24 horas (geralmente menos). Ideal para avaliações, classificação de grandes datasets, geração de embeddings de repositórios e jobs offline.

    +

    Fluxo: monte um arquivo .jsonl (uma requisição por linha, cada uma com custom_id único e body idêntico ao do endpoint-alvo) → faça upload via Files API com purpose="batch" → crie o batch com completion_window="24h" → consulte o status → baixe o output_file_id. Endpoints suportados incluem /v1/responses, /v1/chat/completions, /v1/embeddings, /v1/moderations, /v1/images/generations e /v1/videos.

    +
    + + + + + + + + + +
    LimiteValor
    Requisições por batchAté 50.000
    Tamanho do arquivo de entradaAté 200 MB
    Entradas de embeddings por batchAté 50.000
    Criação de batchesAté 2.000 por hora
    Saída disponívelArquivo de saída apagado 30 dias após a conclusão
    +
    +
    Nota: a ordem das linhas de saída pode não corresponder à de entrada — use sempre o custom_id para mapear. Batches não concluídos a tempo vão para expired; você é cobrado apenas pelas requisições completadas.
    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# 1) upload do .jsonl
    +entrada = client.files.create(file=open("batchinput.jsonl", "rb"), purpose="batch")
    +
    +# 2) cria o batch (janela fixa de 24h)
    +batch = client.batches.create(
    +    input_file_id=entrada.id,
    +    endpoint="/v1/responses",
    +    completion_window="24h",
    +    metadata={"description": "geração noturna de embeddings"},
    +)
    +
    +# 3) consulta o status; 4) ao concluir, baixa o output_file_id
    +batch = client.batches.retrieve(batch.id)
    +if batch.status == "completed":
    +    saida = client.files.content(batch.output_file_id)
    +    print(saida.text)
    +
    +
    +
    +
    import fs from "fs";
    +import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +
    +const entrada = await client.files.create({
    +  file: fs.createReadStream("batchinput.jsonl"),
    +  purpose: "batch",
    +});
    +
    +const batch = await client.batches.create({
    +  input_file_id: entrada.id,
    +  endpoint: "/v1/responses",
    +  completion_window: "24h",
    +});
    +
    +const atual = await client.batches.retrieve(batch.id);
    +if (atual.status === "completed") {
    +  const saida = await client.files.content(atual.output_file_id);
    +  console.log(await saida.text());
    +}
    +
    +
    +
    +
    # upload
    +curl https://api.openai.com/v1/files \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -F purpose="batch" -F file="@batchinput.jsonl"
    +
    +# cria o batch
    +curl https://api.openai.com/v1/batches \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{ "input_file_id": "file-abc123", "endpoint": "/v1/responses", "completion_window": "24h" }'
    +
    +
    +
    + +

    33.2 Flex processing

    +

    Defina service_tier="flex" para custo menor (tarifa de Batch, com desconto adicional de prompt caching) em troca de latência maior e indisponibilidade ocasional de recurso. Ideal para tarefas não produtivas: avaliações, enriquecimento de dados e cargas assíncronas. Está em beta com disponibilidade limitada de modelos.

    +
    Atenção: com Flex, timeouts são mais prováveis — aumente o timeout do SDK (padrão de 10 min). Um 429 Resource Unavailable significa falta de capacidade e não é cobrado; faça retry com backoff, ou retry com service_tier="auto" para cair no processamento padrão.
    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI(timeout=900.0)  # 15 min
    +
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    instructions="Liste e descreva todas as metáforas deste livro.",
    +    input="<texto longo do livro>",
    +    service_tier="flex",
    +)
    +print(resp.output_text)
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI({ timeout: 15 * 60 * 1000 }); // 15 min
    +
    +const resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  instructions: "Liste e descreva todas as metáforas deste livro.",
    +  input: "<texto longo do livro>",
    +  service_tier: "flex",
    +});
    +console.log(resp.output_text);
    +
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "<texto longo do livro>",
    +    "service_tier": "flex"
    +  }'
    +
    +
    +
    + +

    33.3 Priority processing

    +

    Defina service_tier="priority" para latência mais baixa e consistente, mantendo a flexibilidade pay-as-you-go. Ideal para aplicações de alto valor voltadas ao usuário com tráfego regular — não para processamento de dados, avaliações ou tráfego errático. Cobrado com prêmio sobre a padrão; descontos de cache continuam valendo. Pode ser ativado por requisição ou no nível de projeto.

    +
    Atenção: existe um ramp rate limit. Se o tráfego subir rápido demais (≥ 1M TPM e >50% de aumento de TPM em 15 min), parte das requisições é rebaixada para Standard e cobrada como tal — a resposta mostrará service_tier="default". Faça o ramp gradual e evite ETL/batch nesse tier. Contexto longo, modelos fine-tuned e embeddings ainda não são suportados.
    + + +
    + +
    +

    35. Admin APIs

    +

    As Admin APIs automatizam a gestão da organização — convites de usuários, revisão de audit logs, administração de projetos, gestão de chaves, alertas de gasto, retenção de dados, permissões de hosted tools por projeto (/v1/organization/projects/{project_id}/hosted_tool_permissions), itens granulares de cobrança e operações de rate limit — para ferramentas de back-office, fluxos de segurança e tooling operacional fora do dashboard (capacidades expandidas em 26/05/2026).

    +
    Workload Identity Federation (26/05/2026): cargas de trabalho confiáveis podem trocar tokens de identidade externa por tokens de acesso de curta duração da OpenAI API — elimina a necessidade de armazenar API keys de longa duração em CI/CD e infraestrutura.
    + +

    34.1 Chave admin

    +

    Os endpoints sob /v1/organization/... exigem uma Admin API key (criada em Settings → Organization → Admin keys), que não funciona em endpoints comuns. Defina OPENAI_ADMIN_KEY e inicialize o SDK normalmente.

    + +

    34.2 RBAC e acesso a modelo por projeto

    +

    O controle de acesso baseado em papéis (RBAC) governa API e Dashboard com as mesmas permissões. Conceitos: Organização (papéis valem em todos os projetos), Projeto (papéis valem só naquele projeto), Grupos (coleções de usuários, sincronizáveis via SCIM) e Papéis (pacotes de permissões; o acesso de um usuário é a união de seus papéis). Comece pelo princípio do menor privilégio; mudanças de papel podem levar até 30 minutos para propagar.

    +

    Para restringir quais modelos um projeto pode usar, configure model permissions em /v1/organization/projects/{project_id}/model_permissions: defina mode como allow_list (só os modelos listados) ou deny_list (bloqueia os listados, libera os demais).

    + +

    34.3 Alertas de limite de gasto

    +

    Use /v1/organization/projects/{project_id}/spend_alerts para notificar a equipe quando o gasto do projeto atingir um limiar. Os valores são especificados em centavos.

    + +

    34.4 Retenção de dados

    +

    Use /v1/organization/projects/{project_id}/data_retention para sobrescrever ou herdar a política da organização. Defina retention_type="organization_default" para herdar. Por padrão, logs de monitoramento de abuso são retidos por até 30 dias; organizações elegíveis podem solicitar Modified Abuse Monitoring ou Zero Data Retention (ZDR) (sujeito a aprovação prévia da OpenAI). Sob ZDR, o parâmetro store em /v1/responses e /v1/chat/completions é sempre tratado como false.

    + +

    34.5 Convidar usuário e audit logs

    +

    Use /v1/organization/invites para enviar um convite por e-mail à organização (papéis reader ou owner), e /v1/organization/audit_logs para listar ações recentes de usuários e mudanças de configuração — base para auditoria e investigação de segurança.

    +
    +
    + + + +
    +
    +
    import os
    +from openai import OpenAI
    +
    +# Use a chave admin, não a chave de projeto
    +admin = OpenAI(api_key=os.environ["OPENAI_ADMIN_KEY"])
    +
    +# Convidar um usuário como reader
    +admin.organization.invites.create(email="dev@empresa.com.br", role="reader")
    +
    +# Restringir o projeto a um conjunto de modelos
    +admin.organization.projects.model_permissions.create(
    +    project_id="proj_123",
    +    mode="allow_list",
    +    model_ids=["gpt-5.5", "gpt-5.4-mini", "text-embedding-3-large"],
    +)
    +
    +# Alerta de gasto a US$ 50,00 (valor em centavos)
    +admin.organization.projects.spend_alerts.create(
    +    project_id="proj_123", threshold=5000,
    +)
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +const admin = new OpenAI({ apiKey: process.env.OPENAI_ADMIN_KEY });
    +
    +await admin.organization.invites.create({ email: "dev@empresa.com.br", role: "reader" });
    +
    +await admin.organization.projects.modelPermissions.create("proj_123", {
    +  mode: "allow_list",
    +  model_ids: ["gpt-5.5", "gpt-5.4-mini", "text-embedding-3-large"],
    +});
    +
    +await admin.organization.projects.spendAlerts.create("proj_123", { threshold: 5000 });
    +
    +
    +
    +
    # Listar audit logs da organização
    +curl https://api.openai.com/v1/organization/audit_logs \
    +  -H "Authorization: Bearer $OPENAI_ADMIN_KEY"
    +
    +# Restringir modelos de um projeto (allowlist)
    +curl https://api.openai.com/v1/organization/projects/proj_123/model_permissions \
    +  -H "Authorization: Bearer $OPENAI_ADMIN_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{ "mode": "allow_list", "model_ids": ["gpt-5.5", "text-embedding-3-large"] }'
    +
    +
    +
    +
    Atenção: uma Admin API key concede controle amplo sobre a organização. Guarde-a em secret storage, restrinja quem a possui e audite periodicamente. Nunca a exponha em código ou repositórios.
    + + +
    + +
    +

    36. Códigos de erro

    +

    A API retorna erros HTTP padrão; os SDKs oficiais os mapeiam em exceções tipadas. Trate-os programaticamente e aplique backoff onde indicado.

    + +

    35.1 Erros HTTP

    +
    + + + + + + + + + + + + + +
    CódigoCausaComo tratar
    401 Invalid AuthenticationAutenticação inválida.Confirme a API key e a organização correta.
    401 Incorrect API keyChave incorreta, deletada ou de outra org/projeto.Gere uma nova chave e limpe o cache.
    401 IP not authorizedIP fora do allowlist do projeto/organização.Envie do IP correto ou ajuste o IP allowlist.
    403 Country not supportedAcesso de país/região não suportado.Verifique a lista de países suportados.
    429 Rate limit reachedRequisições rápidas demais.Ritme as chamadas; backoff exponencial.
    429 Quota exceededSem créditos ou limite de gasto atingido.Compre créditos ou aumente o limite de uso.
    500 Server errorErro nos servidores da OpenAI.Retry após breve espera; veja a status page.
    503 Engine overloadedTráfego alto.Retry após espera.
    503 Slow DownAumento súbito de tráfego (modelos pay-as-you-go).Reduza ao ritmo original, mantenha 15 min, e suba gradualmente.
    +
    + +

    35.2 Exceções do SDK Python

    +
    + + + + + + + + + + + + + + +
    TipoCausa
    APIConnectionErrorFalha de conexão/rede/proxy/SSL.
    APITimeoutErrorA requisição expirou.
    AuthenticationErrorChave/token inválido, expirado ou revogado.
    BadRequestErrorRequest malformado ou parâmetros faltando.
    ConflictErrorRecurso atualizado por outra requisição.
    InternalServerErrorProblema no lado da OpenAI.
    NotFoundErrorRecurso solicitado não existe.
    PermissionDeniedErrorSem acesso ao recurso pedido.
    RateLimitErrorLimite de taxa atingido.
    UnprocessableEntityErrorNão foi possível processar apesar do formato correto.
    +
    +
    Nota: no WebSocket mode da Responses API você também pode ver previous_response_not_found (refaça com contexto completo e previous_response_id=null) e websocket_connection_limit_reached (conexão atingiu 60 min; abra uma nova).
    + + +
    + +
    +

    37. Checklist de produção

    +

    Ao levar uma aplicação para produção, estas alavancas melhoram qualidade, custo, latência e confiabilidade. Cada item é cumulativo e configurável na Responses API.

    + +
    + + + + + + + + + + + + + + + +
    ItemImpacto
    Usar a Responses APIQualidade, custo, latência, confiabilidade
    reasoning.effortQualidade, custo, latência
    text.verbosityQualidade, custo, latência
    Parâmetro phase do assistantQualidade, custo
    tool_searchCusto, latência
    Ferramentas nativas (built-in tools)Qualidade
    CompactionCusto
    prompt_cache_keyLatência, custo
    reasoning.encrypted_contentQualidade, latência
    background=TrueResumabilidade
    WebSocket modeLatência
    +
    + +

    36.1 Responses API como base

    +

    Sempre comece pela Responses API: é a API principal e o melhor lugar para acessar o comportamento mais recente dos modelos, ferramentas nativas, fluxos com estado e recursos de agente.

    + +

    36.2 reasoning.effort e text.verbosity

    +

    Para gpt-5.5, reasoning.effort aceita none, low, medium (padrão), high e xhigh. Use low para extração, roteamento, classificação ou reescrita simples; medium/high para diagnosticar, comparar opções, planejar ou raciocinar sobre código; reserve xhigh para quando suas avaliações mostrarem que a latência extra compensa. O text.verbosity equilibra concisão (menos tokens de saída, resposta mais rápida) contra completude.

    + +

    36.3 phase, tool_search e ferramentas nativas

    +

    O phase rotula mensagens do assistant como "commentary" (notas/progresso intermediário) ou "final_answer" (resposta concluída); preserve e reenvie esse campo no histórico em fluxos longos para evitar parada precoce. O tool_search (com defer_loading: true nas ferramentas caras) carrega só o subconjunto necessário em runtime, poupando tokens e preservando o cache — comece com hosted tool search e mantenha namespaces com até ~10 funções. Prefira ferramentas nativas (web search, file search, code interpreter, shell, computer use, image generation, MCP/connectors, skills, apply patch): por estarem em distribuição no pós-treino, têm melhor seleção e menos falhas.

    + +

    36.4 Compaction e prompt caching

    +

    A compaction reduz o tamanho do contexto preservando o estado necessário entre muitos turnos — deixe o servidor cuidar (com previous_response_id + context_management e compact_threshold) ou chame client.responses.compact() e reaproveite a saída como está (não edite). O prompt caching reduz latência e custo quando requisições reusam o mesmo prefixo longo: defina prompt_cache_key de forma consistente para prefixos genuinamente compartilhados, mas com granularidade que evite concentrar tráfego — acima de ~15 req/min num mesmo par prefixo+chave, o cache perde eficácia.

    + +

    36.5 Reasoning encrypted, background e WebSocket

    +

    Sempre faça round-trip dos itens de reasoning. Sob requisitos de ZDR (sem armazenar dados de resposta), adicione reasoning.encrypted_content ao include e devolva o item exatamente como veio para um handoff sem estado. Use background=True (requer store=True; incompatível com ZDR) para jobs longos: a API retorna um ID e você faz polling. Use WebSocket mode para fluxos longos e pesados em tool calls — mantendo a conexão aberta e continuando com previous_response_id e apenas os novos itens; em rollouts com 20+ tool calls fica ~40% mais rápido. Uma conexão trata uma resposta por vez e expira em 60 min; funciona com ZDR (dados só em memória).

    +
    +
    + + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    input="Refatore este módulo e explique as decisões.",
    +    reasoning={"effort": "high", "encrypted_content": True},
    +    text={"verbosity": "medium"},
    +    prompt_cache_key="refactor-service-v1",
    +    background=True,
    +    store=True,
    +)
    +print(resp.id, resp.status)   # faça polling por resp.id até completar
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +
    +const resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Refatore este módulo e explique as decisões.",
    +  reasoning: { effort: "high", encrypted_content: true },
    +  text: { verbosity: "medium" },
    +  prompt_cache_key: "refactor-service-v1",
    +  background: true,
    +  store: true,
    +});
    +console.log(resp.id, resp.status);
    +
    +
    +
    +
    curl https://api.openai.com/v1/responses \
    +  -H "Authorization: Bearer $OPENAI_API_KEY" \
    +  -H "Content-Type: application/json" \
    +  -d '{
    +    "model": "gpt-5.5",
    +    "input": "Refatore este módulo e explique as decisões.",
    +    "reasoning": { "effort": "high" },
    +    "text": { "verbosity": "medium" },
    +    "prompt_cache_key": "refactor-service-v1",
    +    "background": true,
    +    "store": true
    +  }'
    +
    +
    +
    + + +
    + +
    +

    Referência rápida de endpoints

    +

    Base: https://api.openai.com/v1. Principais endpoints usados ao longo deste guia.

    +
    + + + + + + + + + + + + + + + +
    Método + caminhoDescrição
    POST /v1/responsesAPI principal para texto, multimodal, reasoning e ferramentas (com estado).
    POST /v1/embeddingsGera vetores de embedding para busca, RAG, clustering.
    POST /v1/moderationsClassifica conteúdo nocivo em texto e imagem (gratuito).
    POST /v1/audio/transcriptionsTranscreve áudio para texto (STT).
    POST /v1/audio/translationsTraduz áudio para inglês.
    POST /v1/audio/speechSintetiza fala a partir de texto (TTS).
    POST /v1/images/generationsGera imagens.
    POST /v1/images/editsEdita imagens existentes.
    GET /v1/realtime / POST /v1/realtime/callsSessões realtime (speech-to-speech, transcrição, tradução).
    POST /v1/batchesCria jobs assíncronos com 50% de desconto e janela de 24h.
    POST /v1/filesFaz upload de arquivos (batch, fine-tuning, entradas).
    +
    + +
    + +
    +

    Tabela de IDs de modelo

    +

    IDs exatos dos modelos atuais cobertos neste guia. Trate IDs e preços como perecíveis: confirme na doc oficial antes de usar em produção.

    +
    + + + + + + + + + + + + + + + + + + + + + + +
    IDTipo / usoEndpoint(s)Parte
    gpt-5.5Frontier de reasoning/coding (effort: none–xhigh)/v1/responsesA
    gpt-5.5-proVariante pro (raciocínio máximo); preço premium/v1/responsesA
    gpt-5.3-codexModelo especializado em código (Codex)/v1/responsesA
    gpt-5.4-miniTexto rápido/barato/v1/responsesA
    gpt-5.4-nanoTexto de menor latência/custo/v1/responsesA
    gpt-image-2Geração e edição de imagem/v1/images/*B
    gpt-realtime-2.1Realtime speech-to-speech/v1/realtimeC
    gpt-realtime-translateTradução em realtime/v1/realtime/translationsC
    gpt-realtime-whisperTranscrição em streaming (realtime)/v1/realtime/transcription_sessionsC
    gpt-4o-transcribeSTT de arquivo/v1/audio/transcriptionsC
    gpt-4o-mini-transcribeSTT de arquivo (mais barato)/v1/audio/transcriptionsC
    gpt-4o-transcribe-diarizeSTT com diarização (rótulo de falantes)/v1/audio/transcriptionsC
    gpt-4o-mini-ttsSíntese de fala (TTS)/v1/audio/speechC
    gpt-audio-1.5Áudio no chat/v1/chat/completionsC
    whisper-1Tradução de áudio e timestamps (srt/vtt/verbose_json, word-level)/v1/audio/translations, /v1/audio/transcriptionsC
    text-embedding-3-smallEmbeddings (1536 dim)/v1/embeddingsD
    text-embedding-3-largeEmbeddings (3072 dim)/v1/embeddingsD
    omni-moderation-latestModeration multimodal (gratuito)/v1/moderationsD
    +
    + +
    + +
    +

    Glossário

    +
    + + + + + + + + + + + + + + + + + +
    TermoDefinição
    Responses APIAPI principal da OpenAI para texto/multimodal/tools, com estado e ferramentas nativas (/v1/responses).
    reasoning effortQuanto o modelo raciocina antes de responder. Enum da API: none·minimal·low·medium·high·xhigh·max (model-dependent; max na família 5.6). Mais esforço = mais latência e tokens de reasoning.
    verbosityAlavanca de concisão vs. completude da saída (low/medium/high).
    prompt cachingReuso automático de prefixos longos para reduzir latência e custo; direcionado por prompt_cache_key.
    compactionRedução controlada do contexto preservando o estado necessário entre turnos.
    VADVoice Activity Detection — detecção de atividade de voz que define os limites de corte do áudio.
    diarizaçãoIdentificação e rotulagem de quem fala em cada trecho do áudio.
    embeddingsVetores numéricos que representam o significado de um texto; distância = relação semântica.
    moderationClassificação de conteúdo potencialmente nocivo em categorias com pontuação de confiança.
    batchProcessamento assíncrono em lote com 50% de desconto e janela de 24h.
    flexservice_tier de menor custo e maior latência, para cargas não produtivas.
    priorityservice_tier de latência baixa e consistente, cobrado com prêmio.
    service tierRegime de processamento de uma requisição: auto, default, flex ou priority.
    +
    + +
    + +
    +

    Receitas oficiais (Cookbook) — RAG, embeddings, avaliação & operação

    +

    Exemplos oficiais do OpenAI Cookbook (e do repositório openai/openai-cookbook) para embeddings, RAG, avaliação e operação. Lidos e classificados em 2026-05-24 quanto a aderência ao estado da arte.

    +
    + + + + + + + + + + + + +
    ReceitaO que ensinaStatus
    Prompt Caching 201prompt_cache_key como chave de shard; Flex vs Batch; caso real de 60%→87% de hit-rate.SOTA
    api_request_parallel_processor.pyScript de produção para processar lotes mantendo-se sob RPM/TPM (backoff).SOTA
    Multi-tool orchestration + RAG (Responses API)Rotear entre web_search, file_search e vector DB num único loop Responses.SOTA
    Evals — regressão / bulk / monitoramentoAcompanhar desempenho de prompts entre iterações; comparar muitos prompts/modelos; detectar regressões em produção. Atenção: a deprecação da plataforma Evals foi anunciada em 2026-06-03 — planeje migração antes de adotar.Deprecação anunciada
    Busca semântica com Supabase / pgvectorRAG self-hosted: Postgres + pgvector, índice HNSW, operador <#> (inner product, vetores unit-norm).SOTA
    Question answering using embeddingsRAG clássico "Search-Ask": embeda corpus, top-k por cosseno, injeta contexto e responde.Portar p/ Responses
    Embedding long inputsLidar com entradas > 8192 tokens: truncar vs. dividir-e-mediar com tiktoken.Técnica atual
    Semantic text searchBusca semântica mínima por cosseno sobre um dataset.Legado
    +
    +
    Ao portar receitas antigas: várias usam Chat Completions e helpers descontinuados (utils.embeddings_utils) ou embeddings de gerações anteriores. No estado da arte, use a Responses API com gpt-5.x e embeddings text-embedding-3-small/-3-large; calcule similaridade com numpy/JS puro em vez do embeddings_utils.
    + +

    Código real, modernizado para o estado da arte

    +

    Três receitas portadas para o estado da arte: embeddings text-embedding-3-small com cosseno calculado em numpy/JS puro (sem o embeddings_utils descontinuado) e geração/roteamento via Responses API com gpt-5.5. Troque os corpora de exemplo pelos seus dados.

    + +

    1. Embeddings + busca semântica (top-k por cosseno) · porta modernizada de Semantic_text_search_using_embeddings.ipynb

    +
    +
    + + +
    +
    +
    import numpy as np
    +from openai import OpenAI
    +
    +client = OpenAI()
    +MODELO_EMB = "text-embedding-3-small"
    +
    +# Corpus de exemplo (troque pelos seus documentos)
    +corpus = [
    +    "O pinguim-imperador é a maior espécie de pinguim.",
    +    "A fotossíntese converte luz solar em energia química.",
    +    "Python é uma linguagem de programação de alto nível.",
    +    "Os Jogos Olímpicos de Inverno de 2022 ocorreram em Pequim.",
    +]
    +
    +def embeddings(textos: list[str]) -> np.ndarray:
    +    # Embeddings da OpenAI já vêm normalizados (norma 1): cosseno = produto interno
    +    resp = client.embeddings.create(model=MODELO_EMB, input=textos)
    +    return np.array([d.embedding for d in resp.data])
    +
    +corpus_emb = embeddings(corpus)
    +
    +def busca(consulta: str, k: int = 3):
    +    q = embeddings([consulta])[0]
    +    sims = corpus_emb @ q                 # similaridade de cosseno (vetores unit-norm)
    +    ordem = np.argsort(-sims)[:k]         # top-k em ordem decrescente
    +    return [(corpus[i], float(sims[i])) for i in ordem]
    +
    +for texto, score in busca("Quem venceu em Pequim 2022?"):
    +    print(f"{score:.3f}  {texto}")
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +const MODELO_EMB = "text-embedding-3-small";
    +
    +// Corpus de exemplo (troque pelos seus documentos)
    +const corpus = [
    +  "O pinguim-imperador é a maior espécie de pinguim.",
    +  "A fotossíntese converte luz solar em energia química.",
    +  "JavaScript é a linguagem da web.",
    +  "Os Jogos Olímpicos de Inverno de 2022 ocorreram em Pequim.",
    +];
    +
    +// Embeddings da OpenAI já vêm normalizados (norma 1): cosseno = produto interno
    +async function embeddings(textos) {
    +  const resp = await client.embeddings.create({ model: MODELO_EMB, input: textos });
    +  return resp.data.map((d) => d.embedding);
    +}
    +const dot = (a, b) => a.reduce((s, v, i) => s + v * b[i], 0);
    +
    +const corpusEmb = await embeddings(corpus);
    +
    +async function busca(consulta, k = 3) {
    +  const [q] = await embeddings([consulta]);
    +  return corpus
    +    .map((texto, i) => ({ texto, score: dot(corpusEmb[i], q) }))
    +    .sort((a, b) => b.score - a.score)
    +    .slice(0, k);
    +}
    +
    +for (const { texto, score } of await busca("Quem venceu em Pequim 2022?")) {
    +  console.log(score.toFixed(3), texto);
    +}
    +
    +
    +
    + +

    2. RAG "Search-Ask": recupera contexto e responde via Responses API · porta do passo de resposta para a Responses API a partir de question_answering_using_embeddings

    +
    +
    + + +
    +
    +
    import numpy as np
    +from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# Reaproveita corpus_emb / busca() do exemplo anterior (text-embedding-3-small)
    +def responder(pergunta: str, k: int = 3) -> str:
    +    trechos = [texto for texto, _ in busca(pergunta, k)]   # top-k por cosseno
    +    contexto = "\n".join(f"- {t}" for t in trechos)
    +    prompt = (
    +        "Use APENAS o contexto abaixo para responder. "
    +        'Se a resposta não estiver no contexto, diga "Não sei.".\n\n'
    +        f"Contexto:\n{contexto}\n\nPergunta: {pergunta}"
    +    )
    +    # Geração no estado da arte: Responses API + gpt-5.5 (sem Chat Completions)
    +    resp = client.responses.create(model="gpt-5.5", input=prompt)
    +    return resp.output_text
    +
    +print(responder("Onde ocorreram os Jogos de Inverno de 2022?"))
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +
    +// Reaproveita corpusEmb / busca() do exemplo anterior (text-embedding-3-small)
    +async function responder(pergunta, k = 3) {
    +  const trechos = (await busca(pergunta, k)).map((r) => r.texto); // top-k por cosseno
    +  const contexto = trechos.map((t) => `- ${t}`).join("\n");
    +  const prompt =
    +    "Use APENAS o contexto abaixo para responder. " +
    +    'Se a resposta não estiver no contexto, diga "Não sei.".\n\n' +
    +    `Contexto:\n${contexto}\n\nPergunta: ${pergunta}`;
    +  // Geração no estado da arte: Responses API + gpt-5.5 (sem Chat Completions)
    +  const resp = await client.responses.create({ model: "gpt-5.5", input: prompt });
    +  return resp.output_text;
    +}
    +
    +console.log(await responder("Onde ocorreram os Jogos de Inverno de 2022?"));
    +
    +
    +
    + +

    3. Orquestração multiferramenta: web_search + file_search numa única chamada · o modelo roteia entre web e a vector store; shapes oficiais de tools-web-search + tools-file-search

    +
    Por que isto é válido: o parâmetro tools da Responses API é um array que aceita várias ferramentas de tipos diferentes; com tool_choice em auto (padrão), o modelo decide quais acionar. A própria doc descreve o modelo podendo "buscar na web, recuperar dos seus arquivos … e chamar suas funções" no mesmo fluxo. Cada shape de ferramenta aqui é oficial e individual; combiná-las num único array é o mecanismo documentado (não um formato especial). Você pode forçar com tool_choice: "required" quando a busca tiver de rodar.
    +
    +
    + + +
    +
    +
    from openai import OpenAI
    +
    +client = OpenAI()
    +
    +# Uma única chamada com DUAS ferramentas hospedadas; o modelo decide qual usar.
    +# web_search -> fatos atuais da internet; file_search -> sua base privada (vector store).
    +resp = client.responses.create(
    +    model="gpt-5.5",
    +    input="Compare nossa política interna de reembolso com as melhores práticas atuais do setor.",
    +    tools=[
    +        {"type": "web_search"},
    +        {"type": "file_search", "vector_store_ids": ["vs_seu_id_aqui"]},
    +    ],
    +)
    +
    +print(resp.output_text)
    +# resp.output traz os itens web_search_call / file_search_call que o modelo acionou
    +
    +
    +
    +
    import OpenAI from "openai";
    +
    +const client = new OpenAI();
    +
    +// Uma única chamada com DUAS ferramentas hospedadas; o modelo decide qual usar.
    +// web_search -> fatos atuais da internet; file_search -> sua base privada (vector store).
    +const resp = await client.responses.create({
    +  model: "gpt-5.5",
    +  input: "Compare nossa política interna de reembolso com as melhores práticas atuais do setor.",
    +  tools: [
    +    { type: "web_search" },
    +    { type: "file_search", vector_store_ids: ["vs_seu_id_aqui"] },
    +  ],
    +});
    +
    +console.log(resp.output_text);
    +// resp.output traz os itens web_search_call / file_search_call que o modelo acionou
    +
    +
    +
    + + +
    + +
    +

    Histórico deste guia

    +
    + + + + + + + + + + +
    DataAlteração
    2026-05-24Versão inicial; modelos verificados na doc oficial.
    2026-05-24Preços de áudio verificados na tabela oficial (Realtime/Transcription); modelos sem linha própria explicitados. Adicionado código real do Cookbook (Python + JavaScript) em cada parte. Fechadas lacunas in-scope: input_file (PDF/documentos/planilhas), gpt-5.5-pro/gpt-5.4-pro, ponteiro gpt-5.3-codex, campo safety_identifier.
    2026-05-24Resolvidos os 2 itens pendentes: file_search usa purpose="assistants" (valor documentado para ingestão em vector store, confirmado no Cookbook + OpenAPI); orquestração web_search+file_search documentada como mecanismo de array de ferramentas (cada shape oficial; modelo roteia via tool_choice: auto). Zero itens UNVERIFIED de preço/código restantes.
    2026-06-25Adicionados gpt-image-1-mini (imagem econômica) e gpt-4o-tts (TTS completo) na tabela de modelos e nas seções de referência. Nota de sunset gpt-image-1 (2026-10-23 → migrar para gpt-image-2) e snapshot gpt-4o-mini-tts-2025-03-20 (sunset 2026-07-23 → migrar para gpt-4o-mini-tts-2025-12-15). Nota de depreciação de 2026-06-11: snapshots gpt-5-2025-08-07, gpt-5-mini-2025-08-07, gpt-5-nano-2025-08-07, gpt-5-pro-2025-10-06, o3-2025-04-16 e o3-pro-2025-06-10 encerram em 2026-12-11 (substitutos: gpt-5.5 / gpt-5.4-mini / gpt-5.4-nano / gpt-5.5-pro). Verificado em developers.openai.com/api/docs/deprecations.
    2026-06-29Varredura de freshness (changelogs oficiais reverificados): gpt-image-1-mini, gpt-image-1.5 e chatgpt-image-latest com sunset 2026-12-01 (anunciado 2026-06-02 → migrar para gpt-image-2); SDK openai 2.44.0 (Python) / 6.45.0 (Node). Confirmados gpt-5.5 como flagship recomendado e gpt-image-2 como default de imagem. Sunsets adicionais verificados: Assistants API 2026-08-26; Evals/Agent Builder/v1-prompts 2026-11-30; gpt-4.1-nano/o1/o3-mini/o4-mini 2026-10-23; Sora 2 / Videos API 2026-09-24. Fonte: developers.openai.com/api/docs/deprecations.
    2026-06-10Varredura de atualização contra doc oficial: billing de containers (Hosted Shell/Code Interpreter) agora é por minuto com mínimo de 5 min por sessão (mudança de 2026-06-02; taxas por 20 min seguem como base de preço); default de prompt_cache_retention passou a 24h para organizações sem ZDR em v1/responses, v1/chat/completions e v1/batch (mudança de 2026-05-29); deprecação da plataforma Evals anunciada em 2026-06-03 sinalizada na tabela do Cookbook; IDs de Embeddings/Moderation preenchidos no catálogo §1.2 (text-embedding-3-small/-large, omni-moderation-latest); marcadores de verificação atualizados para 2026-06-10.
    +
    + +
    + + +
    +
    + + + + + + diff --git a/references/agents_tools_best_guides/guia_providers_adapters.html b/references/agents_tools_best_guides/guia_providers_adapters.html index e4e7521..6204035 100644 --- a/references/agents_tools_best_guides/guia_providers_adapters.html +++ b/references/agents_tools_best_guides/guia_providers_adapters.html @@ -1,914 +1,914 @@ - - - - - -Providers & adapters — camada de portabilidade entre OpenAI, Anthropic e Google - - - - - - - - -
    -
    -
    Providers & adapters Núcleo · portabilidade entre providers
    -
    - Verificado em 2026-07-09 - Super-guia de Agentes - PT-BR - -
    -
    -
    - -
    - - -
    - -
    -

    Providers & adapters

    -

    - A camada de portabilidade do super-guia. Aqui o foco é agnóstico: o papel de cada SDK, - o provider switching contract com declaração de perdas, a equivalência de roles e - instruções, a matriz de comportamento entre OpenAI, Anthropic e Google, e structured outputs - cross-provider. Os parâmetros específicos de cada API ficam nos guias dedicados — este capítulo é a - cola entre eles. Prosa em PT-BR; identificadores, classes e código em inglês. -

    -
    - Super-guia de Agentes - PT-BR - SOTA · verificado 2026-06-29 -
    -
    - -
    -

    Sobre este guia

    -

    - Este capítulo do núcleo trata a aplicação como dona de um contrato canônico e cada - provider como uma projeção desse contrato. O objetivo não é reexplicar a API de cada - provedor — é dar o adapter que converte um modelo canônico (ledger, capabilities, schemas, - roles) para OpenAI Responses/Agents SDK, Anthropic Messages e Google GenAI/Gemini, tornando explícitas - as perdas em cada troca. -

    -
    - Para IA e humanos: use as tabelas como referência de consulta (parâmetros, roles, - comportamento por provider) e os contratos JSON como esquema copy-paste. Cada afirmação perecível - (IDs de modelo, nomes de parâmetro, versão de spec) é conferida na seção - Notas de verificação contra a folha de fatos SOTA do super-guia. -
    -
    - Onde aprofundar cada API: parâmetros completos da Responses API → - guia_openai_modelos; Messages API e blocos de tool/thinking → - guia_claude_api; Interactions API e google-genai → - guia_gemini_interactions_api; runtime do Agents SDK → - guia_agents_sdk e - guia_agents_sdk_orquestracao. -
    -
    - -
    -

    A tese do adapter

    -

    - Trocar de provider deve ser uma operação declarada, nunca transparente. Um sistema que - "só troca o nome do modelo" mente para si mesmo: roles não têm equivalência perfeita, carriers de - reasoning são opacos e específicos, budgets se comportam de forma distinta e o estado servidor de um - provider não existe no outro. O adapter resolve isso projetando o contrato canônico e produzindo uma - loss declaration a cada conversão. -

    -
    - - Contrato canônico projetado para três providers - Um modelo canônico no centro (ledger, capabilities, schemas, roles) é convertido por um adapter para OpenAI, Anthropic e Google, cada conversão emitindo uma declaração de perdas. - - Contrato canônico - ledger · capabilities · schemas - roles · assets · budgets - - adapter - - - - OpenAI - Responses / Agents SDK - - Anthropic - Messages API - - Google - GenAI / Gemini - - - - - - - - ↯ loss - ↯ loss - ↯ loss - - -
    O adapter é o único ponto que conhece dialeto de provider. O produto fala o contrato canônico; cada projeção declara o que foi preservado, transformado e perdido.
    -
    -
    - -
    -

    Parte 1 — SDKs & parâmetros

    -

    O papel de cada camada, os parâmetros da Responses API que importam para a orquestração, e quando o - Agents SDK ou o Pydantic AI entram. Detalhe completo de cada API fica nos guias dedicados.

    -
    - -
    -

    1. Papel de cada SDK/framework

    -

    Cada camada tem um papel; o erro comum é confundir um provider adapter com um banco de estado - durável, ou um framework de runtime com governança de negócio. A tabela separa uso recomendado de - "não confundir com".

    -
    - - - - - - - - - -
    CamadaUso recomendadoNão confundir com
    OpenAI Agents SDK (openai-agents)Runtime de agentes com tools, handoffs, guardrails, sessions, tracing e MCP. Uma das bases recomendadas no ecossistema OpenAI.Banco de estado durável universal ou substituto de políticas de negócio.
    OpenAI Responses APIInterface direta para controle fino de input, tools, estado, reasoning, structured outputs, truncation e loop próprio.Framework de governança; o cliente ainda valida, executa tools e mantém o ledger.
    OpenAI Python SDK (openai)Cliente oficial para chamar a API OpenAI.Orquestrador por si só.
    Anthropic SDK / Messages API (anthropic)Provider adapter para Claude: tools (tool_use/tool_result) e thinking (adaptive/extended).Mesma semântica de roles/tokens/reasoning da OpenAI.
    Google GenAI SDK (google-genai)Provider adapter para Gemini: function calling, files, structured output e thought signatures.Estado durável automático em todo cenário; SDKs legados (google-generativeai).
    Pydantic AI (pydantic-ai)Camada complementar de agentes tipados, output estruturado, deps, evals, observabilidade e wrappers model-agnostic.Substituto obrigatório do Agents SDK; use onde agrega validação/typing/evals.
    -
    - Pin de versões (2026-06-29): openai-agents 0.17.7 (release 2026-06-24; pré-1.0; superfície ainda - evolui; piso openai>=2.36.0,<3 desde a 0.17.4; SDK openai 2.44.0 / @openai/agents 0.12.0), - anthropic 0.113.0, google-genai 2.10.0, pydantic-ai 2.1.0 (série 2.x estável, lançada 2026-06-23; a 2.x traz mudanças incompatíveis — ex.: prefixo openai: passa a usar a Responses API, builtin_tools→native_tools, end_strategy default early→graceful; houve sim série 1.x, de 1.0.0 a 1.99.0, antes da 2.0). - Confirme antes de fixar — ver Notas de verificação. -
    -
    - -
    -

    2. OpenAI Responses API: parâmetros críticos

    -

    Para a orquestração, estes são os campos que mais influenciam controle de fase, estado e budget. A - referência completa (anatomia da Responses, function calling, streaming) está em - guia_openai_modelos.

    -
    - - - - - - - - - - - - - - -
    Parâmetro/campoUsoCuidado
    inputItens de entrada multimodais/projetados do ledger.Não jogar corpus bruto sem caps de budget.
    instructionsInstruções da chamada atual.Com previous_response_id, não assuma carry-over de instructions anteriores.
    toolsBuilt-ins, MCP e function tools.Exponha apenas as allowed tools da fase.
    tool_choiceauto / required / específico / none.Trava fase, não é a única camada de segurança.
    parallel_tool_callsPermite múltiplas function calls numa resposta.A execução paralela é do runtime; built-ins têm restrições.
    max_tool_callsLimite de tool calls hospedadas na resposta.Não substitui o max turns do orquestrador.
    max_output_tokensLimita tokens visíveis + reasoning conforme o modelo.Reserve orçamento para reasoning e resposta final.
    previous_response_idEncadeia o estado servidor da resposta anterior.Não é ledger; não combine com conversation na mesma cadeia.
    conversationObjeto de conversa stateful gerido pelo servidor.Avalie retenção/política de dados; é projeção, não fonte da verdade.
    storetrue persiste a resposta (necessário p/ previous_response_id).Para ZDR/stateless, use store=false e devolva os output items.
    truncationauto / disabled.Truncation automática pode remover contexto crítico silenciosamente.
    -
    - Reasoning stateless (ZDR): para preservar o reasoning entre turnos sem armazenamento - no servidor, combine store=false com include=["reasoning.encrypted_content"] - e devolva o conteúdo cifrado a cada turno. Confira o nome exato do campo na doc atual da Responses API. -
    -
    - -
    -

    3. OpenAI Agents SDK: quando usar como base

    -

    Use o Agents SDK quando o projeto se beneficia de loop de agentes, guardrails, handoffs, - agents-as-tools, sessions, tracing e MCP em código Python-first. A doc oficial o posiciona como - framework leve e recomenda a Responses API direta quando você quer possuir manualmente o loop, - o dispatch de tools e o estado. É uma base recomendada — LangGraph e Google ADK são - alternativas legítimas (ver os guias de framework do super-guia).

    -
    from agents import Agent, Runner, function_tool
    -
    -@function_tool
    -def lookup_policy(topic: str) -> str:
    -    # Chame sua capability real; reduza o output antes de devolver ao agente.
    -    return "síntese com provenance"
    -
    -specialist = Agent(
    -    name="evidence_specialist",
    -    instructions="Responda apenas com evidências tipadas e limitações.",
    -    tools=[lookup_policy],
    -)
    -
    -manager = Agent(
    -    name="orchestrator",
    -    instructions="Planeje, delegue quando necessário e sintetize com fontes.",
    -    tools=[specialist.as_tool(
    -        tool_name="consult_evidence_specialist",
    -        tool_description="Consulta o especialista de evidências; retorna síntese tipada com limitações.",
    -    )],
    -)
    -
    -result = Runner.run_sync(manager, "Pergunta do usuário")
    -print(result.final_output)
    - -

    Mesmo quando o SDK gerencia o loop, mantenha registro externo de traces, usage, tool results e - decisões críticas se o sistema precisa ser auditável — o ledger canônico é seu, não do framework.

    -
    - -
    -

    4. Pydantic AI como camada complementar

    -

    O Pydantic AI brilha nas bordas tipadas: dependências, output estruturado, validação de ferramentas, - evals, observabilidade (Logfire) e wrappers model-agnostic. Convive com o Agents SDK — use Pydantic para - schemas/evals/validadores, o Agents SDK para orquestração/handoffs, e a Responses API direta nos pontos - de controle fino. Nenhum outro guia do conjunto cobre o Pydantic AI, então ele mora aqui.

    -
    from pydantic import BaseModel, Field
    -
    -class EvidenceItem(BaseModel):
    -    source_id: str
    -    claim: str
    -    confidence: float = Field(ge=0, le=1)
    -
    -class SpecialistOutput(BaseModel):
    -    answerable: bool
    -    summary: str
    -    evidence: list[EvidenceItem]
    -    missing: list[str] = []
    -
    -# Use este modelo como contrato de saída de subagente/tool/eval,
    -# independentemente do provider que gerou a resposta.
    - -
    - -
    -

    Parte 2 — Adapters por provider

    -

    O ângulo aqui é de projeção/adapter — o "como o contrato canônico vira chamada deste provider". A API - real de cada um está nos guias dedicados.

    -
    - -
    -

    5. Anthropic adapter

    -

    No adapter Anthropic, trate tool use como blocos estruturados: o modelo emite tool_use, - o cliente executa a tool e devolve tool_result (numa mensagem de role user), - com stop_reason: tool_use. Para thinking, preserve os blocos/assinaturas conforme as regras - de contexto e tool-use. A API completa está em guia_claude_api.

    -
    - - - - - - - - - -
    AspectoRegra prática
    Rolessystem top-level + messages alternando user/assistant; adapte developer/instructions com cuidado.
    ToolsSchemas explícitos (input_schema); tool_choice específico quando a chamada é obrigatória.
    ThinkingOpus 4.8 só adaptive; Fable 5 adaptive sempre ativo (type:"disabled" e budget manual retornam 400); Haiku 4.5 só enabled (budget); Sonnet 4.6 ambos. Preserve assinaturas quando exigidas.
    Structured outputoutput_config.format (json_schema) nativo — não use response_format (padrão OpenAI).
    ContextMeça thinking/contexto; compacte antes do overflow. Opus 4.8/Sonnet 4.6/Fable 5 = 1M (Fable 5 com 128k max output); Haiku 4.5 = 200K.
    Provider switchDeclare perdas quando carriers de reasoning da OpenAI ou thought signatures do Gemini não têm equivalente direto.
    -
    - -
    -

    6. Google GenAI/Gemini adapter

    -

    No adapter Google, use o SDK oficial google-genai (não os SDKs legados). A chamada - canônica de geração é client.models.generate_content(...) — é o caminho atual e correto, não - legado. A Interactions API é uma abstração adicional - (recurso de interação stateful/por passos) que você usa quando precisa desse modelo de estado, não um - substituto da chamada de baixo nível. Em function calling com thought signatures, - preserve as parts exatamente como retornadas — a doc enfatiza passback intacto e regras - específicas para chamadas paralelas/sequenciais.

    -
    - - - - - - - - - -
    AspectoRegra prática
    SDKfrom google import genai; genai.Client() + client.models.generate_content(...).
    Function callingModos AUTO/ANY/NONE; automatic function calling no SDK Python quando apropriado.
    Thought signaturesPreserve parts/signatures; não concatene nem reordene manualmente. Obrigatório devolver as de function calling.
    Thinkingthinking_level (low/medium/high; Flash/Lite ainda têm minimal) — não o legado thinking_budget; não misture os dois (erro 400).
    Structured outputresponse_mime_type="application/json" + response_json_schema.
    Documentos/filesAPIs de files/document processing com asset registry próprio.
    -
    - -
    -

    7. Structured outputs cross-provider

    -

    Para saídas críticas, prefira structured outputs com JSON Schema/Pydantic em vez de pedir - "responda em JSON" por prompt. Os três providers oferecem o mecanismo, com nomes diferentes — o contrato - canônico é o mesmo schema; o adapter só muda o campo da chamada.

    -
    - - - - - - - -
    ProviderMecanismoCampo da chamada
    OpenAIStructured Outputstext.format (json_schema)
    AnthropicStructured outputs nativooutput_config.format (json_schema)
    Google GeminiStructured outputresponse_json_schema + response_mime_type
    Pydantic AIOutput validado (qualquer provider)output_type=Model
    -
    {
    -  "type": "object",
    -  "additionalProperties": false,
    -  "required": ["decision", "rationale", "evidence", "risks"],
    -  "properties": {
    -    "decision": {"type": "string", "enum": ["approve", "reject", "needs_human"]},
    -    "rationale": {"type": "string", "maxLength": 1200},
    -    "evidence": {"type": "array", "items": {"type": "object"}},
    -    "risks": {"type": "array", "items": {"type": "string"}}
    -  }
    -}
    -
    - Regra de ouro: valide o output localmente (Pydantic) sempre, mesmo quando o - provider garante o schema. Isso mantém o contrato estável quando você troca de provider. -
    - -
    - -
    -

    Parte 3 — Portabilidade

    -

    O coração agnóstico do capítulo: comparar comportamento, declarar a troca de provider, mapear roles e - escolher parâmetros por intenção.

    -
    - -
    -

    8. Matriz comparativa de provider behavior

    -

    Onde os três divergem de fato. Use como checklist do que o adapter precisa traduzir. A matriz cruzada - mais profunda (paralelismo, multimodal) está em - guia_paralelismo_tools e - guia_multimodal.

    -
    - - - - - - - - - - - -
    DimensãoOpenAIAnthropicGoogle Gemini
    EstadoResponses com previous_response_id/conversation; store=false possível.Messages + histórico app-managed; cliente mantém o histórico.Histórico de parts; muitas chamadas stateless; o SDK ajuda.
    TransporteHTTP/SSE padrão; WebSocket mode opt-in (wss://api.openai.com/v1/responses) p/ loops longos de tool calls.HTTP + SSE (stream:true); sem WebSocket na Messages API.Interactions: HTTP + SSE; Live API em WebSocket (WSS) p/ voz/vídeo em tempo real.
    Tool loopFunction calls + execução no cliente; built-ins/MCP; Agents SDK pode gerenciar.tool_use/tool_result; client e server tools.Function declarations; automatic function calling no Python.
    Reasoning/thinkingReasoning tokens internos, summaries, encrypted reasoning.Thinking adaptive/extended, blocos + assinaturas, budgets.thinking_level e thought signatures.
    Output budgetmax_output_tokens inclui visível + reasoning.max_tokens interage com o thinking budget.maxOutputTokens para o candidato; thinking à parte.
    Rolesinstructions/system/developer + input items.system top-level + user/assistant.systemInstruction + user/model contents.
    Structured outputtext.format (json_schema).output_config.format (json_schema).response_json_schema + response_mime_type.
    Multimodal/filesInputs multimodais + built-ins.Limites por imagens/PDFs conforme docs.Document processing/files e multimodal.
    -
    Não force WebSocket em todo lugar. Só a OpenAI expõe WebSocket como transporte da API de texto/agente (Responses WebSocket mode — ganho ~40% em rollouts com 20+ tool calls; caso contrário, HTTP/SSE). Em Gemini e Anthropic, a chamada ao modelo é HTTP+SSE; WebSocket só existe para tempo real (Gemini Live API) ou transporte de MCP — não para a inferência de texto. Detalhe por provider: OpenAI §12.2 · Claude §5 · Gemini §6. E lembre: transporte com o provider não dá resume ao usuário — durabilidade/reconexão (event store, replay por cursor, failover como nova tentativa) é a camada 2, no guia Streaming Durável & Resumível.
    -
    - -
    -

    9. Provider switching contract

    -

    Trocar provider deve ser declarado. O adapter produz uma matriz de perdas e uma justificativa de - roteamento — assim a troca é auditável e reversível.

    -
    {
    -  "provider_switch": {
    -    "from": "openai_responses",
    -    "to": "gemini",
    -    "reason": "latency_or_capability",
    -    "preserved": ["messages", "assets", "function_schemas", "citations"],
    -    "lost_or_transformed": ["openai_encrypted_reasoning", "developer_role_semantics"],
    -    "required_rehydration": ["systemInstruction", "thought_signature_policy"],
    -    "risk": "medium",
    -    "user_visible": false
    -  }
    -}
    -
      -
    • ☑ Não migrar carriers privados (reasoning/thinking cifrado, signatures) como texto comum.
    • -
    • ☑ Não presumir que roles e budgets têm equivalência perfeita.
    • -
    • ☑ Não misturar histórico do provider A com o B sem adapter e loss declaration.
    • -
    • ☑ Registrar motivo, modelo, versão, parâmetros e usage estimado/real.
    • -
    -
    - Perda silenciosa: passar o carrier de reasoning de um provider como mensagem de texto - para outro não "preserva o raciocínio" — corrompe o estado e pode vazar conteúdo opaco. Sempre - descarte ou re-hidrate explicitamente, nunca traduza por engano. -
    -
    - -
    -

    10. Equivalência de roles e instruções

    -

    A projeção de roles é a principal fonte de drift. Não existe equivalência perfeita entre - system, developer, instructions, systemInstruction e - mensagens comuns — o adapter registra como cada intenção foi projetada e o que se perdeu.

    -
    - - - - - - - - -
    Intenção canônicaOpenAIAnthropicGoogle
    Política não negociávelsystem/developer/instructions conforme a rota.system top-level.systemInstruction.
    Tarefa do usuárioinput/message user.user message.user content/part.
    Resposta do modelooutput items.assistant message.model content.
    Tool requestfunction/tool call item.tool_use block.function_call part.
    Tool resultfunction_call_output.tool_result block (role user).function_response part.
    - -
    - -
    -

    11. Matriz de parâmetros por intenção

    -

    A cola operacional: dada uma intenção de orquestração, quais controles usar em cada provider.

    -
    - - - - - - - - - - - -
    IntençãoControles típicos
    Forçar nenhuma tooltool_choice: none ou sem tools; prompt de síntese final; guardrail de tool call vazio.
    Permitir várias consultas read-onlyparallel_tool_calls quando suportado; runtime executa com fan-out cap.
    Obrigar tool específicatool_choice específico (OpenAI/Anthropic) / mode ANY (Gemini).
    Controlar profundidadereasoning.effort (OpenAI) / thinking (Anthropic) / thinking_level (Gemini); output cap ajustado.
    Evitar truncation perigosaMedir tokens, compactar antes, truncation: disabled quando falha explícita é melhor.
    Reduzir custoModelo menor para triagem (mini/nano/flash-lite/haiku), caps, early exit e cache permitido pela política.
    Minimizar latência em loop longo de toolsOpenAI: WebSocket mode da Responses API (conexão persistente, só itens novos + previous_response_id; ~40% em 20+ tool calls). Anthropic/Gemini: HTTP+SSE com stream, preâmbulo curto e prompt/context caching — não há WebSocket de inferência nesses dois. Ver linha Transporte na §8.
    Fallback cross-vendor por classe (2026-07)Pares de equivalência aproximada de classe/custo: gpt-5.6-sol ↔ claude-opus-4-8 (frontier) · gpt-5.6-terra ↔ claude-sonnet-5/gemini-3.1-pro (workhorse) · gpt-5.6-luna/gpt-5.4-nano ↔ gemini-3.5-flash/-lite/haiku-4.5 (volume). Ressalvas: tokenizers diferentes (~±30% na contagem), reasoning/thinking não portável, tools built-in distintas — reveja caps e evals ao trocar, não só o preço.
    - -
    - -
    -

    12. Receitas de adapter

    -

    Receitas curtas por provider. As completas (com cookbook) ficam nos guias dedicados.

    -

    OpenAI

    -
    - - - - - - - - -
    CasoConfiguração base
    Structured answerResponses API + output schema + validação local + retry controlado.
    Tool loop manualResponses API + function tools + loop client-side + ledger.
    Fluxo sensível (ZDR)store=false + encrypted reasoning quando aplicável + ledger app-managed.
    Built-in search/file/codeIsolar a fase de built-in, limitar max_tool_calls, registrar outputs reduzidos.
    Agents runtimeAgents SDK com guardrails/tracing/sessions + ledger externo para auditoria.
    -

    Anthropic & Google

    -
    - - - - - - - - -
    ProviderReceitaAtenção
    AnthropicMessages API com tool_use/tool_result e schemas explícitos.Preservar blocos/assinaturas de thinking no tool-use quando exigido.
    AnthropicThinking (adaptive/extended) para tarefas complexas.Budget interage com max_tokens; medir custo.
    Google Geminigoogle-genai com automatic function calling quando útil.Histórico completo e thought signatures intactas.
    Google GeminiDocument processing/files para multimodal.Governar assets no registry próprio.
    Google GeminiStructured output com response_json_schema.Validar localmente e declarar perdas no provider switch.
    -
    - Gate PROVIDER: toda rota deve declarar quais recursos são obrigatórios, opcionais ou - não suportados por provider. Ao trocar, registre a loss_declaration: perda de tool nativa, - de estado, diferença de thinking/reasoning, de schema, custo, latência e política de retenção. -
    -
    - -
    -

    Cheat sheet — adapter & portabilidade

    -

    Imports essenciais por provider

    -
    -
    - - - -
    -
    -
    # OpenAI: Responses API + Agents SDK
    -from openai import OpenAI
    -from agents import Agent, Runner, function_tool
    -client = OpenAI()
    -resp = client.responses.create(model="gpt-5.5", input="...")
    -
    -
    -
    # Anthropic: Messages API
    -from anthropic import Anthropic
    -client = Anthropic()
    -msg = client.messages.create(
    -    model="claude-opus-4-8", max_tokens=1024,
    -    messages=[{"role": "user", "content": "..."}])
    -
    -
    -
    # Google: google-genai (SDK atual; não os legados)
    -from google import genai
    -client = genai.Client()
    -resp = client.models.generate_content(
    -    model="gemini-3.1-pro-preview", contents="...")
    -
    -
    -

    Decisões rápidas

    -
      -
    • Precisa de loop/handoffs/guardrails Python-first no ecossistema OpenAI? → Agents SDK.
    • -
    • Quer possuir o loop, dispatch e estado manualmente? → Responses API direta.
    • -
    • Precisa de tipagem/output validado/evals model-agnostic? → Pydantic AI por cima.
    • -
    • Vai trocar de provider? → emita o provider_switch com loss declaration.
    • -
    -
    - -
    -

    Notas de verificação

    -

    Fatos perecíveis conferidos contra a folha de fatos SOTA do super-guia (2026-06-10). Identificadores - de modelo não são hardcoded no corpo agnóstico — aparecem só em exemplos e nesta seção.

    -
      -
    • Resolvido URL oficial do Pydantic AI é pydantic.dev/docs/ai (verificação ao vivo 2026-05-25: ai.pydantic.dev/ retorna 301 para pydantic.dev/docs/ai/overview/; /evals/evals/ e /integrations/logfire/ também resolvem sob pydantic.dev/docs/ai/). O domínio ai.pydantic.dev não é fabricado — é o domínio antigo, hoje redirecionado. Alinhado com guia_operacao_seguranca_evals.html.
    • -
    • Resolvido Versões instaláveis (PyPI/npm, 2026-06-29): openai-agents 0.17.7 (release 2026-06-24; piso openai>=2.36.0,<3; SDK openai 2.44.0 Python / 6.45.0 Node; @openai/agents 0.12.0), anthropic 0.113.0 (@anthropic-ai/sdk 0.107.0), google-genai 2.10.0, pydantic-ai 2.1.0 (V2 estável; a série 1.x existiu — 1.0.0 a 1.99.0 — antes da 2.0; caminho de upgrade recomendado: ir primeiro a uma 1.x recente para ver os deprecation warnings, depois migrar para V2), langchain-core 1.4.8, langchain-anthropic 1.4.8, langchain-google-genai 4.2.6 (requer langchain-core>=1.4.7,<2), langgraph 1.2.6, langgraph-api 0.10.0.
    • -
    • Resolvido Structured output nativo da Anthropic é output_config.format (não response_format).
    • -
    • Resolvido Gemini série 3 usa thinking_level (não thinking_budget); misturar os dois retorna 400.
    • -
    • Resolvido Thinking por modelo Anthropic: Opus 4.8 só adaptive; Fable 5 adaptive sempre ativo (desativar retorna 400); Haiku 4.5 só enabled; Sonnet 4.6 ambos.
    • -
    • Novo Claude Fable 5 (claude-fable-5, GA 2026-06-09): 1M de contexto, 128k max output, adaptive thinking sempre ativo. Atualização 2026-07-09: reimplantado globalmente em 01/07 (controles de exportação levantados em 30/06); via API pay-as-you-go a $10/$50 por MTok. Em planos de assinatura, o acesso incluído foi estendido até 12/07 e, a partir de 13/07, passa a exigir saldo pré-pago de usage credits. Opus 4.8 segue como flagship recomendado — os exemplos deste guia permanecem com claude-opus-4-8.
    • -
    • Atenção Sampling deprecado: temperature, top_p e top_k retornam erro 400 com valor não-default em Claude Opus 4.7, 4.8 e Fable 5 (ainda válidos em Opus 4.6, Sonnet 4.6 e anteriores). Omita e guie por prompting. Opus 4.7+/Fable 5 também usam novo tokenizer (~30% mais tokens) — recalibre max_tokens.
    • -
    • Resolvido IDs SOTA usados nos exemplos: gpt-5.5, claude-opus-4-8, gemini-3.1-pro-preview. Os exemplos permanecem com gpt-5.5 (estável/maduro); trocar o model= por outro ID é transparente para o adapter.
    • -
    • Novo OpenAI lançou a família gpt-5.6 (Sol/Terra/Luna) em 2026-07-09 — gpt-5.6-sol (flagship), gpt-5.6-terra (custo/desempenho), gpt-5.6-luna (econômico), alias gpt-5.6→-sol. Via API em preview limitado (Responses/Chat Completions/Codex), GA "nas próximas semanas"; gpt-5.5 segue não-depreciado. Nos adapters, basta passar o novo model=; note que gpt-5.6+ aceita caching explícito (prompt_cache_options/prompt_cache_breakpoint) que os modelos anteriores rejeitam.
    • -
    • Resolvido Campo de reasoning cifrado include=["reasoning.encrypted_content"] confirmado na Responses API (guia Reasoning > Encrypted reasoning items e API Reference de responses.create): habilita reusar reasoning items em modo stateless (store=false ou ZDR). Verificado 2026-05-25 em developers.openai.com · reasoning.
    • -
    • Resolvido Superfície do Pydantic AI confirmada em pydantic.dev/docs/ai: Agent(model, deps_type=, output_type=, instructions=), @agent.tool/@agent.tool_plain, RunContext, run_sync/run, ToolOutput. Verificado 2026-05-25.
    • -
    • Resolvido Agent.as_tool(...) exige tool_name e tool_description no openai-agents 0.17.x — exemplo corrigido após revisão adversarial (codex/gpt-5.5, 2026-05-25). Runner.run_sync(agent, "texto") confirmado válido.
    • -
    • Resolvido google-genai: client.models.generate_content(...) é a chamada canônica atual (não legado); a Interactions API é abstração stateful adicional, não substituta. Estrutura Gemini = response_json_schema + response_mime_type.
    • -
    -
    - Fonte única de fatos: este guia cita a folha de fatos - do projeto (interna); em conflito, vale a folha verificada. -
    -
    - -
    -
    - - -
    -
    -
    -
    Providers & adapters Núcleo · portabilidade entre providers
    -

    - Referência técnica construída a partir da documentação oficial pública em 2026-06-10. - Para informação sempre atualizada, consulte as fontes oficiais de cada provider - (OpenAI, - Anthropic, - Google). -

    -
    -
    -
    Crédito de produção
    -
    Gerado por subagentes Claude Opus 4.7 (xhigh)
    -
    revisão e montagem pelo orquestrador · 2026-05-25
    -
    - Super-guia de Agentes - PT-BR -
    -
    -
    -
    Navegação rápida
    - - -
    -
    -
    - - - - + + + + + +Providers & adapters — camada de portabilidade entre OpenAI, Anthropic e Google + + + + + + + + +
    +
    +
    Providers & adapters Núcleo · portabilidade entre providers
    +
    + Verificado em 2026-07-12 + Super-guia de Agentes + PT-BR + +
    +
    +
    + +
    + + +
    + +
    +

    Providers & adapters

    +

    + A camada de portabilidade do super-guia. Aqui o foco é agnóstico: o papel de cada SDK, + o provider switching contract com declaração de perdas, a equivalência de roles e + instruções, a matriz de comportamento entre OpenAI, Anthropic e Google, e structured outputs + cross-provider. Os parâmetros específicos de cada API ficam nos guias dedicados — este capítulo é a + cola entre eles. Prosa em PT-BR; identificadores, classes e código em inglês. +

    +
    + Super-guia de Agentes + PT-BR + SOTA · verificado 2026-07-12 +
    +
    + +
    +

    Sobre este guia

    +

    + Este capítulo do núcleo trata a aplicação como dona de um contrato canônico e cada + provider como uma projeção desse contrato. O objetivo não é reexplicar a API de cada + provedor — é dar o adapter que converte um modelo canônico (ledger, capabilities, schemas, + roles) para OpenAI Responses/Agents SDK, Anthropic Messages e Google GenAI/Gemini, tornando explícitas + as perdas em cada troca. +

    +
    + Para IA e humanos: use as tabelas como referência de consulta (parâmetros, roles, + comportamento por provider) e os contratos JSON como esquema copy-paste. Cada afirmação perecível + (IDs de modelo, nomes de parâmetro, versão de spec) é conferida na seção + Notas de verificação contra a folha de fatos SOTA do super-guia. +
    +
    + Onde aprofundar cada API: parâmetros completos da Responses API → + guia_openai_modelos; Messages API e blocos de tool/thinking → + guia_claude_api; Interactions API e google-genai → + guia_gemini_interactions_api; runtime do Agents SDK → + guia_agents_sdk e + guia_agents_sdk_orquestracao. +
    +
    + +
    +

    A tese do adapter

    +

    + Trocar de provider deve ser uma operação declarada, nunca transparente. Um sistema que + "só troca o nome do modelo" mente para si mesmo: roles não têm equivalência perfeita, carriers de + reasoning são opacos e específicos, budgets se comportam de forma distinta e o estado servidor de um + provider não existe no outro. O adapter resolve isso projetando o contrato canônico e produzindo uma + loss declaration a cada conversão. +

    +
    + + Contrato canônico projetado para três providers + Um modelo canônico no centro (ledger, capabilities, schemas, roles) é convertido por um adapter para OpenAI, Anthropic e Google, cada conversão emitindo uma declaração de perdas. + + Contrato canônico + ledger · capabilities · schemas + roles · assets · budgets + + adapter + + + + OpenAI + Responses / Agents SDK + + Anthropic + Messages API + + Google + GenAI / Gemini + + + + + + + + ↯ loss + ↯ loss + ↯ loss + + +
    O adapter é o único ponto que conhece dialeto de provider. O produto fala o contrato canônico; cada projeção declara o que foi preservado, transformado e perdido.
    +
    +
    + +
    +

    Parte 1 — SDKs & parâmetros

    +

    O papel de cada camada, os parâmetros da Responses API que importam para a orquestração, e quando o + Agents SDK ou o Pydantic AI entram. Detalhe completo de cada API fica nos guias dedicados.

    +
    + +
    +

    1. Papel de cada SDK/framework

    +

    Cada camada tem um papel; o erro comum é confundir um provider adapter com um banco de estado + durável, ou um framework de runtime com governança de negócio. A tabela separa uso recomendado de + "não confundir com".

    +
    + + + + + + + + + +
    CamadaUso recomendadoNão confundir com
    OpenAI Agents SDK (openai-agents)Runtime de agentes com tools, handoffs, guardrails, sessions, tracing e MCP. Uma das bases recomendadas no ecossistema OpenAI.Banco de estado durável universal ou substituto de políticas de negócio.
    OpenAI Responses APIInterface direta para controle fino de input, tools, estado, reasoning, structured outputs, truncation e loop próprio.Framework de governança; o cliente ainda valida, executa tools e mantém o ledger.
    OpenAI Python SDK (openai)Cliente oficial para chamar a API OpenAI.Orquestrador por si só.
    Anthropic SDK / Messages API (anthropic)Provider adapter para Claude: tools (tool_use/tool_result) e thinking (adaptive/extended).Mesma semântica de roles/tokens/reasoning da OpenAI.
    Google GenAI SDK (google-genai)Provider adapter para Gemini: function calling, files, structured output e thought signatures.Estado durável automático em todo cenário; SDKs legados (google-generativeai).
    Pydantic AI (pydantic-ai)Camada complementar de agentes tipados, output estruturado, deps, evals, observabilidade e wrappers model-agnostic.Substituto obrigatório do Agents SDK; use onde agrega validação/typing/evals.
    +
    + Pin de versões (2026-07-12): openai-agents 0.18.2 (release 2026-07-11; pré-1.0; superfície ainda + evolui; piso openai>=2.45.0,<3 desde a 0.18.2 — era >=2.36.0 em 0.17.x/0.18.0/0.18.1; SDK openai 2.45.0 / @openai/agents 0.13.2), + anthropic 0.116.0, google-genai 2.11.0, pydantic-ai 2.9.0 (série 2.x estável, iniciada em 2.0.0 em 2026-06-23; a 2.x traz mudanças incompatíveis — ex.: prefixo openai: passa a usar a Responses API, builtin_tools→native_tools, end_strategy default early→graceful; houve sim série 1.x, de 1.0.0 a 1.99.0, antes da 2.0). + Confirme antes de fixar — ver Notas de verificação. +
    +
    + +
    +

    2. OpenAI Responses API: parâmetros críticos

    +

    Para a orquestração, estes são os campos que mais influenciam controle de fase, estado e budget. A + referência completa (anatomia da Responses, function calling, streaming) está em + guia_openai_modelos.

    +
    + + + + + + + + + + + + + + +
    Parâmetro/campoUsoCuidado
    inputItens de entrada multimodais/projetados do ledger.Não jogar corpus bruto sem caps de budget.
    instructionsInstruções da chamada atual.Com previous_response_id, não assuma carry-over de instructions anteriores.
    toolsBuilt-ins, MCP e function tools.Exponha apenas as allowed tools da fase.
    tool_choiceauto / required / específico / none.Trava fase, não é a única camada de segurança.
    parallel_tool_callsPermite múltiplas function calls numa resposta.A execução paralela é do runtime; built-ins têm restrições.
    max_tool_callsLimite de tool calls hospedadas na resposta.Não substitui o max turns do orquestrador.
    max_output_tokensLimita tokens visíveis + reasoning conforme o modelo.Reserve orçamento para reasoning e resposta final.
    previous_response_idEncadeia o estado servidor da resposta anterior.Não é ledger; não combine com conversation na mesma cadeia.
    conversationObjeto de conversa stateful gerido pelo servidor.Avalie retenção/política de dados; é projeção, não fonte da verdade.
    storetrue persiste a resposta (necessário p/ previous_response_id).Para ZDR/stateless, use store=false e devolva os output items.
    truncationauto / disabled.Truncation automática pode remover contexto crítico silenciosamente.
    +
    + Reasoning stateless (ZDR): para preservar o reasoning entre turnos sem armazenamento + no servidor, combine store=false com include=["reasoning.encrypted_content"] + e devolva o conteúdo cifrado a cada turno. Confira o nome exato do campo na doc atual da Responses API. +
    +
    + +
    +

    3. OpenAI Agents SDK: quando usar como base

    +

    Use o Agents SDK quando o projeto se beneficia de loop de agentes, guardrails, handoffs, + agents-as-tools, sessions, tracing e MCP em código Python-first. A doc oficial o posiciona como + framework leve e recomenda a Responses API direta quando você quer possuir manualmente o loop, + o dispatch de tools e o estado. É uma base recomendada — LangGraph e Google ADK são + alternativas legítimas (ver os guias de framework do super-guia).

    +
    from agents import Agent, Runner, function_tool
    +
    +@function_tool
    +def lookup_policy(topic: str) -> str:
    +    # Chame sua capability real; reduza o output antes de devolver ao agente.
    +    return "síntese com provenance"
    +
    +specialist = Agent(
    +    name="evidence_specialist",
    +    instructions="Responda apenas com evidências tipadas e limitações.",
    +    tools=[lookup_policy],
    +)
    +
    +manager = Agent(
    +    name="orchestrator",
    +    instructions="Planeje, delegue quando necessário e sintetize com fontes.",
    +    tools=[specialist.as_tool(
    +        tool_name="consult_evidence_specialist",
    +        tool_description="Consulta o especialista de evidências; retorna síntese tipada com limitações.",
    +    )],
    +)
    +
    +result = Runner.run_sync(manager, "Pergunta do usuário")
    +print(result.final_output)
    + +

    Mesmo quando o SDK gerencia o loop, mantenha registro externo de traces, usage, tool results e + decisões críticas se o sistema precisa ser auditável — o ledger canônico é seu, não do framework.

    +
    + +
    +

    4. Pydantic AI como camada complementar

    +

    O Pydantic AI brilha nas bordas tipadas: dependências, output estruturado, validação de ferramentas, + evals, observabilidade (Logfire) e wrappers model-agnostic. Convive com o Agents SDK — use Pydantic para + schemas/evals/validadores, o Agents SDK para orquestração/handoffs, e a Responses API direta nos pontos + de controle fino. Nenhum outro guia do conjunto cobre o Pydantic AI, então ele mora aqui.

    +
    from pydantic import BaseModel, Field
    +
    +class EvidenceItem(BaseModel):
    +    source_id: str
    +    claim: str
    +    confidence: float = Field(ge=0, le=1)
    +
    +class SpecialistOutput(BaseModel):
    +    answerable: bool
    +    summary: str
    +    evidence: list[EvidenceItem]
    +    missing: list[str] = []
    +
    +# Use este modelo como contrato de saída de subagente/tool/eval,
    +# independentemente do provider que gerou a resposta.
    + +
    + +
    +

    Parte 2 — Adapters por provider

    +

    O ângulo aqui é de projeção/adapter — o "como o contrato canônico vira chamada deste provider". A API + real de cada um está nos guias dedicados.

    +
    + +
    +

    5. Anthropic adapter

    +

    No adapter Anthropic, trate tool use como blocos estruturados: o modelo emite tool_use, + o cliente executa a tool e devolve tool_result (numa mensagem de role user), + com stop_reason: tool_use. Para thinking, preserve os blocos/assinaturas conforme as regras + de contexto e tool-use. A API completa está em guia_claude_api.

    +
    + + + + + + + + + +
    AspectoRegra prática
    Rolessystem top-level + messages alternando user/assistant; adapte developer/instructions com cuidado.
    ToolsSchemas explícitos (input_schema); tool_choice específico quando a chamada é obrigatória.
    ThinkingOpus 4.8 só adaptive; Fable 5 adaptive sempre ativo (type:"disabled" e budget manual retornam 400); Haiku 4.5 só enabled (budget); Sonnet 4.6 ambos. Preserve assinaturas quando exigidas.
    Structured outputoutput_config.format (json_schema) nativo — não use response_format (padrão OpenAI).
    ContextMeça thinking/contexto; compacte antes do overflow. Opus 4.8/Sonnet 4.6/Fable 5 = 1M (Fable 5 com 128k max output); Haiku 4.5 = 200K.
    Provider switchDeclare perdas quando carriers de reasoning da OpenAI ou thought signatures do Gemini não têm equivalente direto.
    +
    + +
    +

    6. Google GenAI/Gemini adapter

    +

    No adapter Google, use o SDK oficial google-genai (não os SDKs legados). A chamada + canônica de geração é client.models.generate_content(...) — é o caminho atual e correto, não + legado. A Interactions API é uma abstração adicional + (recurso de interação stateful/por passos) que você usa quando precisa desse modelo de estado, não um + substituto da chamada de baixo nível. Em function calling com thought signatures, + preserve as parts exatamente como retornadas — a doc enfatiza passback intacto e regras + específicas para chamadas paralelas/sequenciais.

    +
    + + + + + + + + + +
    AspectoRegra prática
    SDKfrom google import genai; genai.Client() + client.models.generate_content(...).
    Function callingModos AUTO/ANY/NONE; automatic function calling no SDK Python quando apropriado.
    Thought signaturesPreserve parts/signatures; não concatene nem reordene manualmente. Obrigatório devolver as de function calling.
    Thinkingthinking_level (low/medium/high; Flash/Lite ainda têm minimal) — não o legado thinking_budget; não misture os dois (erro 400).
    Structured outputresponse_mime_type="application/json" + response_json_schema.
    Documentos/filesAPIs de files/document processing com asset registry próprio.
    +
    + +
    +

    7. Structured outputs cross-provider

    +

    Para saídas críticas, prefira structured outputs com JSON Schema/Pydantic em vez de pedir + "responda em JSON" por prompt. Os três providers oferecem o mecanismo, com nomes diferentes — o contrato + canônico é o mesmo schema; o adapter só muda o campo da chamada.

    +
    + + + + + + + +
    ProviderMecanismoCampo da chamada
    OpenAIStructured Outputstext.format (json_schema)
    AnthropicStructured outputs nativooutput_config.format (json_schema)
    Google GeminiStructured outputresponse_json_schema + response_mime_type
    Pydantic AIOutput validado (qualquer provider)output_type=Model
    +
    {
    +  "type": "object",
    +  "additionalProperties": false,
    +  "required": ["decision", "rationale", "evidence", "risks"],
    +  "properties": {
    +    "decision": {"type": "string", "enum": ["approve", "reject", "needs_human"]},
    +    "rationale": {"type": "string", "maxLength": 1200},
    +    "evidence": {"type": "array", "items": {"type": "object"}},
    +    "risks": {"type": "array", "items": {"type": "string"}}
    +  }
    +}
    +
    + Regra de ouro: valide o output localmente (Pydantic) sempre, mesmo quando o + provider garante o schema. Isso mantém o contrato estável quando você troca de provider. +
    + +
    + +
    +

    Parte 3 — Portabilidade

    +

    O coração agnóstico do capítulo: comparar comportamento, declarar a troca de provider, mapear roles e + escolher parâmetros por intenção.

    +
    + +
    +

    8. Matriz comparativa de provider behavior

    +

    Onde os três divergem de fato. Use como checklist do que o adapter precisa traduzir. A matriz cruzada + mais profunda (paralelismo, multimodal) está em + guia_paralelismo_tools e + guia_multimodal.

    +
    + + + + + + + + + + + +
    DimensãoOpenAIAnthropicGoogle Gemini
    EstadoResponses com previous_response_id/conversation; store=false possível.Messages + histórico app-managed; cliente mantém o histórico.Histórico de parts; muitas chamadas stateless; o SDK ajuda.
    TransporteHTTP/SSE padrão; WebSocket mode opt-in (wss://api.openai.com/v1/responses) p/ loops longos de tool calls.HTTP + SSE (stream:true); sem WebSocket na Messages API.Interactions: HTTP + SSE; Live API em WebSocket (WSS) p/ voz/vídeo em tempo real.
    Tool loopFunction calls + execução no cliente; built-ins/MCP; Agents SDK pode gerenciar.tool_use/tool_result; client e server tools.Function declarations; automatic function calling no Python.
    Reasoning/thinkingReasoning tokens internos, summaries, encrypted reasoning.Thinking adaptive/extended, blocos + assinaturas, budgets.thinking_level e thought signatures.
    Output budgetmax_output_tokens inclui visível + reasoning.max_tokens interage com o thinking budget.maxOutputTokens para o candidato; thinking à parte.
    Rolesinstructions/system/developer + input items.system top-level + user/assistant.systemInstruction + user/model contents.
    Structured outputtext.format (json_schema).output_config.format (json_schema).response_json_schema + response_mime_type.
    Multimodal/filesInputs multimodais + built-ins.Limites por imagens/PDFs conforme docs.Document processing/files e multimodal.
    +
    Não force WebSocket em todo lugar. Só a OpenAI expõe WebSocket como transporte da API de texto/agente (Responses WebSocket mode — ganho ~40% em rollouts com 20+ tool calls; caso contrário, HTTP/SSE). Em Gemini e Anthropic, a chamada ao modelo é HTTP+SSE; WebSocket só existe para tempo real (Gemini Live API) ou transporte de MCP — não para a inferência de texto. Detalhe por provider: OpenAI §12.2 · Claude §5 · Gemini §6. E lembre: transporte com o provider não dá resume ao usuário — durabilidade/reconexão (event store, replay por cursor, failover como nova tentativa) é a camada 2, no guia Streaming Durável & Resumível.
    +
    + +
    +

    9. Provider switching contract

    +

    Trocar provider deve ser declarado. O adapter produz uma matriz de perdas e uma justificativa de + roteamento — assim a troca é auditável e reversível.

    +
    {
    +  "provider_switch": {
    +    "from": "openai_responses",
    +    "to": "gemini",
    +    "reason": "latency_or_capability",
    +    "preserved": ["messages", "assets", "function_schemas", "citations"],
    +    "lost_or_transformed": ["openai_encrypted_reasoning", "developer_role_semantics"],
    +    "required_rehydration": ["systemInstruction", "thought_signature_policy"],
    +    "risk": "medium",
    +    "user_visible": false
    +  }
    +}
    +
      +
    • ☑ Não migrar carriers privados (reasoning/thinking cifrado, signatures) como texto comum.
    • +
    • ☑ Não presumir que roles e budgets têm equivalência perfeita.
    • +
    • ☑ Não misturar histórico do provider A com o B sem adapter e loss declaration.
    • +
    • ☑ Registrar motivo, modelo, versão, parâmetros e usage estimado/real.
    • +
    +
    + Perda silenciosa: passar o carrier de reasoning de um provider como mensagem de texto + para outro não "preserva o raciocínio" — corrompe o estado e pode vazar conteúdo opaco. Sempre + descarte ou re-hidrate explicitamente, nunca traduza por engano. +
    +
    + +
    +

    10. Equivalência de roles e instruções

    +

    A projeção de roles é a principal fonte de drift. Não existe equivalência perfeita entre + system, developer, instructions, systemInstruction e + mensagens comuns — o adapter registra como cada intenção foi projetada e o que se perdeu.

    +
    + + + + + + + + +
    Intenção canônicaOpenAIAnthropicGoogle
    Política não negociávelsystem/developer/instructions conforme a rota.system top-level.systemInstruction.
    Tarefa do usuárioinput/message user.user message.user content/part.
    Resposta do modelooutput items.assistant message.model content.
    Tool requestfunction/tool call item.tool_use block.function_call part.
    Tool resultfunction_call_output.tool_result block (role user).function_response part.
    + +
    + +
    +

    11. Matriz de parâmetros por intenção

    +

    A cola operacional: dada uma intenção de orquestração, quais controles usar em cada provider.

    +
    + + + + + + + + + + + +
    IntençãoControles típicos
    Forçar nenhuma tooltool_choice: none ou sem tools; prompt de síntese final; guardrail de tool call vazio.
    Permitir várias consultas read-onlyparallel_tool_calls quando suportado; runtime executa com fan-out cap.
    Obrigar tool específicatool_choice específico (OpenAI/Anthropic) / mode ANY (Gemini).
    Controlar profundidadereasoning.effort (OpenAI) / thinking (Anthropic) / thinking_level (Gemini); output cap ajustado.
    Evitar truncation perigosaMedir tokens, compactar antes, truncation: disabled quando falha explícita é melhor.
    Reduzir custoModelo menor para triagem (mini/nano/flash-lite/haiku), caps, early exit e cache permitido pela política.
    Minimizar latência em loop longo de toolsOpenAI: WebSocket mode da Responses API (conexão persistente, só itens novos + previous_response_id; ~40% em 20+ tool calls). Anthropic/Gemini: HTTP+SSE com stream, preâmbulo curto e prompt/context caching — não há WebSocket de inferência nesses dois. Ver linha Transporte na §8.
    Fallback cross-vendor por classe (2026-07)Pares de equivalência aproximada de classe/custo: gpt-5.6-sol ↔ claude-opus-4-8 (frontier) · gpt-5.6-terra ↔ claude-sonnet-5/gemini-3.1-pro (workhorse) · gpt-5.6-luna/gpt-5.4-nano ↔ gemini-3.5-flash/-lite/haiku-4.5 (volume). Ressalvas: tokenizers diferentes (~±30% na contagem), reasoning/thinking não portável, tools built-in distintas — reveja caps e evals ao trocar, não só o preço.
    + +
    + +
    +

    12. Receitas de adapter

    +

    Receitas curtas por provider. As completas (com cookbook) ficam nos guias dedicados.

    +

    OpenAI

    +
    + + + + + + + + +
    CasoConfiguração base
    Structured answerResponses API + output schema + validação local + retry controlado.
    Tool loop manualResponses API + function tools + loop client-side + ledger.
    Fluxo sensível (ZDR)store=false + encrypted reasoning quando aplicável + ledger app-managed.
    Built-in search/file/codeIsolar a fase de built-in, limitar max_tool_calls, registrar outputs reduzidos.
    Agents runtimeAgents SDK com guardrails/tracing/sessions + ledger externo para auditoria.
    +

    Anthropic & Google

    +
    + + + + + + + + +
    ProviderReceitaAtenção
    AnthropicMessages API com tool_use/tool_result e schemas explícitos.Preservar blocos/assinaturas de thinking no tool-use quando exigido.
    AnthropicThinking (adaptive/extended) para tarefas complexas.Budget interage com max_tokens; medir custo.
    Google Geminigoogle-genai com automatic function calling quando útil.Histórico completo e thought signatures intactas.
    Google GeminiDocument processing/files para multimodal.Governar assets no registry próprio.
    Google GeminiStructured output com response_json_schema.Validar localmente e declarar perdas no provider switch.
    +
    + Gate PROVIDER: toda rota deve declarar quais recursos são obrigatórios, opcionais ou + não suportados por provider. Ao trocar, registre a loss_declaration: perda de tool nativa, + de estado, diferença de thinking/reasoning, de schema, custo, latência e política de retenção. +
    +
    + +
    +

    Cheat sheet — adapter & portabilidade

    +

    Imports essenciais por provider

    +
    +
    + + + +
    +
    +
    # OpenAI: Responses API + Agents SDK
    +from openai import OpenAI
    +from agents import Agent, Runner, function_tool
    +client = OpenAI()
    +resp = client.responses.create(model="gpt-5.5", input="...")
    +
    +
    +
    # Anthropic: Messages API
    +from anthropic import Anthropic
    +client = Anthropic()
    +msg = client.messages.create(
    +    model="claude-opus-4-8", max_tokens=1024,
    +    messages=[{"role": "user", "content": "..."}])
    +
    +
    +
    # Google: google-genai (SDK atual; não os legados)
    +from google import genai
    +client = genai.Client()
    +resp = client.models.generate_content(
    +    model="gemini-3.1-pro-preview", contents="...")
    +
    +
    +

    Decisões rápidas

    +
      +
    • Precisa de loop/handoffs/guardrails Python-first no ecossistema OpenAI? → Agents SDK.
    • +
    • Quer possuir o loop, dispatch e estado manualmente? → Responses API direta.
    • +
    • Precisa de tipagem/output validado/evals model-agnostic? → Pydantic AI por cima.
    • +
    • Vai trocar de provider? → emita o provider_switch com loss declaration.
    • +
    +
    + +
    +

    Notas de verificação

    +

    Fatos perecíveis conferidos contra a folha de fatos SOTA do super-guia (2026-06-10). Identificadores + de modelo não são hardcoded no corpo agnóstico — aparecem só em exemplos e nesta seção.

    +
      +
    • Resolvido URL oficial do Pydantic AI é pydantic.dev/docs/ai (verificação ao vivo 2026-05-25: ai.pydantic.dev/ retorna 301 para pydantic.dev/docs/ai/overview/; /evals/evals/ e /integrations/logfire/ também resolvem sob pydantic.dev/docs/ai/). O domínio ai.pydantic.dev não é fabricado — é o domínio antigo, hoje redirecionado. Alinhado com guia_operacao_seguranca_evals.html.
    • +
    • Resolvido Versões instaláveis (PyPI/npm, 2026-07-12): openai-agents 0.18.2 (release 2026-07-11; piso openai>=2.45.0,<3 só na 0.18.2 — 0.18.0/0.18.1 usavam >=2.36.0; SDK openai 2.45.0 Python / 6.46.0 Node; @openai/agents 0.13.2), anthropic 0.116.0 (@anthropic-ai/sdk 0.111.0), google-genai 2.11.0, pydantic-ai 2.9.0 (V2 estável; a série 1.x existiu — 1.0.0 a 1.99.0 — antes da 2.0.0, que iniciou a série 2.x em 2026-06-23; caminho de upgrade recomendado: ir primeiro a uma 1.x recente para ver os deprecation warnings, depois migrar para V2), langchain-core 1.4.9, langchain-anthropic 1.4.8, langchain-google-genai 4.2.7 (requer langchain-core>=1.4.7,<2), langgraph 1.2.9, langgraph-api 0.11.0.
    • +
    • Resolvido Structured output nativo da Anthropic é output_config.format (não response_format).
    • +
    • Resolvido Gemini série 3 usa thinking_level (não thinking_budget); misturar os dois retorna 400.
    • +
    • Resolvido Thinking por modelo Anthropic: Opus 4.8 só adaptive; Fable 5 adaptive sempre ativo (desativar retorna 400); Haiku 4.5 só enabled; Sonnet 4.6 ambos.
    • +
    • Novo Claude Fable 5 (claude-fable-5, GA 2026-06-09): 1M de contexto, 128k max output, adaptive thinking sempre ativo. Atualização 2026-07-09: reimplantado globalmente em 01/07 (controles de exportação levantados em 30/06); via API pay-as-you-go a $10/$50 por MTok. Em planos de assinatura, o acesso incluído foi estendido até 12/07 e, a partir de 13/07, passa a exigir saldo pré-pago de usage credits. Opus 4.8 segue como flagship recomendado — os exemplos deste guia permanecem com claude-opus-4-8.
    • +
    • Atenção Sampling deprecado: temperature, top_p e top_k retornam erro 400 com valor não-default em Claude Opus 4.7, 4.8 e Fable 5 (ainda válidos em Opus 4.6, Sonnet 4.6 e anteriores). Omita e guie por prompting. Opus 4.7+/Fable 5 também usam novo tokenizer (~30% mais tokens) — recalibre max_tokens.
    • +
    • Resolvido IDs SOTA usados nos exemplos: gpt-5.5, claude-opus-4-8, gemini-3.1-pro-preview. Os exemplos permanecem com gpt-5.5 (estável/maduro); trocar o model= por outro ID é transparente para o adapter.
    • +
    • Novo OpenAI lançou a família gpt-5.6 (Sol/Terra/Luna) em 2026-07-09 — gpt-5.6-sol (flagship), gpt-5.6-terra (custo/desempenho), gpt-5.6-luna (econômico), alias gpt-5.6→-sol. Via API em preview limitado (Responses/Chat Completions/Codex), GA "nas próximas semanas"; gpt-5.5 segue não-depreciado. Nos adapters, basta passar o novo model=; note que gpt-5.6+ aceita caching explícito (prompt_cache_options/prompt_cache_breakpoint) que os modelos anteriores rejeitam.
    • +
    • Resolvido Campo de reasoning cifrado include=["reasoning.encrypted_content"] confirmado na Responses API (guia Reasoning > Encrypted reasoning items e API Reference de responses.create): habilita reusar reasoning items em modo stateless (store=false ou ZDR). Verificado 2026-05-25 em developers.openai.com · reasoning.
    • +
    • Resolvido Superfície do Pydantic AI confirmada em pydantic.dev/docs/ai: Agent(model, deps_type=, output_type=, instructions=), @agent.tool/@agent.tool_plain, RunContext, run_sync/run, ToolOutput. Verificado 2026-05-25.
    • +
    • Resolvido Agent.as_tool(...) exige tool_name e tool_description no openai-agents 0.17.x — exemplo corrigido após revisão adversarial (codex/gpt-5.5, 2026-05-25). Runner.run_sync(agent, "texto") confirmado válido.
    • +
    • Resolvido google-genai: client.models.generate_content(...) é a chamada canônica atual (não legado); a Interactions API é abstração stateful adicional, não substituta. Estrutura Gemini = response_json_schema + response_mime_type.
    • +
    +
    + Fonte única de fatos: este guia cita a folha de fatos + do projeto (interna); em conflito, vale a folha verificada. +
    +
    + +
    +
    + + +
    +
    +
    +
    Providers & adapters Núcleo · portabilidade entre providers
    +

    + Referência técnica construída a partir da documentação oficial pública em 2026-06-10. + Para informação sempre atualizada, consulte as fontes oficiais de cada provider + (OpenAI, + Anthropic, + Google). +

    +
    +
    +
    Crédito de produção
    +
    Gerado por subagentes Claude Opus 4.7 (xhigh)
    +
    revisão e montagem pelo orquestrador · 2026-05-25
    +
    + Super-guia de Agentes + PT-BR +
    +
    +
    +
    Navegação rápida
    + + +
    +
    +
    + + + + diff --git a/references/agents_tools_best_guides/guia_skills.html b/references/agents_tools_best_guides/guia_skills.html index ed97b88..34704e0 100644 --- a/references/agents_tools_best_guides/guia_skills.html +++ b/references/agents_tools_best_guides/guia_skills.html @@ -5,7 +5,7 @@ Guia de Agent Skills — Autoria, Ativação & Harness - +