mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-26 08:56:21 +02:00
Structure the tech specs directory (#836)
Tech spec some subdirectories for different languages
This commit is contained in:
parent
48da6c5f8b
commit
e7efb673ef
423 changed files with 0 additions and 0 deletions
479
docs/tech-specs/pt/tool-services.pt.md
Normal file
479
docs/tech-specs/pt/tool-services.pt.md
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
---
|
||||
layout: default
|
||||
title: "Serviços de Ferramentas: Ferramentas de Agente Dinamicamente Plugáveis"
|
||||
parent: "Portuguese (Beta)"
|
||||
---
|
||||
|
||||
# Serviços de Ferramentas: Ferramentas de Agente Dinamicamente Plugáveis
|
||||
|
||||
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
||||
|
||||
## Status
|
||||
|
||||
Implementado
|
||||
|
||||
## Visão Geral
|
||||
|
||||
Esta especificação define um mecanismo para ferramentas de agente dinamicamente plugáveis, chamadas "serviços de ferramentas". Ao contrário dos tipos de ferramentas integradas existentes (`KnowledgeQueryImpl`, `McpToolImpl`, etc.), os serviços de ferramentas permitem que novas ferramentas sejam introduzidas por:
|
||||
|
||||
1. Implantando um novo serviço baseado em Pulsar
|
||||
2. Adicionando um descritor de configuração que informa ao agente como invocá-lo
|
||||
|
||||
Isso permite a extensibilidade sem modificar o framework de resposta do agente principal.
|
||||
|
||||
## Terminologia
|
||||
|
||||
| Termo | Definição |
|
||||
|------|------------|
|
||||
| **Ferramenta Integrada** | Tipos de ferramentas existentes com implementações codificadas em `tools.py` |
|
||||
| **Serviço de Ferramenta** | Um serviço Pulsar que pode ser invocado como uma ferramenta de agente, definido por um descritor de serviço |
|
||||
| **Ferramenta** | Uma instância configurada que referencia um serviço de ferramenta, exposta ao agente/LLM |
|
||||
|
||||
Este é um modelo de duas camadas, análogo às ferramentas MCP:
|
||||
MCP: O servidor MCP define a interface da ferramenta → A configuração da ferramenta a referencia
|
||||
Serviços de Ferramenta: O serviço de ferramenta define a interface Pulsar → A configuração da ferramenta a referencia
|
||||
|
||||
## Contexto: Ferramentas Existentes
|
||||
|
||||
### Implementação de Ferramenta Integrada
|
||||
|
||||
As ferramentas são atualmente definidas em `trustgraph-flow/trustgraph/agent/react/tools.py` com implementações tipadas:
|
||||
|
||||
```python
|
||||
class KnowledgeQueryImpl:
|
||||
async def invoke(self, question):
|
||||
client = self.context("graph-rag-request")
|
||||
return await client.rag(question, self.collection)
|
||||
```
|
||||
|
||||
Cada tipo de ferramenta:
|
||||
Possui um serviço Pulsar pré-definido que ele chama (por exemplo, `graph-rag-request`)
|
||||
Conhece o método exato a ser chamado no cliente (por exemplo, `client.rag()`)
|
||||
Possui argumentos tipados definidos na implementação
|
||||
|
||||
### Registro de Ferramentas (service.py:105-214)
|
||||
|
||||
As ferramentas são carregadas da configuração com um campo `type` que mapeia para uma implementação:
|
||||
|
||||
```python
|
||||
if impl_id == "knowledge-query":
|
||||
impl = functools.partial(KnowledgeQueryImpl, collection=data.get("collection"))
|
||||
elif impl_id == "text-completion":
|
||||
impl = TextCompletionImpl
|
||||
# ... etc
|
||||
```
|
||||
|
||||
## Arquitetura
|
||||
|
||||
### Modelo de Duas Camadas
|
||||
|
||||
#### Camada 1: Descritor do Serviço de Ferramenta
|
||||
|
||||
Um serviço de ferramenta define uma interface de serviço Pulsar. Ele declara:
|
||||
As filas Pulsar para solicitação/resposta
|
||||
Os parâmetros de configuração que ele requer das ferramentas que o utilizam
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "custom-rag",
|
||||
"request-queue": "non-persistent://tg/request/custom-rag",
|
||||
"response-queue": "non-persistent://tg/response/custom-rag",
|
||||
"config-params": [
|
||||
{"name": "collection", "required": true}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Um serviço de ferramenta que não requer parâmetros de configuração:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "calculator",
|
||||
"request-queue": "non-persistent://tg/request/calc",
|
||||
"response-queue": "non-persistent://tg/response/calc",
|
||||
"config-params": []
|
||||
}
|
||||
```
|
||||
|
||||
#### Nível 2: Descritor de Ferramenta
|
||||
|
||||
Uma ferramenta referencia um serviço de ferramenta e fornece:
|
||||
Valores de parâmetros de configuração (que satisfazem os requisitos do serviço)
|
||||
Metadados da ferramenta para o agente (nome, descrição)
|
||||
Definições de argumentos para o LLM
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "query-customers",
|
||||
"description": "Query the customer knowledge base",
|
||||
"service": "custom-rag",
|
||||
"collection": "customers",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"description": "The question to ask about customers"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Múltiplas ferramentas podem referenciar o mesmo serviço com diferentes configurações:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "query-products",
|
||||
"description": "Query the product knowledge base",
|
||||
"service": "custom-rag",
|
||||
"collection": "products",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"description": "The question to ask about products"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Formato da Requisição
|
||||
|
||||
Quando uma ferramenta é invocada, a requisição ao serviço da ferramenta inclui:
|
||||
`user`: Do pedido do agente (multi-tenência)
|
||||
`config`: Valores de configuração codificados em JSON, provenientes da descrição da ferramenta
|
||||
`arguments`: Argumentos codificados em JSON, provenientes do LLM
|
||||
|
||||
```json
|
||||
{
|
||||
"user": "alice",
|
||||
"config": "{\"collection\": \"customers\"}",
|
||||
"arguments": "{\"question\": \"What are the top customer complaints?\"}"
|
||||
}
|
||||
```
|
||||
|
||||
O serviço de ferramenta recebe estes como dicionários analisados no método `invoke`.
|
||||
|
||||
### Implementação Genérica do Serviço de Ferramenta
|
||||
|
||||
Uma classe `ToolServiceImpl` invoca serviços de ferramenta com base na configuração:
|
||||
|
||||
```python
|
||||
class ToolServiceImpl:
|
||||
def __init__(self, context, request_queue, response_queue, config_values, arguments, processor):
|
||||
self.request_queue = request_queue
|
||||
self.response_queue = response_queue
|
||||
self.config_values = config_values # e.g., {"collection": "customers"}
|
||||
# ...
|
||||
|
||||
async def invoke(self, **arguments):
|
||||
client = await self._get_or_create_client()
|
||||
response = await client.call(user, self.config_values, arguments)
|
||||
if isinstance(response, str):
|
||||
return response
|
||||
else:
|
||||
return json.dumps(response)
|
||||
```
|
||||
|
||||
## Decisões de Design
|
||||
|
||||
### Modelo de Configuração de Duas Camadas
|
||||
|
||||
Os serviços de ferramentas seguem um modelo de duas camadas semelhante às ferramentas MCP:
|
||||
|
||||
1. **Serviço de Ferramenta**: Define a interface do serviço Pulsar (tópico, parâmetros de configuração necessários)
|
||||
2. **Ferramenta**: Referencia um serviço de ferramenta, fornece valores de configuração, define argumentos do LLM
|
||||
|
||||
Essa separação permite:
|
||||
Que um único serviço de ferramenta seja usado por várias ferramentas com diferentes configurações
|
||||
Uma distinção clara entre a interface do serviço e a configuração da ferramenta
|
||||
A reutilização das definições de serviço
|
||||
|
||||
### Mapeamento de Solicitações: Transmissão com Envelope
|
||||
|
||||
A solicitação a um serviço de ferramenta é um envelope estruturado contendo:
|
||||
`user`: Propagado do pedido do agente para multi-inquilinato
|
||||
Valores de configuração: Do descritor da ferramenta (por exemplo, `collection`)
|
||||
`arguments`: Argumentos fornecidos pelo LLM, transmitidos como um dicionário
|
||||
|
||||
O gerenciador de agente analisa a resposta do LLM em `act.arguments` como um dicionário (`agent_manager.py:117-154`). Este dicionário é incluído no envelope da solicitação.
|
||||
|
||||
### Tratamento de Esquemas: Não Tipados
|
||||
|
||||
As solicitações e respostas usam dicionários não tipados. Não há validação de esquema no nível do agente - o serviço de ferramenta é responsável por validar suas entradas. Isso fornece o máximo de flexibilidade para definir novos serviços.
|
||||
|
||||
### Interface do Cliente: Tópicos Pulsar Diretos
|
||||
|
||||
Os serviços de ferramentas usam tópicos Pulsar diretos, sem a necessidade de configuração de fluxo. O descritor do serviço de ferramenta especifica os nomes completos das filas:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [...]
|
||||
}
|
||||
```
|
||||
|
||||
Isso permite que os serviços sejam hospedados em qualquer namespace.
|
||||
|
||||
### Tratamento de Erros: Convenção de Erro Padrão
|
||||
|
||||
As respostas do serviço de ferramenta seguem a convenção de esquema existente com um campo `error`:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Error:
|
||||
type: str = ""
|
||||
message: str = ""
|
||||
```
|
||||
|
||||
Estrutura da resposta:
|
||||
Sucesso: `error` é `None`, a resposta contém o resultado
|
||||
Erro: `error` é preenchido com `type` e `message`
|
||||
|
||||
Isso corresponde ao padrão usado em todo o serviço existente (por exemplo, `PromptResponse`, `QueryResponse`, `AgentResponse`).
|
||||
|
||||
### Correlação de Requisições/Respostas
|
||||
|
||||
As requisições e respostas são correlacionadas usando um `id` nas propriedades da mensagem Pulsar:
|
||||
|
||||
A requisição inclui `id` nas propriedades: `properties={"id": id}`
|
||||
A(s) resposta(s) incluem o mesmo `id`: `properties={"id": id}`
|
||||
|
||||
Isso segue o padrão existente usado em todo o código-fonte (por exemplo, `agent_service.py`, `llm_service.py`).
|
||||
|
||||
### Suporte a Streaming
|
||||
|
||||
Os serviços de ferramenta podem retornar respostas em streaming:
|
||||
|
||||
Múltiplas mensagens de resposta com o mesmo `id` nas propriedades
|
||||
Cada resposta inclui o campo `end_of_stream: bool`
|
||||
A resposta final tem `end_of_stream: True`
|
||||
|
||||
Isso corresponde ao padrão usado em `AgentResponse` e outros serviços de streaming.
|
||||
|
||||
### Tratamento da Resposta: Retorno de String
|
||||
|
||||
Todas as ferramentas existentes seguem o mesmo padrão: **receber argumentos como um dicionário, retornar a observação como uma string**.
|
||||
|
||||
| Ferramenta | Tratamento da Resposta |
|
||||
|------|------------------|
|
||||
| `KnowledgeQueryImpl` | Retorna `client.rag()` diretamente (string) |
|
||||
| `TextCompletionImpl` | Retorna `client.question()` diretamente (string) |
|
||||
| `McpToolImpl` | Retorna uma string, ou `json.dumps(output)` se não for uma string |
|
||||
| `StructuredQueryImpl` | Formata o resultado para uma string |
|
||||
| `PromptImpl` | Retorna `client.prompt()` diretamente (string) |
|
||||
|
||||
Os serviços de ferramenta seguem o mesmo contrato:
|
||||
O serviço retorna uma resposta em string (a observação)
|
||||
Se a resposta não for uma string, ela é convertida via `json.dumps()`
|
||||
Nenhuma configuração de extração é necessária no descritor
|
||||
|
||||
Isso mantém o descritor simples e coloca a responsabilidade de retornar uma resposta de texto apropriada para o agente no serviço.
|
||||
|
||||
## Guia de Configuração
|
||||
|
||||
Para adicionar um novo serviço de ferramenta, são necessários dois itens de configuração:
|
||||
|
||||
### 1. Configuração do Serviço de Ferramenta
|
||||
|
||||
Armazenado sob a chave de configuração `tool-service`. Define as filas Pulsar e os parâmetros de configuração disponíveis.
|
||||
|
||||
| Campo | Obrigatório | Descrição |
|
||||
|-------|----------|-------------|
|
||||
| `id` | Sim | Identificador único para o serviço de ferramenta |
|
||||
| `request-queue` | Sim | Tópico Pulsar completo para requisições (por exemplo, `non-persistent://tg/request/joke`) |
|
||||
| `response-queue` | Sim | Tópico Pulsar completo para respostas (por exemplo, `non-persistent://tg/response/joke`) |
|
||||
| `config-params` | Não | Array de parâmetros de configuração que o serviço aceita |
|
||||
|
||||
Cada parâmetro de configuração pode especificar:
|
||||
`name`: Nome do parâmetro (obrigatório)
|
||||
`required`: Se o parâmetro deve ser fornecido pelas ferramentas (padrão: falso)
|
||||
|
||||
Exemplo:
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [
|
||||
{"name": "style", "required": false}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Configuração da Ferramenta
|
||||
|
||||
Armazenado sob a chave de configuração `tool`. Define uma ferramenta que o agente pode usar.
|
||||
|
||||
| Campo | Obrigatório | Descrição |
|
||||
|-------|----------|-------------|
|
||||
| `type` | Sim | Deve ser `"tool-service"` |
|
||||
| `name` | Sim | Nome da ferramenta exposto para o LLM |
|
||||
| `description` | Sim | Descrição do que a ferramenta faz (mostrada para o LLM) |
|
||||
| `service` | Sim | ID do serviço de ferramenta a ser invocado |
|
||||
| `arguments` | Não | Array de definições de argumentos para o LLM |
|
||||
| *(parâmetros de configuração)* | Varia | Quaisquer parâmetros de configuração definidos pelo serviço |
|
||||
|
||||
Cada argumento pode especificar:
|
||||
`name`: Nome do argumento (obrigatório)
|
||||
`type`: Tipo de dados, por exemplo, `"string"` (obrigatório)
|
||||
`description`: Descrição mostrada para o LLM (obrigatório)
|
||||
|
||||
Exemplo:
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "tell-joke",
|
||||
"description": "Tell a joke on a given topic",
|
||||
"service": "joke-service",
|
||||
"style": "pun",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "topic",
|
||||
"type": "string",
|
||||
"description": "The topic for the joke (e.g., programming, animals, food)"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Carregando a Configuração
|
||||
|
||||
Use `tg-put-config-item` para carregar as configurações:
|
||||
|
||||
```bash
|
||||
# Load tool-service config
|
||||
tg-put-config-item tool-service/joke-service < joke-service.json
|
||||
|
||||
# Load tool config
|
||||
tg-put-config-item tool/tell-joke < tell-joke.json
|
||||
```
|
||||
|
||||
O agente-gerenciador deve ser reiniciado para aplicar novas configurações.
|
||||
|
||||
## Detalhes da Implementação
|
||||
|
||||
### Esquema
|
||||
|
||||
Tipos de requisição e resposta em `trustgraph-base/trustgraph/schema/services/tool_service.py`:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ToolServiceRequest:
|
||||
user: str = "" # User context for multi-tenancy
|
||||
config: str = "" # JSON-encoded config values from tool descriptor
|
||||
arguments: str = "" # JSON-encoded arguments from LLM
|
||||
|
||||
@dataclass
|
||||
class ToolServiceResponse:
|
||||
error: Error | None = None
|
||||
response: str = "" # String response (the observation)
|
||||
end_of_stream: bool = False
|
||||
```
|
||||
|
||||
### Servidor: DynamicToolService
|
||||
|
||||
Classe base em `trustgraph-base/trustgraph/base/dynamic_tool_service.py`:
|
||||
|
||||
```python
|
||||
class DynamicToolService(AsyncProcessor):
|
||||
"""Base class for implementing tool services."""
|
||||
|
||||
def __init__(self, **params):
|
||||
topic = params.get("topic", default_topic)
|
||||
# Constructs topics: non-persistent://tg/request/{topic}, non-persistent://tg/response/{topic}
|
||||
# Sets up Consumer and Producer
|
||||
|
||||
async def invoke(self, user, config, arguments):
|
||||
"""Override this method to implement the tool's logic."""
|
||||
raise NotImplementedError()
|
||||
```
|
||||
|
||||
### Cliente: ToolServiceImpl
|
||||
|
||||
Implementação em `trustgraph-flow/trustgraph/agent/react/tools.py`:
|
||||
|
||||
```python
|
||||
class ToolServiceImpl:
|
||||
def __init__(self, context, request_queue, response_queue, config_values, arguments, processor):
|
||||
# Uses the provided queue paths directly
|
||||
# Creates ToolServiceClient on first use
|
||||
|
||||
async def invoke(self, **arguments):
|
||||
client = await self._get_or_create_client()
|
||||
response = await client.call(user, config_values, arguments)
|
||||
return response if isinstance(response, str) else json.dumps(response)
|
||||
```
|
||||
|
||||
### Arquivos
|
||||
|
||||
| Arquivo | Propósito |
|
||||
|------|---------|
|
||||
| `trustgraph-base/trustgraph/schema/services/tool_service.py` | Esquemas de requisição/resposta |
|
||||
| `trustgraph-base/trustgraph/base/tool_service_client.py` | Cliente para invocar serviços |
|
||||
| `trustgraph-base/trustgraph/base/dynamic_tool_service.py` | Classe base para implementação de serviço |
|
||||
| `trustgraph-flow/trustgraph/agent/react/tools.py` | Classe `ToolServiceImpl` |
|
||||
| `trustgraph-flow/trustgraph/agent/react/service.py` | Carregamento de configuração |
|
||||
|
||||
### Exemplo: Serviço de Piadas
|
||||
|
||||
Um exemplo de serviço em `trustgraph-flow/trustgraph/tool_service/joke/`:
|
||||
|
||||
```python
|
||||
class Processor(DynamicToolService):
|
||||
async def invoke(self, user, config, arguments):
|
||||
style = config.get("style", "pun")
|
||||
topic = arguments.get("topic", "")
|
||||
joke = pick_joke(topic, style)
|
||||
return f"Hey {user}! Here's a {style} for you:\n\n{joke}"
|
||||
```
|
||||
|
||||
Configuração do serviço de ferramenta:
|
||||
```json
|
||||
{
|
||||
"id": "joke-service",
|
||||
"request-queue": "non-persistent://tg/request/joke",
|
||||
"response-queue": "non-persistent://tg/response/joke",
|
||||
"config-params": [{"name": "style", "required": false}]
|
||||
}
|
||||
```
|
||||
|
||||
Configuração da ferramenta:
|
||||
```json
|
||||
{
|
||||
"type": "tool-service",
|
||||
"name": "tell-joke",
|
||||
"description": "Tell a joke on a given topic",
|
||||
"service": "joke-service",
|
||||
"style": "pun",
|
||||
"arguments": [
|
||||
{"name": "topic", "type": "string", "description": "The topic for the joke"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Compatibilidade com versões anteriores
|
||||
|
||||
Os tipos de ferramentas integradas existentes continuam a funcionar sem alterações.
|
||||
`tool-service` é um novo tipo de ferramenta, juntamente com os tipos existentes (`knowledge-query`, `mcp-tool`, etc.).
|
||||
|
||||
## Considerações futuras
|
||||
|
||||
### Serviços de autoanúncio
|
||||
|
||||
Uma melhoria futura poderia permitir que os serviços publicassem seus próprios descritores:
|
||||
|
||||
Os serviços publicam em um tópico `tool-descriptors` conhecido na inicialização.
|
||||
O agente se inscreve e registra dinamicamente as ferramentas.
|
||||
Permite um verdadeiro sistema de plug-and-play sem alterações de configuração.
|
||||
|
||||
Isso está fora do escopo da implementação inicial.
|
||||
|
||||
## Referências
|
||||
|
||||
Implementação atual da ferramenta: `trustgraph-flow/trustgraph/agent/react/tools.py`
|
||||
Registro de ferramentas: `trustgraph-flow/trustgraph/agent/react/service.py:105-214`
|
||||
Esquemas do agente: `trustgraph-base/trustgraph/schema/services/agent.py`
|
||||
Loading…
Add table
Add a link
Reference in a new issue