Skip to main content

Prompt Manager — Cliente Python

prompt-manager-client é a biblioteca que as aplicações de IA importam para buscar seus prompts na API do Prompt Manager em tempo de execução. Os prompts se atualizam ao vivo: quando alguém commita e publica uma nova versão na UI, a aplicação passa a usá-la em segundos, sem redeploy.

Ela é deliberadamente pequena — três coisas públicas:

  • PromptManager — cliente síncrono (requests)
  • AsyncPromptManager — cliente assíncrono (httpx), mesma interface com await
  • Prompt — o prompt imutável e totalmente resolvido que uma busca retorna

Instalação

O pacote está publicado no PyPI como prompt-manager-client-dl:

uv add prompt-manager-client-dl
# ou: pip install prompt-manager-client-dl

O nome de import continua sendo prompt_manager. O código-fonte vive neste repositório, em client/ — para desenvolver contra ele, instale como dependência de path/git:

uv add "prompt-manager-client-dl @ git+ssh://git@bitbucket.org/avisourgente/prompt-manager.git#subdirectory=client"

Requer Python ≥ 3.10. Dependências: requests, httpx, cachetools.

Começo rápido

Crie um cliente por processo na inicialização (ele guarda o cache e a sessão HTTP) e reutilize-o:

from prompt_manager import PromptManager

pm = PromptManager(
    application="superchat",                 # o nome da sua aplicação no manager
    environment="prod",                      # qual deployment seguir
    fallback_dir="prompts_fallback",         # opcional: snapshots offline (veja abaixo)
)

# Uma chamada: busca (com cache) + preenche variáveis + relata o uso
text = pm.render(
    "resposta_juridica",
    variables={"pergunta": pergunta, "contexto": contexto},
    request_id=request_id,        # campos opcionais de observabilidade —
    user=user_email,              # eles vinculam o caso real ao prompt
    metadata={"tenant": tenant},  # na tela de "Registros" do manager
)

render() retorna a string final pronta para enviar ao modelo — e levanta PromptValidationError se o prompt define mensagens de chat. Para esses (ou para padronizar tudo em mensagens), use render_messages(), que aceita os mesmos argumentos e retorna uma lista [{"role", "content"}] no formato OpenAI:

messages = pm.render_messages(
    "resposta_juridica",
    variables={"pergunta": pergunta, "contexto": contexto},
)
# → [{"role": "system", "content": "..."}, {"role": "user", "content": "..."}]

# pronto para qualquer SDK no formato OpenAI (openai, litellm, ...):
resposta = client.chat.completions.create(model=..., messages=messages)

# LangChain aceita esses dicts diretamente:
resposta = chat_model.invoke(messages)

Um prompt sem marcadores de papel vira uma única mensagem system — então render_messages() pode ser o único caminho da sua aplicação, sem ramificar pelo formato do prompt.

Onde o cliente se conecta (base_url)

O endereço da API é resolvido nesta ordem:

  1. o argumento base_url do construtor, se informado;
  2. a variável de ambiente PROMPT_MANAGER_URL;
  3. o padrão de produção: http://promptmanager-prod.datalawyer.local.

Ou seja: em produção você não configura nada, e deployments de staging/dev redirecionam todos os clientes com uma única variável de ambiente:

export PROMPT_MANAGER_URL=http://localhost:8000   # ex.: stack de dev local

Async

from prompt_manager import AsyncPromptManager

pm = AsyncPromptManager(application="superchat", environment="prod")

async def handle(question: str) -> str:
    return await pm.render("resposta_juridica", variables={"pergunta": question})

Use-o como async context manager (async with AsyncPromptManager(...) as pm:) ou mantenha-o pela vida do processo; ao sair, ele descarrega os relatos de uso pendentes e fecha seu cliente httpx (a menos que você tenha passado o seu próprio).

Trabalhando com o objeto Prompt

get_prompt() retorna o prompt resolvido sem renderizá-lo:

prompt = pm.get_prompt("resposta_juridica")

prompt.template          # texto resolvido completo (fragmentos e exemplos já expandidos)
prompt.variables         # as variáveis de runtime que o template ainda espera
prompt.version           # número da versão commitada que esta resolução usou
prompt.hash              # hash do snapshot — registre-o para rastrear qualquer chamada de LLM até o prompt exato
prompt.suggested_model   # modelo + parâmetros sugeridos pelo autor do prompt
prompt.suggested_params
prompt.fragment_versions # quais versões de fragmentos foram embutidas
prompt.fewshots          # quais bancos de exemplos foram injetados, e quantos exemplos cada um contribuiu

prompt.messages          # o template já dividido em mensagens de chat pelo servidor
prompt.is_chat           # True se o template usa marcadores de papel

rendered = prompt.render(pergunta="...", contexto="...")            # prompts de texto
messages = prompt.render_messages(pergunta="...", contexto="...")   # qualquer prompt

render e render_messages (tanto no cliente quanto no Prompt) validam os valores: nomes de variáveis desconhecidos, variáveis obrigatórias faltando e {{placeholders}} restantes levantam PromptValidationError. Valores dict/list são codificados em JSON automaticamente.

Fragmentos

Fragmentos (blocos reutilizáveis: modelos de documento, seções de instrução, personas) são servidos pelo mesmo /fetch que os prompts — get_prompt() funciona para ambos e prompt.kind distingue ("prompt" ou "fragment"). Para o caso comum — a aplicação quer só o texto do fragmento, mantendo os {{placeholders}} para preencher depois — use get_fragment_text():

modelo = pm.get_fragment_text("modelo-contestacao")             # placeholders intactos
modelo = pm.get_fragment_text("modelo-contestacao", values={"esfera": "civel"})

Sub-fragmentos e bancos de exemplos chegam expandidos pelo servidor; ramos {% if %} são resolvidos localmente com os values informados (os defaults registrados preenchem os omitidos); marcadores de papel são descartados e o texto vem inteiro. Diferente de render(), nada é obrigatório — placeholders restantes são devolvidos como estão. Cache, revalidação por ETag e fallback offline funcionam exatamente como em get_prompt(); fragmentos compartilhados vivem na pseudo-aplicação shared (PromptManager(application="shared", ...)). Disponível também no AsyncPromptManager (await pm.get_fragment_text(...)).

Mensagens de chat

Um template pode conter linhas com marcadores de papel {% system %} / {% user %} / {% assistant %} — uma nova mensagem começa em cada marcador, e o conteúdo antes do primeiro pertence a system. O servidor já entrega o template dividido (prompt.messages), e render_messages() preenche as variáveis mantendo os papéis. render() recusa prompts de chat (PromptValidationError) em vez de devolver texto com marcadores embutidos; se você realmente quiser o texto plano, junte os conteúdos de render_messages() deliberadamente. Snapshots de fallback antigos (sem o campo messages) continuam funcionando: o cliente divide o template localmente com a mesma regra do servidor.

Ambientes

O environment informado na construção é o padrão; qualquer chamada pode sobrescrevê-lo:

pm.get_prompt("resposta_juridica", environment="staging")

"default" é especial: ele sempre segue a versão commitada mais recente, sem precisar de deployment explícito. Ambientes nomeados (prod, staging, …) servem a versão que foi fixada neles pela UI — e caem para a versão mais recente se o prompt nunca foi fixado ali.

Fluxo ({% if %} no template)

Não existe uma classe separada de variáveis de "controle": as booleanas e categóricas que decidem os ramos {% if %} são variáveis comuns, passadas em variables junto com as de texto. O servidor entrega o template com as tags {% if %} intactas e a biblioteca resolve os ramos localmente a cada render; a mesma variável também pode ser impressa como {{placeholder}} (booleanas viram true/false). Uma busca e uma entrada de cache cobrem todas as combinações.

messages = pm.render_messages(
    "chitchat",
    variables={
        "agente_customizado": True,        # booleana → decide o ramo
        "agent_description": descricao,    # variável de texto → preenche {{...}}
        "query": pergunta,
        ...
    },
)

Uma booleana/categórica omitida usa o valor padrão registrado no manager — a mesma regra do servidor, então o texto resultante é byte a byte o que o playground mostra para os mesmos valores. Variáveis cujo único uso está em um ramo desligado deixam de ser obrigatórias (continuam aceitas, apenas não são usadas). Snapshots de fallback gerados pelo prompt-manager pull preservam as tags, então o fallback offline também cobre todas as combinações.

Ablação de few-shots (A/B sem exemplos)

fewshots=False resolve o mesmo prompt com todos os bancos de exemplos desligados — é assim que uma aplicação mede o que os exemplos realmente valem:

com_exemplos = pm.render("classificador", variables=v)                    # normal
sem_exemplos = pm.render("classificador", variables=v, fewshots=False)   # ablação

As duas resoluções têm cache e ETag separados.

Cache, resiliência e fallback offline

O cliente é construído para que a API de prompts nunca seja um ponto único de falha:

  1. Cache com TTL (padrão 45 s, ttl= no construtor): buscas repetidas dentro da janela não custam nada.
  2. Revalidação por ETag: expirado o TTL, o cliente revalida com If-None-Match; um prompt inalterado custa um 304, não um novo download.
  3. Último valor conhecido: se a API estiver inacessível, o cliente registra um warning e continua servindo o último prompt buscado com sucesso (por chave nome/ambiente/fewshots), pela vida do processo.
  4. Arquivos de fallback locais: se a API estiver inacessível e nada foi buscado ainda (ex.: logo após um cold start), o cliente carrega <fallback_dir>/<nome>.<ambiente>.json, depois <fallback_dir>/<nome>.json e, em último caso, <fallback_dir>/<nome>.default.json — assim um bundle com apenas snapshots default continua útil em prod/staging.

Só quando os quatro falham ele levanta PromptUnavailableError. O resultado obsoleto/de fallback também entra no cache com TTL, então uma indisponibilidade custa no máximo um timeout por janela de TTL, não um por chamada.

Gere os snapshots de fallback com a CLI incluída (commite-os no seu repositório ou embuta-os na sua imagem, atualizando a cada deploy):

uv run prompt-manager pull --app superchat --env prod --out prompts_fallback/

(--url sobrescreve o endereço da API; caso contrário valem PROMPT_MANAGER_URL / o padrão de produção, igual à biblioteca.)

Relato de uso

Cada render()/render_messages() dispara (fire-and-forget) um relato para POST /api/v1/usage com a identidade do prompt (nome, versão, hash do snapshot) e os valores de variáveis com que foi preenchido. A UI do manager os lê de volta para que os prompts possam ser testados contra casos reais de produção em vez de casos inventados.

  • Nunca bloqueia nem quebra um render — falhas são logadas em nível debug e descartadas.
  • Passe request_id, user e metadata para tornar os casos gravados filtráveis.
  • Desabilite completamente com report_usage=False (ex.: em testes), ou no servidor deixando OPENSEARCH_HOST vazio.

Referência do construtor

Parâmetro Padrão Significado
application (obrigatório) Nome da aplicação registrada no manager
base_url $PROMPT_MANAGER_URL, senão http://promptmanager-prod.datalawyer.local Raiz da API do Prompt Manager
environment "default" Ambiente padrão de todas as chamadas
ttl 45 Segundos que um prompt buscado é servido sem revalidação
fallback_dir None Diretório com snapshots offline do prompt-manager pull
timeout 10 Timeout HTTP em segundos
session / client None Traga seu próprio requests.Session / httpx.AsyncClient
report_usage True Relata as variáveis de cada render para a tela de Registros

Release files for prompt-manager-client-dl 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for prompt-manager-client-dl 0.6.0
File Size Uploaded
prompt_manager_client_dl-0.6.0.tar.gz 27.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for prompt-manager-client-dl 0.6.0
File Interpreter ABI Platform
prompt_manager_client_dl-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 47.0 kB

Release files / prompt_manager_client_dl-0.6.0.tar.gz

Download URL prompt_manager_client_dl-0.6.0.tar.gz
Size 27.0 kB
Tags Source
SHA-256 checksum
How to use checksums
defd259b22dfe1b0b0300b3d878bc94dcb96fa6d5207072fc0f6405562845233
BLAKE2b-256 checksum
How to use checksums
dc0421b9e7f301f8e6c421bbb21de9db75e0552247adc878f9c74ec46de07869
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / prompt_manager_client_dl-0.6.0-py3-none-any.whl

Download URL prompt_manager_client_dl-0.6.0-py3-none-any.whl
Size 19.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d66f43e8bc22a423b550645e8f49fb90c1cb481800442ab8e178d5175528c1ca
BLAKE2b-256 checksum
How to use checksums
b6a366a3fd66d73201620a2bb0c1efcce264f7e0bfde4a076e95aab5cfba2ea4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.8.0

2 release files

0.7.0

2 release files

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page