Pular para conteúdo

Resolver procedimento por nome

Transforma o nome do exame/consulta em linguagem natural em um (id_procedimento, id_especialidade, id_agenda).

Complexidade crescente

Dependendo da clínica, a dificuldade muda:

  • MEDCENTER: 1 procedimento por médico (consulta da especialidade dele). Basta resolver médico → procedimento cai junto.
  • CLINFETO: ~100+ procedimentos, múltiplos médicos podem fazer o mesmo.

Caso simples — Medcenter

# scheduling.py (MEDCENTER)
PROCEDIMENTOS = [
    {"id_especialidade": 450, "id_agenda": 3, "id_procedimento": 64639,
     "procedimento": "CONSULTA ORTOPEDISTA MAURICIO",
     "medico": "MAURICIO SIQUEIRA CAMILO"},
    # ... 7 médicos
]

# Resolve tudo pelo médico
def buscar_procedimento_por_medico(nome_medico: str) -> dict | None:
    # ... ver resolver-medico.md

O nome do procedimento é praticamente ignorado — o que importa é o médico.

Caso complexo — Clinfeto

Estrutura de dados

# agendamento.py:73-202 (CLINFETO)
PROCEDIMENTOS_JOANA = {
    167: (58, 129, "US ABDOME INFERIOR MASCULINO"),
    168: (58, 129, "US ABDOME SUPERIOR"),
    170: (58, 129, "US ABDOME TOTAL"),
    # ... ~100 procedimentos
}

PROCEDIMENTOS_RENNAN = { ... }
PROCEDIMENTOS_OB = { ... }    # obstetrícia compartilhada entre 3 médicas

PROCEDIMENTOS_POR_AGENDA = {
    58: PROCEDIMENTOS_JOANA,
    57: PROCEDIMENTOS_SUELEM,
    55: PROCEDIMENTOS_RAFAELLA,
    54: PROCEDIMENTOS_PRISCILA,
    59: PROCEDIMENTOS_RENNAN,
}

Cada entrada é id_procedimento → (id_agenda, id_especialidade, nome_canônico).

Busca por nome + agenda

def buscar_procedimento(nome_procedimento: str, agenda_id: int) -> dict | None:
    procs = PROCEDIMENTOS_POR_AGENDA.get(agenda_id, {})
    norm = _normalize(apply_aliases(_normalize(nome_procedimento)))

    # Exato
    for pid, (aid, eid, nome) in procs.items():
        if _normalize(nome) == norm:
            return {"id_agenda": aid, "id_especialidade": eid, "id_procedimento": pid}

    # Parcial
    for pid, (aid, eid, nome) in procs.items():
        nn = _normalize(nome)
        if norm in nn or nn in norm:
            return {"id_agenda": aid, "id_especialidade": eid, "id_procedimento": pid}

    return None

Aliases — acomodar variações do LLM

O LLM produz variações ("ULTRASSOM ABDOMINAL", "US ABDOME TOTAL", "ultrassonografia de abdômen"). Use um dicionário explícito:

# agendamento.py:205-292 (CLINFETO, trecho)
ALIASES = {
    "OBSTETRICA INICIAL ENDOVAGINAL":      "US OBSTETRICA (ENDOVAGINAL)",
    "OBSTETRICA ENDOVAGINAL":              "US OBSTETRICA (ENDOVAGINAL)",
    "MORFOLOGICA 1 TRIMESTRE":             "US OBSTETRICA MORFOLOGICA 1 TRIMESTRE",
    "TRANSVAGINAL":                        "US TRANSVAGINAL (UTERO OVARIO ANEXOS E VAGINA)",
    "MAMA":                                "US MAMA / AXILA",
    "ABDOME TOTAL":                        "US ABDOME TOTAL",
    # ... ~100 aliases
}

def apply_aliases(nome_normalizado: str) -> str:
    return ALIASES.get(nome_normalizado, nome_normalizado)

Origem dos aliases

Cada alias veio de um caso real onde o LLM errou. Não é preventivo, é corretivo. Quando adicionar um novo alias, documentar o motivo em comentário se for obscuro.

"Sem preferência de médico" — agregação

Se o paciente não escolheu médico, precisamos saber quais médicos fazem o procedimento. Solução:

def buscar_procedimentos_todos_medicos(nome_procedimento: str) -> list[dict]:
    """Retorna lista de {id_agenda, id_especialidade, id_procedimento} para
    TODOS os médicos que fazem esse procedimento."""
    norm = _normalize(apply_aliases(_normalize(nome_procedimento)))
    result = []
    for agenda_id, procs in PROCEDIMENTOS_POR_AGENDA.items():
        for pid, (aid, eid, nome) in procs.items():
            if _normalize(nome) == norm or norm in _normalize(nome):
                result.append({
                    "id_agenda": aid,
                    "id_especialidade": eid,
                    "id_procedimento": pid,
                })
                break   # um resultado por agenda
    return result

O que o agente precisa saber

Ambos os projetos colocam a lista de procedimentos disponíveis no system prompt (ou em menus numerados). O LLM escolhe o nome da lista, o que reduz o espaço de variação.

Nunca deixar o LLM inventar nomes

Se o paciente pede "USG do pé" e a clínica não faz, o agente precisa retornar FALHA_CONSULTA (ou transferir), nunca tentar mapear para algo parecido.

Guardião anti-inversão

LLMs às vezes invertem os argumentos (nome_convenio recebe o procedimento, nome_procedimento recebe o convênio). Ver Guardian validator.