Skip to main content
Glama
caioribeiro25

agro-market-agent

README.md
# agro-market-agent

[![CI](https://github.com/caioribeiro25/agro-market-agent/actions/workflows/ci.yml/badge.svg)](https://github.com/caioribeiro25/agro-market-agent/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
[![Ruff](https://img.shields.io/badge/lint-ruff-orange)](https://github.com/astral-sh/ruff)
[![mypy](https://img.shields.io/badge/types-mypy%20strict-informational)](https://mypy-lang.org/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)

Agente de IA multi-step que responde perguntas de inteligência de mercado
agropecuário — *"qual minha margem na soja hoje, com custo de R$95/saca?"* —
decidindo sozinho quais ferramentas chamar, em que ordem, e finalizando com um
relatório. As ferramentas são expostas por um **MCP server** próprio (Model
Context Protocol), reutilizável em qualquer cliente MCP.

Não é um wrapper de chatbot: é um agente instrumentado, testado e avaliado,
construído com as preocupações de um sistema de produção.

## O que este projeto demonstra

| Área | Como |
|------|------|
| **Agente sobre a API oficial** | Loop de tool-use com o SDK da Anthropic — sem framework de orquestração, para deixar explícito o mecanismo. |
| **MCP server próprio** | 5 tools tipadas (`src/agro_market/server.py`), reutilizáveis em qualquer cliente MCP (ex: Claude Desktop). |
| **Avaliação rigorosa** | `tests/eval.py`: precision/recall de seleção de tools + **LLM-as-judge** + **detecção de regressão** contra baseline. |
| **Observabilidade** | Tracing estruturado (spans JSON no stderr), contabilidade de tokens e **custo por execução**, `RunTrace` persistida em disco. |
| **Type safety** | Modelos Pydantic v2 em todas as fronteiras; **mypy strict** e **ruff** no CI. |
| **Robustez** | Guardrails de entrada, timeout global, limite de iterações; cliente HTTP com **retry exponencial + cache TTL**. |
| **Testes sem custo** | Anthropic e HTTP mockados (`respx`) — a suíte roda no CI **sem API key e sem rede**. |
| **Fonte de dados plugável** | Padrão adapter: `mock` (offline, default) ou `yahoo` (HTTP real), trocável por config. |
| **Engenharia de projeto** | `pyproject.toml`, layout `src/`, CI (GitHub Actions), pre-commit, Dockerfile, Makefile. |

## Arquitetura

```
  Usuário
    │  pergunta em linguagem natural
    ▼
  Agente (Claude + tool runner)  ── src/agro_market/agent.py
    │  guardrails · tracing · timeout · limite de iterações
    │  descobre e chama tools via MCP (stdio)
    ▼
  MCP Server  ── src/agro_market/server.py
    ├── list_commodities
    ├── get_commodity_price   → data_sources.py  (mock | yahoo, com retry+cache)
    ├── calculate_margin      → calculations.py   (lógica pura)
    ├── get_historical_trend  → db.py             (SQLite)
    └── generate_report       → markdown
```

## Estrutura

```
src/agro_market/
├── agent.py          loop de orquestração (Claude + MCP)
├── server.py         MCP server (5 tools)
├── data_sources.py   adapter de preço: mock | Yahoo (httpx + tenacity + cache)
├── calculations.py   lógica de negócio pura
├── db.py             SQLite + histórico auto-semeado
├── domain.py         modelos Pydantic (contratos entre camadas)
├── observability.py  tracer, spans, custo, RunTrace
├── guardrails.py     validação de entrada
└── config.py         settings tipadas (pydantic-settings)
tests/
├── test_*.py         unit + integração (mockados, rodam no CI)
└── eval.py           avaliação end-to-end (LLM-as-judge, usa a API)
```

## Quickstart

```bash
python -m venv .venv
.venv\Scripts\activate            # Windows (Linux/macOS: source .venv/bin/activate)
pip install -e ".[dev]"
copy .env.example .env             # e preencha ANTHROPIC_API_KEY
```

Rodar o agente:

```bash
python -m agro_market.agent "Qual minha margem na soja com custo de R$95/saca em 1000 sacas? Gere um relatório."
```

O agente busca o preço → calcula a margem → consulta a tendência → gera o
relatório, e ao final reporta tools chamadas, tokens, custo e latência.

## Qualidade (o que roda no CI, sem API key)

```bash
make check      # ruff + mypy strict + pytest (com cobertura)
# ou individualmente:
ruff check .
mypy
pytest          # 20 testes, ~86% de cobertura, sem rede
```

## Avaliação (metodologia)

`tests/eval.py` roda cenários fixos e mede, por caso:

- **Seleção de tools** — precision/recall contra o conjunto esperado.
- **Qualidade da resposta** — LLM-as-judge dá nota 0..1 com justificativa
  (via structured output).
- **Custo e latência** por execução.

Agrega as métricas e **compara com um baseline** (`eval_baseline.json`): se a
nota média cair além do limiar, sinaliza regressão e falha. É o que separa
"funcionou uma vez" de "não regrediu".

```bash
python tests/eval.py    # exige ANTHROPIC_API_KEY
```

## Observabilidade

Cada execução emite spans estruturados (JSON no stderr, prontos para um
coletor de logs) e persiste uma `RunTrace` completa em `traces/` — pergunta,
spans com duração, tools chamadas, tokens e custo estimado. Debugar uma run
que deu errado é ler um JSON, não vasculhar prints.

## Fontes de dados

- `AGRO_PRICE_SOURCE=mock` (default) — determinística, offline.
- `AGRO_PRICE_SOURCE=yahoo` — futuros via Yahoo Finance, com timeout, retry
  exponencial e cache TTL. Ponto de extensão para CEPEA/ESALQ isolado no adapter.

## Configuração

Todas via ambiente (prefixo `AGRO_`) — ver `.env.example`. Principais:
`AGRO_MODEL`, `AGRO_PRICE_SOURCE`, `AGRO_MAX_TOOL_ITERATIONS`, `AGRO_AGENT_TIMEOUT_S`.

## MCP server em outro cliente

```bash
python -m agro_market.server        # processo stdio
```

Aponte a config MCP do cliente (ex: Claude Desktop) para esse comando.

## Roadmap

- [ ] Integração CEPEA/ESALQ real no adapter
- [ ] Export de traces em formato OpenTelemetry
- [ ] GIF de demonstração no README

## Stack

Python · Anthropic API (tool use) · Model Context Protocol · Pydantic v2 ·
httpx · tenacity · SQLite · pytest · ruff · mypy · GitHub Actions

TDQS

A4/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: listing commodities, getting price, calculating margin, historical trend, and report generation. No overlap or ambiguity.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (e.g., list_commodities, get_commodity_price), making them predictable and easy to understand.

Tool Count5/5

With 5 tools, the server covers the entire agricultural market analysis workflow without being too sparse or overwhelming. Each tool earns its place.

Completeness5/5

The tool set provides a complete lifecycle: discovering commodities, fetching prices, calculating margins, viewing historical trends, and generating reports. No obvious gaps for the intended purpose.

Maintenance

ActivitySlowing
ResponsivenessNo issues