mirror of
https://github.com/hoshikawa2/agent_platform_oci.git
synced 2026-11-06 03:14:12 +00:00
bugfix: Multi-item
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
# Implementação prática — MCP Multi-Item
|
||||
|
||||
Este documento mostra o caminho mínimo para adicionar uma operação multi-item a um agente sem criar lógica paralela no código do agente.
|
||||
|
||||
## 1. Modele uma única operação lógica
|
||||
|
||||
Exemplo de requisito:
|
||||
|
||||
```text
|
||||
quero cancelar Produto A, Produto B e Produto C
|
||||
```
|
||||
|
||||
A operação lógica deve continuar sendo uma só:
|
||||
|
||||
```text
|
||||
cancelar_produtos
|
||||
```
|
||||
|
||||
Não crie `cancelar_produto_1`, `cancelar_produto_2`, loops no agent ou intents artificiais por item.
|
||||
|
||||
## 2. Declare a coleção em `tools.yaml`
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
cancelar_produtos:
|
||||
description: Cancela um ou mais produtos do cliente.
|
||||
mcp_server: contas
|
||||
enabled: true
|
||||
tool_type: action
|
||||
confirmation_required: true
|
||||
requires: [items]
|
||||
args_schema:
|
||||
items:
|
||||
type: array
|
||||
label: os produtos
|
||||
description: Lista de produtos a cancelar.
|
||||
user_prompt: Quais produtos deseja cancelar?
|
||||
```
|
||||
|
||||
Também é aceito `type: list` quando o projeto já usa essa forma.
|
||||
|
||||
## 3. Use a policy transacional existente
|
||||
|
||||
```yaml
|
||||
tool_policies:
|
||||
cancelar_produtos:
|
||||
operation_type: transactional
|
||||
require_confirmation: true
|
||||
requires: [items]
|
||||
pre_validation:
|
||||
enabled: true
|
||||
tool: validar_produtos_cancelamento
|
||||
fail_open: false
|
||||
```
|
||||
|
||||
Nenhuma chave específica de multi-item é necessária.
|
||||
|
||||
## 4. Canonicalize os itens no MCP validator
|
||||
|
||||
Entrada possível:
|
||||
|
||||
```json
|
||||
{
|
||||
"items": ["produto a", "produto b", "produto c"]
|
||||
}
|
||||
```
|
||||
|
||||
Saída recomendada:
|
||||
|
||||
```json
|
||||
{
|
||||
"eligible": true,
|
||||
"status": "ELIGIBLE",
|
||||
"transaction_decision": {
|
||||
"resolved_arguments": {
|
||||
"items": [
|
||||
{"name": "Produto A", "id": "1001"},
|
||||
{"name": "Produto B", "id": "1002"},
|
||||
{"name": "Produto C", "id": "1003"}
|
||||
]
|
||||
},
|
||||
"target_tool": "cancelar_produtos",
|
||||
"confirmation_message": "Você confirma o cancelamento de Produto A, Produto B e Produto C?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
O validator deve ser side-effect-free.
|
||||
|
||||
## 5. Não transforme uma falha individual em rejeição global
|
||||
|
||||
Caso:
|
||||
|
||||
```text
|
||||
A = válido
|
||||
B = inválido
|
||||
C = válido
|
||||
```
|
||||
|
||||
Se A e C ainda podem ser executados, não use simplesmente:
|
||||
|
||||
```json
|
||||
{
|
||||
"eligible": false,
|
||||
"reason": "B inválido"
|
||||
}
|
||||
```
|
||||
|
||||
Isso encerraria a transação inteira.
|
||||
|
||||
Prefira manter a transação elegível quando houver item acionável e preservar informação suficiente para a tool primária produzir o resultado final por item.
|
||||
|
||||
## 6. Execute a coleção no MCP Server ou workflow
|
||||
|
||||
### Backend com API batch
|
||||
|
||||
```python
|
||||
async def cancelar_produtos(items):
|
||||
response = await backend.cancel_batch(items)
|
||||
return normalize_results(response)
|
||||
```
|
||||
|
||||
### Backend com API apenas unitária
|
||||
|
||||
```python
|
||||
async def cancelar_produtos(items):
|
||||
results = []
|
||||
for item in items:
|
||||
try:
|
||||
response = await backend.cancel_one(item)
|
||||
results.append({
|
||||
"name": item["name"],
|
||||
"success": True,
|
||||
"response": response,
|
||||
})
|
||||
except Exception as exc:
|
||||
results.append({
|
||||
"name": item["name"],
|
||||
"success": False,
|
||||
"error": str(exc),
|
||||
})
|
||||
return {"results": results}
|
||||
```
|
||||
|
||||
O loop acima pertence ao MCP/workflow, **não ao Agent**.
|
||||
|
||||
## 7. Retorne `results[]` por item
|
||||
|
||||
Contrato mínimo:
|
||||
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{"name": "Produto A", "success": true},
|
||||
{"name": "Produto B", "success": false, "error": "not_found"},
|
||||
{"name": "Produto C", "success": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
O framework aceita `success` ou `ok` booleano por item.
|
||||
|
||||
## 8. Resultado interpretado pelo framework
|
||||
|
||||
No exemplo anterior:
|
||||
|
||||
```text
|
||||
items_count = 3
|
||||
items_succeeded_count = 2
|
||||
items_failed_count = 1
|
||||
multi_item_status = PARTIAL_SUCCESS
|
||||
```
|
||||
|
||||
O framework preserva os resultados terminais e fornece esse contexto para composição/presentation.
|
||||
|
||||
## 9. Workflow com etapa auxiliar
|
||||
|
||||
Estrutura recomendada:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "COMPLETED",
|
||||
"output": {
|
||||
"cancelar_produtos": {
|
||||
"results": [
|
||||
{"name": "A", "success": true},
|
||||
{"name": "B", "success": true}
|
||||
]
|
||||
},
|
||||
"registrar_analitica": {
|
||||
"success": false,
|
||||
"error": "analytics unavailable"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
O resultado autoritativo da operação principal deve estar em:
|
||||
|
||||
```text
|
||||
workflow.output[cancelar_produtos].results
|
||||
```
|
||||
|
||||
Assim uma falha auxiliar não converte A e B em falha operacional.
|
||||
|
||||
## 10. Checklist do desenvolvedor
|
||||
|
||||
Antes de criar código adicional, verifique:
|
||||
|
||||
- [ ] existe uma única tool lógica para a operação;
|
||||
- [ ] a coleção está declarada como `array` ou `list` em `tools.yaml`;
|
||||
- [ ] confirmação/pre-validation usam `tool_policies.yaml` existente;
|
||||
- [ ] canonicalização pertence ao MCP validator;
|
||||
- [ ] fan-out, se necessário, pertence ao MCP Server/workflow;
|
||||
- [ ] a tool primária devolve `results[]`;
|
||||
- [ ] cada item contém `success` ou `ok` booleano;
|
||||
- [ ] sucessos parciais não são apagados por uma falha global posterior;
|
||||
- [ ] a apresentação comunica sucesso/falha por item;
|
||||
- [ ] não foi criado um segundo motor multi-item no Agent.
|
||||
|
||||
## 11. Testes mínimos recomendados
|
||||
|
||||
Cubra ao menos:
|
||||
|
||||
```text
|
||||
1 item / sucesso
|
||||
N itens / todos sucesso
|
||||
N itens / sucesso parcial
|
||||
N itens / todos falha
|
||||
item não canonicalizado
|
||||
confirmação única para N itens
|
||||
falha auxiliar após sucesso primário
|
||||
replay/idempotência da mesma operação
|
||||
```
|
||||
|
||||
Para detalhes do contrato interno do runtime, consulte `docs/MCP_MULTI_ITEM_DEVELOPER_GUIDE.md`.
|
||||
229
Tuning-Performance/Multi_Item_MCP/README.md
Normal file
229
Tuning-Performance/Multi_Item_MCP/README.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# Multi-Item MCP
|
||||
|
||||
Capability de referência para operações MCP que precisam processar **mais de um item do mesmo tipo** em uma única intenção: produtos, pedidos, VAS, ativos, faturas, linhas, contratos ou recursos.
|
||||
|
||||
> Esta capability é **framework-native**. Ela não exige um motor multi-item dentro do agente e não adiciona novos atributos obrigatórios a `tools.yaml` ou `tool_policies.yaml`.
|
||||
|
||||
## Quando usar
|
||||
|
||||
Use quando o usuário puder solicitar, por exemplo:
|
||||
|
||||
```text
|
||||
cancele Produto A, Produto B e Produto C
|
||||
```
|
||||
|
||||
ou:
|
||||
|
||||
```text
|
||||
consulte os pedidos 1001, 1002 e 1003
|
||||
```
|
||||
|
||||
O desenvolvedor deve modelar **uma operação lógica** que receba a coleção. O framework cuida de estado, confirmação e interpretação de resultados; o MCP Server ou workflow de domínio cuida da execução dos itens.
|
||||
|
||||
## Divisão de responsabilidades
|
||||
|
||||
```text
|
||||
Agent
|
||||
seleciona a operação
|
||||
NÃO cria motor multi-item
|
||||
|
||||
↓
|
||||
|
||||
tools.yaml
|
||||
declara array/list
|
||||
NÃO exige chave multi_item
|
||||
|
||||
↓
|
||||
|
||||
tool_policies.yaml
|
||||
confirmação + pre-validation
|
||||
usa o mesmo contrato transacional existente
|
||||
|
||||
↓
|
||||
|
||||
MCP validator
|
||||
resolve/canonicaliza os itens
|
||||
pode preencher transaction_decision.resolved_arguments
|
||||
|
||||
↓
|
||||
|
||||
MCP tool / workflow
|
||||
executa os itens
|
||||
devolve results[] com success/ok por item
|
||||
|
||||
↓
|
||||
|
||||
Agent Framework
|
||||
mantém estado
|
||||
controla confirmação
|
||||
interpreta results[]
|
||||
preserva evidência por item
|
||||
calcula SUCCESS / PARTIAL_SUCCESS / FAILED
|
||||
|
||||
↓
|
||||
|
||||
LLM / Presentation
|
||||
apresenta cada sucesso/falha
|
||||
```
|
||||
|
||||
## Configuração mínima
|
||||
|
||||
### `tools.yaml`
|
||||
|
||||
O modo de configuração continua o mesmo. Declare o parâmetro como `array` ou `list`:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
cancelar_produtos:
|
||||
description: Cancela um ou mais produtos.
|
||||
mcp_server: contas
|
||||
enabled: true
|
||||
tool_type: action
|
||||
confirmation_required: true
|
||||
requires: [items]
|
||||
args_schema:
|
||||
items:
|
||||
type: array
|
||||
label: os produtos
|
||||
description: Produtos solicitados pelo cliente.
|
||||
user_prompt: Informe quais produtos deseja cancelar.
|
||||
```
|
||||
|
||||
Não é necessário criar configuração como:
|
||||
|
||||
```yaml
|
||||
# NÃO EXISTE / NÃO É NECESSÁRIO
|
||||
multi_item: true
|
||||
multi_item_strategy: partial
|
||||
fan_out: framework
|
||||
```
|
||||
|
||||
### `tool_policies.yaml`
|
||||
|
||||
O contrato também continua o mesmo:
|
||||
|
||||
```yaml
|
||||
tool_policies:
|
||||
cancelar_produtos:
|
||||
operation_type: transactional
|
||||
require_confirmation: true
|
||||
requires: [items]
|
||||
pre_validation:
|
||||
enabled: true
|
||||
tool: validar_produtos_cancelamento
|
||||
fail_open: false
|
||||
```
|
||||
|
||||
## Pre-validation e lista canônica
|
||||
|
||||
O validator pode transformar nomes informais em uma coleção canônica antes da confirmação:
|
||||
|
||||
```json
|
||||
{
|
||||
"eligible": true,
|
||||
"transaction_decision": {
|
||||
"resolved_arguments": {
|
||||
"items": [
|
||||
{"name": "Produto A", "id": "1001"},
|
||||
{"name": "Produto B", "id": "1002"},
|
||||
{"name": "Produto C", "id": "1003"}
|
||||
]
|
||||
},
|
||||
"target_tool": "cancelar_produtos",
|
||||
"confirmation_message": "Você confirma o cancelamento de Produto A, Produto B e Produto C?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Validação parcial
|
||||
|
||||
`eligible` é global para a transação. Portanto, se pelo menos um item puder ser processado, o validator **não deve reprovar o lote inteiro apenas porque outro item falhou**.
|
||||
|
||||
Padrão recomendado:
|
||||
|
||||
1. `eligible: true` quando existe pelo menos um item acionável;
|
||||
2. preservar/canonicalizar todos os itens necessários em `resolved_arguments`;
|
||||
3. executar a operação primária;
|
||||
4. retornar o resultado terminal individual em `results[]`.
|
||||
|
||||
Se nenhum item puder ser processado, `eligible: false` é apropriado.
|
||||
|
||||
## Resultado MCP esperado
|
||||
|
||||
A tool primária deve retornar `results[]` com `success` ou `ok` booleano por item:
|
||||
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{"name": "Produto A", "success": true},
|
||||
{"name": "Produto B", "success": false, "error": "not_found"},
|
||||
{"name": "Produto C", "success": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
O framework deriva automaticamente:
|
||||
|
||||
```text
|
||||
PARTIAL_SUCCESS
|
||||
2 succeeded
|
||||
1 failed
|
||||
```
|
||||
|
||||
Estados possíveis:
|
||||
|
||||
| Resultado dos itens | Status do framework |
|
||||
|---|---|
|
||||
| todos concluídos | `SUCCESS` |
|
||||
| alguns concluídos e alguns falharam | `PARTIAL_SUCCESS` |
|
||||
| todos falharam | `FAILED` |
|
||||
|
||||
## Uma chamada lógica, não N chamadas no agente
|
||||
|
||||
Se o backend suporta batch, prefira:
|
||||
|
||||
```text
|
||||
Agent -> cancelar_produtos(items=[A,B,C]) -> MCP
|
||||
```
|
||||
|
||||
Se o backend possui apenas API unitária, o fan-out deve ficar encapsulado no MCP Server ou no workflow de domínio:
|
||||
|
||||
```text
|
||||
Agent -> cancelar_produtos(items=[A,B,C])
|
||||
|
|
||||
v
|
||||
MCP/workflow
|
||||
/ | \
|
||||
A B C
|
||||
\ | /
|
||||
results[]
|
||||
```
|
||||
|
||||
Evite:
|
||||
|
||||
```python
|
||||
# NÃO: lógica multi-item dentro do agente
|
||||
for item in items:
|
||||
await tool_router.call("cancelar_produto", {"item": item})
|
||||
```
|
||||
|
||||
## Workflow-backed tools
|
||||
|
||||
Quando a operação é implementada por workflow, o caminho preferencial do resultado primário é:
|
||||
|
||||
```text
|
||||
workflow.output[tool_name].results
|
||||
```
|
||||
|
||||
Isso permite distinguir a operação primária de etapas auxiliares. Uma falha posterior não deve apagar o sucesso terminal de itens já executados.
|
||||
|
||||
## Documentação completa
|
||||
|
||||
Consulte também:
|
||||
|
||||
- `docs/MCP_MULTI_ITEM_DEVELOPER_GUIDE.md` — guia canônico em português;
|
||||
- `docs/MCP_MULTI_ITEM_DEVELOPER_GUIDE_en.md` — guia canônico em inglês;
|
||||
- `templates/agent_template_backend/docs/MCP_MULTI_ITEM.md` — referência junto ao template;
|
||||
- `specs/SPEC-010-Agent-Development.md` — regra arquitetural de desenvolvimento.
|
||||
|
||||
Para um passo a passo prático, leia `IMPLEMENTACAO_MULTI_ITEM_MCP.md` nesta pasta.
|
||||
69
Tuning-Performance/Multi_Item_MCP/README_en.md
Normal file
69
Tuning-Performance/Multi_Item_MCP/README_en.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Multi-Item MCP
|
||||
|
||||
Reference capability for MCP operations that process **multiple items of the same kind** in one user intent: products, orders, services, assets, invoices, lines, contracts, or resources.
|
||||
|
||||
This capability is **framework-native**. It does not require a multi-item engine in the agent and does not introduce new mandatory keys in `tools.yaml` or `tool_policies.yaml`.
|
||||
|
||||
```text
|
||||
Agent selects the operation; no fan-out engine
|
||||
-> tools.yaml declares array/list
|
||||
-> tool_policies.yaml confirmation + pre-validation
|
||||
-> MCP validator resolves/canonicalizes items
|
||||
-> MCP tool/workflow executes items and returns results[]
|
||||
-> Agent Framework preserves per-item evidence and derives
|
||||
SUCCESS / PARTIAL_SUCCESS / FAILED
|
||||
-> Presentation reports each success/failure
|
||||
```
|
||||
|
||||
## Minimal configuration
|
||||
|
||||
`tools.yaml` keeps the existing list contract:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
cancel_products:
|
||||
requires: [items]
|
||||
args_schema:
|
||||
items:
|
||||
type: array
|
||||
```
|
||||
|
||||
`tool_policies.yaml` also keeps the current transaction contract:
|
||||
|
||||
```yaml
|
||||
tool_policies:
|
||||
cancel_products:
|
||||
operation_type: transactional
|
||||
require_confirmation: true
|
||||
requires: [items]
|
||||
pre_validation:
|
||||
enabled: true
|
||||
tool: validate_products_for_cancellation
|
||||
fail_open: false
|
||||
```
|
||||
|
||||
No `multi_item: true`, framework fan-out flag, or extra agent code is required.
|
||||
|
||||
## MCP result contract
|
||||
|
||||
The primary tool should return `results[]` with boolean `success` or `ok` per item:
|
||||
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{"name": "A", "success": true},
|
||||
{"name": "B", "success": false, "error": "not_found"},
|
||||
{"name": "C", "success": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The framework derives `PARTIAL_SUCCESS` for the example above and preserves the successful items.
|
||||
|
||||
If the downstream system only supports single-item APIs, put the fan-out inside the MCP Server or domain workflow, not inside the agent.
|
||||
|
||||
For the complete contract see:
|
||||
|
||||
- `docs/MCP_MULTI_ITEM_DEVELOPER_GUIDE_en.md`
|
||||
- `docs/MCP_MULTI_ITEM_DEVELOPER_GUIDE.md`
|
||||
- `IMPLEMENTACAO_MULTI_ITEM_MCP.md`
|
||||
Reference in New Issue
Block a user