Este artigo aborda os limites do cliente e da plataforma subjacentes à experiência do utilizador e às interações com o Ask DoorDash: como passámos dos carrosséis de hackathons para esse modelo, como um único artefacto serve três leitores e como o contexto e o estado se mantêm consistentes à medida que os consumidores navegam pelo DoorDash. Segue-se «Construir o DoorDash Assistant: Uma Visão Geral da Engenharia» e às nossas análises aprofundadas A criação do Ask DoorDash (Parte 2): Inteligência, A criação do Ask DoorDash (Parte 3): Avaliação, e A criação do Ask DoorDash (Parte 4): Uma plataforma para a criação e evolução de agentes.
O Ask DoorDash transforma pedidos como «prepara-me um jantar de 60 dólares para 10 pessoas», «ajuda-me a fazer tacos de frango» e «petiscos para a semana» em listas de compras editáveis. Gera uma lista com produtos disponíveis para compra, preços, fotografias, controlo de quantidades e botões simples para substituir qualquer artigo e concluir a compra. No caso de pedidos de restaurantes, são apresentados estabelecimentos e pratos que se integram no fluxo de compras nativo. Ambas as funcionalidades funcionam no mesmo cliente e na mesma infraestrutura da plataforma. Este artigo centra-se no caso de utilização de compras de supermercado, uma vez que este é o que coloca maior pressão sobre todas as principais complexidades da criação de uma interface intuitiva para compras orientadas por um agente. As listas de compras de supermercado contêm normalmente dez ou vinte itens, passam por várias rondas de revisão e têm de lidar facilmente com restrições do consumidor, como orçamentos e restrições alimentares.
As sessões de utilizadores de julho de 2026 revelaram que, nas sessões relacionadas com compras de mercearia em que era apresentada uma lista de compras, os consumidores realizaram, em média, cerca de duas interações com a interface do utilizador cada um. Cerca de um terço dessas sessões culminou na aplicação da lista a um carrinho de compras. O assistente capta a intenção geral dos consumidores e sintetiza-a. O resultado são componentes nativos, que permitem um refinamento granular por parte dos consumidores. As edições simples atualizam imediatamente um artefacto de referência, enquanto as alterações que exigem raciocínio dão início a uma nova ronda do agente.
Para criar uma experiência de compras colaborativa e eficaz entre o consumidor e o agente, os agentes de compras têm de se integrar numa interface interativa baseada em dados de comércio em tempo real e no contexto atual da aplicação do consumidor. Quando um consumidor está a fazer compras numa aplicação, espera ver, à primeira vista, artigos reais que possa adquirir. O texto pode descrever esse ambiente, mas os componentes interativos baseados em imagens permitem que os consumidores o percorram efetivamente. O contexto também é importante. Os consumidores que abrem a DoorDash têm expectativas diferentes das que têm em relação a uma aplicação de chat de uso geral. Fazem compras navegando, passando de lojas e páginas, em vez de descreverem o que querem. Ir ao encontro deles onde se encontram é uma peça essencial do quebra-cabeças.
As grandes coisas têm um início modesto
O assistente de compras da DoorDash começou por ser um projeto de hackathon. Sabíamos desde o início que a integração dos componentes existentes da DoorDash seria um elemento fundamental de tudo o que viéssemos a construir. As primeiras versões baseavam-se fortemente em carrosséis: primeiro, uma lista de lojas próximas em potencial; depois, um carrossel de resultados de pesquisa para cada artigo que o agente procurava. Eram apresentados em linha, cada um com o respetivo termo de pesquisa associado. O resultado era, essencialmente, um registo de conversa com resultados comerciais colados nele.
Em termos de funcionalidade, era semelhante ao que lançamos hoje. No que diz respeito à experiência do utilizador, era mais rudimentar, e vale a pena analisar os pormenores.
Depois de encontrar um conjunto de lojas, o assistente perguntou qual delas explorar e aguardou que a resposta fosse digitada. Cada carrossel representava um único artigo de que o consumidor precisava, e escolher uma opção adicionava esse artigo ao carrinho. Cada um aparecia com as opções dispostas em toda a largura do ecrã e a escolha ainda em aberto. Assim, organizar as compras para uma semana significava percorrer a lista, uma seleção de cada vez, sem possibilidade de selecionar um conjunto de artigos de uma só vez.
Por trás de tudo isto estava uma falha que se manifestava em ambos os sentidos: a interface tinha sido concebida principalmente para apresentar o trabalho do assistente. Cada carrossel era encabeçado pela consulta que o tinha gerado e os resultados apareciam na ordem em que tinham sido recuperados. Os termos de pesquisa e os conjuntos de resultados em bruto são o material de trabalho de um agente. Apresentar os resultados diretamente é o equivalente, na interface, a imprimir um rastreio da pilha. O assistente submetia-se com a mesma facilidade à interface, trabalhando um item de cada vez, porque uma pilha de carrosséis por item era o que o ecrã conseguia mostrar. Cada um tinha sido concebido em função das limitações do outro, em vez de ser concebido em função do utilizador.
A lição não foi que reutilizar componentes existentes fosse errado; a familiaridade que estes transmitem é precisamente a razão pela qual o assistente se assemelha ao DoorDash. Simplesmente, tínhamos criado o contentor errado para eles. É o contentor que determina a ordem em que aparecem, ao lado de que outros elementos se situam e o que um consumidor pode fazer com eles. Acima de tudo, um utilizador precisa de uma superfície de compras, em vez de uma interface de conversação. Tínhamos criado uma interface de conversação que, por acaso, continha componentes de compras. A reutilização de componentes deu-nos o vocabulário. Compô-lo numa superfície foi a parte mais difícil.
O que sobreviveu ao hackathon foi a base: a mesma infraestrutura de streaming que foi criada é aquela em que a experiência funciona atualmente. Entretanto, a camada de descodificação que transformava os resultados das ferramentas na interface do utilizador não perdurou. O assistente já não apresenta, de todo, os resultados das ferramentas. Em vez disso, investimos tempo na construção de uma arquitetura de artefactos que separa os requisitos dos utilizadores dos requisitos de armazenamento e dos agentes. Por outras palavras: deixámos de descodificar o material de trabalho do agente para o apresentar e começámos a construir em torno das necessidades dos diferentes componentes e utilizadores do sistema.

Figura 1: O mesmo pedido de compras, com um ano de diferença. A versão criada no hackathon apresentava um carrossel por artigo, cada um encabeçado pela consulta que o gerou; a seleção ficava a cargo do consumidor. Atualmente, o assistente apresenta cada lista como um cartão na conversa, com os artigos mais populares já selecionados.
Um objeto, três lentes
Uma lista de compras tem três leitores: o serviço que a armazena, o agente que a revê e a pessoa que faz as compras. Cada um precisa de ver algo diferente. Manter essas informações separadas é o que permite que a edição feita pelo consumidor apareça imediatamente e se mantenha válida sem exigir mais uma iteração do modelo.
O formulário guardado é o sistema de registo: um blob JSON armazenado como um artefacto no Managed Agent Services, conforme descrito na publicação da plataforma. Tem de estar completo e é a única cópia oficial.
O agente não lê esse blob diretamente. Uma lista de compras interativa contém muito mais detalhes do que um modelo necessita para a maioria das respostas. Repetir o nome de cada produto, preço, quantidade, substituição e cada elemento de metadados de apresentação a cada turno entraria em conflito com o que o consumidor realmente pediu. Assim, quando um agente emite um widget, o que permanece no contexto da conversa é um resumo compacto: a loja e o que a lista contém. Quando uma resposta requer o estado exato, o agente lê o artefacto e obtém uma visão reduzida, sem os metadados de exibição. Essa visão é inequívoca e suficientemente pequena para ser analisada de forma eficiente. Uma lista média ocupa entre 40 e 60 KB de JSON. O que permanece no contexto da conversa é uma única linha de cerca de 240 caracteres, aproximadamente 250 vezes menor.
O que o consumidor vê é diferente, e assume várias formas. Na conversa, a lista é apresentada como um widget compacto: a loja, o nome da lista, o tempo estimado de entrega, algumas fotos dos artigos e um botão «Adicionar ao carrinho» com o total estimado. Isso é suficiente para avaliar a lista num relance, sem sair do chat. Um botão «Ver lista» abre a visualização em página inteira, que apresenta a lista completa e tudo o que é necessário para a analisar em pormenor. Ambas as visualizações foram concebidas para serem compreendidas imediatamente e para que se possa agir diretamente a partir delas.
Um pormenor mostra até que ponto estas perspetivas divergem. Quando o agente escolhe um produto para um item da lista, mantém os outros produtos que corresponderam à mesma pesquisa, e o consumidor pode alternar entre eles com um toque. Mantém dez candidatos por item, e 99,7% dos itens têm correspondências suficientes para preencher esse número, pelo que quase todas as linhas na perspetiva do consumidor têm uma seleção e nove alternativas por trás dela. A visualização do consumidor apresenta todas essas alternativas. A visualização do agente não apresenta nenhuma delas, porque a escolha entre elas é da responsabilidade do consumidor (a menos que seja explicitamente pedido ao assistente para o fazer).

Manter os pés no chão
Com um carrinho que contém iogurte de framboesa, ao clicar em «Recomendar combinações para o carrinho» são apresentadas duas sugestões: granola, «porque combina com o seu iogurte», e mirtilos, «para adicionar fruta ao seu iogurte» (ver Figura 3). O caso de contraste já existe no nosso próprio produto, no mesmo ecrã: a página do carrinho apresenta um carrossel de artigos complementares que sugere artigos que o consumidor possa querer adicionar, sem qualquer justificação. O nosso agente do carrinho poderia ter apresentado exatamente isso: uma lista de itens plausíveis. Os itens poderiam muito bem ter sido os mesmos em qualquer dos casos. É a justificação que indica ao consumidor que a sugestão foi fundamentada e não apenas plausível e, uma vez que cada widget é também um local para agir, essa distinção tem um impacto real.
É isso que a integração com a realidade oferece: a diferença entre uma experiência de compras cativante e uma mera novidade. Se o resultado apresentado pelo assistente não for tangível, os consumidores têm poucos motivos para abandonar a rica experiência que a aplicação DoorDash já proporciona. O texto continua a desempenhar o seu papel, mas de forma secundária. Colocámos deliberadamente a lógica do assistente dentro dos widgets e à sua volta, em vez de mostrar as células dos itens exatamente como aparecem noutras partes da aplicação.
A integração também tem de ser assegurada ao nível dos dados, e aí o trabalho é dividido. Um agente escolhe um tipo de conteúdo suportado e fornece os dados comerciais correspondentes; o cliente iOS é responsável pela apresentação e interação, mapeando esse conteúdo para componentes nativos do sistema de design da DoorDash. Um pedido de mercearia gera uma lista de compras editável com quantidades, substituições e um subtotal. Um pedido de restaurante pode gerar fichas de loja, fichas de artigos ou sugestões para o carrinho.
É essa separação que fundamenta os próprios dados. Os valores comerciais num widget não provêm do modelo. Os preços, o inventário, o horário de funcionamento da loja e o conteúdo do carrinho são lidos a partir dos mesmos sistemas de registo que o resto da aplicação utiliza, pelo que um preço apresentado no Ask corresponde ao preço na página da loja naquele momento. O conteúdo tipado também proporciona ao backend e ao cliente um contrato estável. A implementação de um novo widget requer mais do que uma simples alteração no prompt. O agente tem de saber quando o utilizar e o que nele colocar, e o cliente precisa de um esquema nomeado, além do código para o descodificar e apresentar. Para além disso, um novo widget chega ao consumidor através do mesmo mecanismo de conversação e transmissão que qualquer outro.

Widgets como canais de E/S
Cada novo widget que integramos contribuiu para tornar o assistente mais funcional. A razão para isso tem tanto a ver com a entrada de dados como com a saída de resultados. Existe um limite que rege todos eles: uma edição determinística permanece no cliente e aplica-se diretamente ao artefacto, enquanto uma alteração que exija uma avaliação dá início a um ciclo do agente. Os exemplos abaixo estão organizados em função de onde essa linha se situa.
A versão do hackathon perguntava qual a loja que o consumidor pretendia e, em seguida, aguardava que este a escrevesse. Não tinha forma de escolher por si própria; hoje em dia, essa escolha é automática. Muitas outras perguntas ainda dependem do consumidor, e a introdução direta de texto pode ser uma forma pouco eficaz de recolher as respostas. A introdução de texto é uma limitação de fluxo único: o consumidor pode saber todas as respostas, mas só as consegue fornecer à velocidade a que consegue escrever ou falar.
É aqui que os widgets ganham o seu lugar. Um consumidor pode ter dez operações para aplicar a uma lista de compras, sendo cada uma delas simples. Individualmente, são triviais; quando descritas em prosa, tornam-se uma tarefa complexa. É a diferença entre olhar por cima do ombro de alguém e dizer-lhe quais os botões que deve premir, e premir os botões por si próprio.
As perguntas esclarecedoras estruturadas são o exemplo mais claro, e o padrão é inspirado nos agentes de codificação: a ferramenta AskUserQuestion da Claude Code desempenha a mesma função para os programadores. Disponibilizamos um widget que interrompe o consumidor com um pequeno conjunto de perguntas (de escolha múltipla e seleção múltipla), permitindo-lhe orientar a conversa em momentos genuinamente abertos. Tornou-se um pilar fundamental do modelo de interação no agente de mercearia e está agora a ser adotado no agente de restaurante para simplificar o mesmo tipo de interação. Integramos esta funcionalidade com a nossa plataforma de memória do consumidor, o que reduz significativamente as opções, mas continuam a existir lacunas de conhecimento que exigem a intervenção do consumidor. Fazer perguntas é inevitável. Mas podemos fazê-lo de uma forma que seja fácil e eficiente para o consumidor responder.
A visualização da lista em página inteira é onde a colaboração de entrada/saída se concretiza. Um consumidor pode alterar a quantidade de um artigo, eliminar um artigo, trocar um artigo por uma das alternativas que o assistente encontrou ao lado dele e adicionar a lista finalizada ao seu carrinho. Cada uma dessas ações manipula o artefacto diretamente. Nenhuma delas requer que o assistente atue em nome do consumidor, e nenhuma implica uma ida e volta ao LLM. O caso da troca aproveita melhor os conjuntos de candidatos da versão desenvolvida no hackathon. As alternativas entre as quais o consumidor escolhe são os outros candidatos que o assistente recuperou quando selecionou o artigo. A lista de todas as opções disponíveis para o consumidor preenchia anteriormente um carrossel. Agora, encontram-se a um toque de distância de uma decisão, em vez de se apresentarem diante do consumidor como uma questão em aberto.
A mudança de loja é a exceção, e a exceção é a parte interessante. Não se trata de uma alteração da lista existente. Transforma-se num pedido ao assistente que reconstrói a lista na loja alternativa. Esta interação também é rara: foi a primeira ação em 0,1% das sessões ativas, o que corresponde aproximadamente ao que esperaríamos se o limite fosse definido no ponto certo. Se essa linha for traçada no local errado, o consumidor ou espera que o assistente faça algo que poderia ter feito com um simples toque, ou tem de percorrer várias etapas com toques que poderiam ter beneficiado do discernimento do assistente.
O artefacto torna a divisão segura, e os dois lados escrevem nele de forma diferente. Uma alteração na quantidade, uma remoção ou uma troca segue o caminho mais curto: o cliente atualiza a lista no local e a alteração aparece imediatamente. Uma alteração de armazenamento, por outro lado, dá início a um ciclo do agente, porque é necessário recriar a correspondência de toda a lista com um catálogo diferente. Uma revisão do agente não sobrescreve o que lá estava; produz uma nova lista derivada da anterior.
O resultado é que uma edição direta tem carácter vinculativo. Antes de uma intervenção alterar a lista, o agente consulta a versão atual em vez de se basear na transcrição; assim, se o consumidor retirar o leite de aveia, a intervenção seguinte começa com uma lista que já não inclui o leite de aveia.
O comportamento observado durante o mesmo período mostra onde se situa essa linha. Imediatamente após o primeiro pedido, quase três quartos das primeiras ações seguintes ocorreram através de um componente. A partir da segunda mensagem, a situação inverte-se, e as respostas digitadas passam a constituir a maioria em todos os níveis de profundidade que medimos. Os controlos absorvem os ajustes imediatos e estruturados; a linguagem assume o controlo quando a alteração é mais significativa ou mais difícil de expressar com um toque.

Todas as revisões do assistente permanecem ativas
Quando o assistente revê uma lista de compras, a versão que substitui permanece no ecrã e continua a poder ser utilizada.
Essa não foi a nossa primeira implementação. A primeira versão ocultava as listas substituídas: assim que uma revisão era publicada, a lista subjacente deixava de poder ser visualizada ou editada. Uma lista atual, sem confusão. Parecia um comportamento mais organizado. No entanto, o que isso fez foi tornar a revisão algo dispendioso. Se solicitar uma alteração pudesse apagar uma lista com a qual se estava satisfeito, a atitude mais segura seria deixar de solicitar alterações, o que compromete todo o sentido de um fluxo colaborativo.
Assim, cada revisão auxiliar produz agora um novo artefacto derivado do anterior, e cada um permanece no local onde foi criado na conversa. Se recuar na página, as versões anteriores continuam todas lá, ainda ativas: um consumidor pode abrir uma lista anterior, editá-la ou adicioná-la ao seu carrinho em vez da versão mais recente. Pedir uma alteração não custa nada, porque o que tinham há um momento está à distância de um simples deslocamento para trás.
Nem todas as listas criadas pelo assistente se tornam uma versão que o consumidor vê. Quando o assistente elabora uma lista de sugestões e conclui que a loja não dispõe do que foi solicitado, essa lista nunca é apresentada. O consumidor é informado, por meio de texto, de que faltavam artigos na loja e que uma nova lista está a caminho. É um dos poucos casos em que a prosa desempenha o papel de forma direta e que ilustra a razão subjacente a tudo o resto neste artigo: a interação é utilizada para simplificar e o texto é utilizado para justificar.
Quando uma lista se transforma num carrinho
Um assistente que edita diretamente o carrinho pode remover um artigo que o consumidor pretendia comprar ou adicionar um que este nunca confirmou, sem que lhe seja pedido. Basta um único erro para perder a confiança do consumidor, porque a falha ocorre de forma silenciosa e afeta precisamente o que este está prestes a pagar.
Por isso, apresentamos, em vez disso, uma lista de compras como proposta. Esta pode conter dezenas de artigos e passar por várias rondas de revisão, quer isso signifique remover um produto da despensa que o consumidor já tenha, alterar uma quantidade, trocar um produto ou reformular parte de uma receita, e nada disso afeta o carrinho. Para confirmar a compra, é necessário clicar explicitamente em «Adicionar ao carrinho», que é a estrutura mais simples que encontrámos e que dá ao consumidor controlo real sem o obrigar a supervisionar cada passo.
Os dois elementos ainda têm de ser conciliados, e a escolha interessante é quem o faz. O assistente analisa o carrinho enquanto elabora a lista, mas não a ajusta automaticamente para que corresponda: se uma receita precisar de duas bananas, a lista pede duas, independentemente de já haver ou não quatro no carrinho. Elaborar a lista com exatamente o que foi solicitado e conciliá-la com o carrinho numa etapa separada permite manter cada decisão num único local.
Essa etapa surge no momento da confirmação. Quando a lista e o carrinho coincidem, são apresentadas ao consumidor as duplicatas e este decide se pretende substituir essas quantidades ou aumentá-las. É um momento breve, mas são momentos breves como este que determinam se se ganha ou se perde a confiança.
Transmitir o contexto em toda a plataforma DoorDash
Não basta que o assistente esteja disponível num único local; tem de ser acessível a partir de qualquer ponto da aplicação. Abrir o assistente já é um forte sinal de intenção, mas um sinal ambíguo. Um consumidor, nesse momento, pode estar a fazer uma encomenda num restaurante favorito, a comprar mantimentos para a semana, a procurar uns auscultadores novos ou a procurar apoio relativamente a uma encomenda anterior. Um consumidor que tenha acedido a uma determinada mercearia está a enviar um sinal muito mais claro: é provável que pretenda encher o carrinho nessa loja. Transmitir esse contexto ao assistente é o que lhe permite concentrar-se na intenção provável, em vez de ter de perguntar.
O sistema de âmbito que concebemos para este projeto abrange o cliente e o Gateway. O cliente associa elementos-chave do contexto de entrada a cada pedido: o tópico sob o qual o consumidor entrou (mercearia, restaurante), a loja que está a consultar e alguns identificadores relacionados. O Gateway utiliza o tópico para decidir a que agente encaminhar o pedido e os restantes elementos para fornecer às ferramentas os identificadores de que necessitam.
O Scope é, deliberadamente, um conjunto simples de pares chave-valor, em vez de um esquema tipado, e é o cliente que decide o que nele é incluído. As chaves não reconhecidas são transmitidas em vez de rejeitadas, pelo que uma nova superfície pode começar a enviar contexto sem ter de aguardar uma alteração no Gateway. A exceção é o próprio tópico: adicionar um novo implica indicar ao Gateway para que agente deve encaminhá-lo. Assim, embora uma nova superfície seja de baixo custo, um novo domínio não o é.
O tema é também a parte que se aplica apenas à primeira mensagem de um contexto. Isso dá ao assistente uma base sólida a partir da qual trabalhar, sem ser excessivamente prescritivo, e é o que permite aos utilizadores sair de um âmbito quando optam explicitamente por fazê-lo. Um utilizador que utilize o assistente dentro de um restaurante pode sair completamente do âmbito do restaurante, pedindo-lhe para «encontrar uma receita para este prato e preparar-me uma lista de compras, para que eu o possa fazer em casa». Esse pedido não é gratuito, mas o custo é um pequeno desvio no percurso, em vez de um beco sem saída: o agente do restaurante tem de reconhecer o pedido como estando fora do seu domínio e devolvê-lo antes que outro agente o receba.
Em certos casos, os âmbitos também nos permitem ignorar completamente o modelo. Tomemos como exemplo o ponto de entrada «Reordenar o meu último carrinho». Poderia simplesmente enviar essa frase ao assistente como uma mensagem e, embora isso funcionasse, anexar um âmbito permite-nos ser mais específicos. O caso «reordenar» é, na prática, determinístico, pelo que podemos contornar o LLM e devolver uma lista de compras quase imediatamente. O que é devolvido é um widget comum de lista de compras: o consumidor pode alterar quantidades, trocar produtos ou pedir ao assistente para a rever no chat, exatamente como faria com qualquer outra lista. Note-se que esta omissão só se aplica se a loja ainda tiver todos os artigos do carrinho anterior; se um artigo não estiver disponível, o pedido é encaminhado para o agente de mercearia, que reconstrói a lista da mesma forma que faria a partir de um pedido digitado.
O escopo é também o que torna possível uma conversa única e contínua ao longo de uma sessão da aplicação, mas só funciona porque o escopo, a associação de agentes e o estado da sessão são mantidos separados. Tratamos o âmbito como um contexto por turno. A fixação, descrita anteriormente nesta série de publicações do blogue, mantém os turnos de acompanhamento com o agente que resolveu o turno anterior. Tanto a fixação como a transcrição (a conversa propriamente dita) são associadas ao chat e não ao âmbito; assim, um consumidor que se desloca de uma loja para outra redireciona a fixação para um agente de um novo domínio sem descartar o que foi dito. Vários agentes especializam-se internamente, e o sistema continua a comportar-se como um único assistente.

Conclusão
A integração de agentes em produtos de consumo ainda está numa fase inicial. No entanto, as bases estão a tornar-se claras. Os widgets são onde os consumidores realizam o trabalho e a interação entre o consumidor e o agente é o que os orienta. Existem atualmente três «leitores» do nosso artefacto de lista de compras, cada um dos quais necessita de uma perspetiva diferente do mesmo. Utilizamos a parte voltada para o utilizador para ancorar o consumidor em produtos reais e para tornar as modificações comuns ações com um único toque. À medida que os agentes assumem mais tarefas, esperamos que o que um consumidor precisa de ver e o que um agente precisa de analisar continuem a mudar, e que a linha divisória entre uma interface de aplicação e uma interface de chat se torne mais difícil de traçar.


































