O prompt que você não escreveu
No capítulo do agente sem framework, o system prompt era seu. Você escreveu à mão o texto que explicava o ciclo, listava as Tools e mandava o modelo parar em Final Answer:. Estava tudo num arquivo que você abria e editava.
Depois veio o CodeAgent, e esse texto sumiu do seu código. Ele não sumiu do programa — só saiu das suas mãos.
Este capítulo mostra onde ele foi parar, como olhar para ele, e o que acontece quando alguém entrega um arquivo prompts.yaml e diz que é assim que se configura o agente.
Onde o prompt foi parar
Acrescente uma linha ao alfred_smolagents.py, logo depois de criar o agente:
print(agente.system_prompt)
Saem 9.036 caracteres que você não digitou. O smolagents monta esse texto a partir de um template que vem instalado junto com a biblioteca:
.venv\Lib\site-packages\smolagents\prompts\code_agent.yaml
É um arquivo YAML comum. Abra, se quiser — é o mesmo tipo de texto que você escreveu no capítulo do agente do zero, só que mais longo e mais cuidadoso.
O template é um arquivo do pacote, não do seu projeto. Se você atualizar o smolagents, ele muda. Essa é a diferença que importa: no agente do zero, o prompt era seu e ficava parado; aqui, ele é da biblioteca e acompanha a versão dela.
A parte que você já conhece
Procure o nome de uma das suas Tools no meio dos 9.036 caracteres:
you only have access to these tools, behaving like regular python functions:
<code>
def consultar_assunto(termo: string) -> integer:
"""Converte o nome de um assunto judicial no código numérico correspondente.
Args:
termo: nome (ou parte do nome) do assunto, por exemplo "violência doméstica".
"""
Reconheça o que está aí: é a sua docstring. Palavra por palavra.
O capítulo das Tools disse que a docstring é o contrato. Aqui está a prova material: o @tool leu a assinatura e a docstring, e o smolagents as colou dentro do prompt como se fossem uma declaração de função. O modelo nunca vê o corpo da sua Tool. Ele vê essas seis linhas.
Repare também nos tipos: termo: string, -> integer. Não são os tipos do Python (str, int) — são os tipos do esquema JSON que o smolagents usa por dentro. É o mesmo vocabulário que você vai reencontrar na Unidade 3, quando a Tool atravessar a fronteira do MCP.
O prompts.yaml que vem no material do HF
Quem faz o curso original da Hugging Face recebe, no espaço de exemplo, um arquivo prompts.yaml de 317 linhas e um app.py que o carrega assim:
import yaml
with open("prompts.yaml", "r") as stream:
prompt_templates = yaml.safe_load(stream)
agente = CodeAgent(
tools=[final_answer, buscar_processos_cnj],
model=modelo,
max_steps=6,
prompt_templates=prompt_templates, # <-- aqui
)
A pergunta natural, e é uma boa pergunta: isso ainda funciona? E eu preciso disso?
Duas respostas diferentes, e é importante não confundir uma com a outra.
Funciona? Funciona.
O parâmetro prompt_templates= existe, está vivo, e o arquivo é lido. Dá para medir sem sair do lugar: monte o mesmo agente duas vezes, uma com o YAML e outra sem, e compare o tamanho do prompt resultante.
import yaml
from smolagents import CodeAgent
sem = CodeAgent(tools=[consultar_assunto], model=modelo)
com = CodeAgent(tools=[consultar_assunto], model=modelo,
prompt_templates=yaml.safe_load(open("prompts.yaml", encoding="utf-8")))
print(len(sem.system_prompt)) # 9036
print(len(com.system_prompt)) # 8788
Números diferentes, mesmo agente. O arquivo entrou.
Preciso? Não precisa.
O prompt_templates= é opcional. Sem ele, o smolagents usa o template que vem instalado — o mesmo que você acabou de imprimir. O agente da Unidade 1, o da Unidade 2 e o da Unidade 3 rodam todos sem prompts.yaml, e é por isso que você nunca viu esse arquivo nos exemplos do curso.
Um prompts.yaml no seu projeto quer dizer uma coisa só: você decidiu substituir o texto da biblioteca pelo seu. É uma decisão legítima. Só não é gratuita, e a próxima seção mostra o preço.
O preço: o template congela, a biblioteca não
O prompts.yaml do material do HF foi escrito para uma versão anterior do smolagents. Passar ele para a versão 1.26 não dá erro. Não dá aviso. O agente sobe e responde.
O que muda é o texto que o modelo lê. Três diferenças medidas, todas silenciosas.
1. A tag de código está errada — e o agente sobrevive por acaso
A versão 1.26 delimita código com <code> e </code>:
print(agente.code_block_tags) # ('<code>', '</code>')
O prompts.yaml do HF ensina outra coisa. Ele manda o modelo fechar o bloco com <end_code>, e insiste: a expressão aparece 14 vezes no prompt montado.
| prompt padrão da 1.26 | prompt do prompts.yaml |
|
|---|---|---|
ocorrências de </code> |
15 | 0 |
ocorrências de <end_code> |
0 | 14 |
Ou seja: o modelo é instruído 14 vezes a escrever uma marca que o interpretador não procura, e zero vezes a escrever a que ele procura.
Deveria quebrar sempre. Não quebra — porque o smolagents tem uma segunda tentativa:
# smolagents/utils.py, dentro de parse_code_blobs {: #smolagentsutilspy-dentro-de-parse-code-blobs }
matches = extract_code_from_text(text, code_block_tags)
if not matches: # Fallback to markdown pattern
matches = extract_code_from_text(text, ("```(?:python|py)", "\n```"))
Falhou com as tags, tenta o bloco markdown ```python. Como os modelos escrevem markdown por hábito, o código costuma ser encontrado por essa segunda via. E há ainda uma terceira: se nada casar, ele tenta ast.parse no texto inteiro.
Repare no formato desta falha, porque ele se repete no curso inteiro: o template está errado, o resultado está certo, e nada no meio do caminho avisa. O agente funciona apoiado num plano B que existe para outra finalidade.
Quando o modelo escrever o bloco sem marcação markdown — e ele às vezes escreve — as três tentativas falham de uma vez e o erro que aparece é este:
Error in code parsing:
Your code snippet is invalid, because the regex pattern <code>(.*?)</code> was
not found in it.
A mensagem cita <code>, que é o que a biblioteca queria. Ela não cita <end_code>, que é o que o seu YAML mandou o modelo escrever. Quem for depurar isso vai procurar o defeito no lugar errado.
2. As Tools aparecem como prosa, não como assinatura
Com o template padrão, a sua Tool chega ao modelo como código:
def consultar_assunto(termo: string) -> integer:
"""Converte o nome de um assunto judicial no código numérico correspondente.
Args:
termo: nome (ou parte do nome) do assunto, por exemplo "violência doméstica".
"""
Com o prompts.yaml do HF, a mesma Tool chega como lista:
- consultar_assunto: Converte o nome de um assunto judicial no código numérico correspondente.
Takes inputs: {'termo': {'type': 'string', 'description': 'nome (ou parte do nome) do assunto, por exemplo "violência doméstica".'}}
Returns an output of type: integer
A informação é a mesma. A forma não. Você está pedindo a um modelo que escreve Python que deduza a chamada a partir de uma descrição em inglês, em vez de mostrar a ele a assinatura que ele deve chamar. O template mais novo mostra código para quem vai escrever código — e essa mudança foi deliberada.
3. Três chaves que ninguém lê
As chaves de topo dos dois arquivos são idênticas: system_prompt, planning, managed_agent, final_answer. Um diff superficial diria que está tudo certo.
A diferença está um nível abaixo, dentro de planning:
subchave de planning |
no prompts.yaml do HF |
usada pela 1.26 |
|---|---|---|
initial_plan |
sim | sim |
update_plan_pre_messages |
sim | sim |
update_plan_post_messages |
sim | sim |
initial_facts |
sim | não |
update_facts_pre_messages |
sim | não |
update_facts_post_messages |
sim | não |
Três blocos de texto que você pode editar com todo o cuidado do mundo sem que nada aconteça. Não há erro, não há aviso — a chave simplesmente não é procurada por ninguém.
Isto é o oposto do problema anterior e vale guardar como par. Na tag <end_code>, você escreve uma instrução e ela chega ao modelo estando errada. Aqui, você escreve uma instrução e ela não chega ao modelo. Nos dois casos, o agente responde normalmente.
Editar um template sem imprimir o resultado é escrever no escuro.
Como olhar, quando for preciso olhar
A ferramenta é uma linha. Guarde-a:
print(agente.system_prompt)
Antes de acusar o modelo de não seguir uma instrução, confira se a instrução chegou até ele. Três verificações que cabem em segundos:
p = agente.system_prompt
print(len(p)) # o prompt tem o tamanho que você espera?
print(agente.code_block_tags) # a tag que o template ensina é a que a lib procura?
print("consultar_assunto" in p) # a sua Tool foi realmente anunciada?
E, para saber se um YAML de terceiro está mesmo sendo lido, compare os dois tamanhos como na seção anterior. Se derem o mesmo número, o arquivo não entrou.
O que fazer com o prompts.yaml
Para este curso: não use. Os exemplos das três unidades passam tools=, model= e max_steps=, e param aí. O template da biblioteca acompanha a versão dela, e é a versão dela que define como o código vai ser lido.
Personalize o prompt quando houver um motivo que você saiba dizer em voz alta — por exemplo, exigir que o agente responda em português, ou proibi-lo de citar número de processo que não tenha vindo de uma Tool. Quando esse dia chegar:
- Comece do arquivo instalado,
smolagents/prompts/code_agent.yaml, não de um YAML antigo de outra pessoa. Copie e edite. - Anote a versão do
smolagentspara a qual você copiou, num comentário no topo do arquivo. - Imprima o prompt depois de carregar, e confira as tags de código.
- Repita o passo 3 a cada atualização da biblioteca. Nada vai avisar você.
Boa parte do que se pede a um agente não precisa de template nenhum. A instrução do agente.run(...) chega ao modelo do mesmo jeito, vale só para aquela pergunta, e não congela com a versão da biblioteca.
Foi assim que o curso resolveu o problema do português e o da forma dos dados na Unidade 3: uma frase a mais na pergunta, e nenhum arquivo de configuração a manter.
Template é para o que vale sempre. Pergunta é para o resto — e o resto é a maioria.
Exercícios
- Imprima o prompt do seu
alfred_smolagents.pye localize as duas Tools. Confira que o texto que o modelo lê é a sua docstring, sem uma vírgula de diferença. - Mude uma docstring — troque
"parte do nome do assunto"por"o nome EXATO do assunto"— e imprima de novo. Meça em quantos lugares do prompt a mudança apareceu. - Apague o bloco
Args:de uma das docstrings e rode o arquivo. Você não chega nem a criar o agente:
DocstringParsingException: Cannot generate JSON schema for consultar_assunto
because the docstring has no description for the argument 'termo'
O erro estoura no @tool, na hora de importar o módulo — antes do modelo, antes da pergunta. Explique por que essa é a melhor hora possível para essa falha acontecer, e compare com o que aconteceria se ela só aparecesse no meio de uma execução.
- Carregue o
prompts.yamldo material do HF no seu agente e rode a mesma pergunta três vezes. Conte quantas execuções passaram pelo plano B do markdown e quantas quebraram noparse_code_blobs.
Fixando o capítulo
Q1: Passar prompt_templates= com um YAML escrito para uma versão antiga do smolagents produz o quê, na versão 1.26?
Q2: Você quer que o agente responda sempre em português. Onde essa instrução deve ir?
O prompt já não é seu, mas continua legível — e uma linha basta para lê-lo. Guarde essa linha: na Unidade 3, quando a Tool vier de outro processo e você não tiver mais o @tool na mão, ela vai ser o único jeito de saber o que o modelo está realmente vendo.