Perdi minha chave da Zhipu na migração da VM?

Diagnóstico de um problema que parecia 'chave perdida' mas era provedor nativo do Kilo usando JWT obsoleto. Como fazer o Kilo enxergar créditos avulsos da Z.ai.

O problema

A frase chegou meio desesperada: “veja os meus arquivos do Kilo, acho que minha chave da Zhipu se perdeu na migração da VM”. A suspeita fazia todo sentido. Eu tinha acabado de mudar minhas configurações de um computador físico para uma VM (uma Máquina Virtual, que é basicamente um “computador de mentira” rodando dentro de outro computador).

No meio desse caminho, o Kilo Code — uma extensão que uso no meu editor de código (o VS Code) para conversar com inteligências artificiais da Z.ai/Zhipu — simplesmente parou de funcionar. Ele não reconhecia mais o serviço. Os modelos de IA nem apareciam na lista e, quando eu tentava forçar o uso, o sistema devolvia um erro de autorização.

Quando mudamos de ambiente em TI, é muito comum “perder” as chaves de API (que funcionam como senhas digitais para que um programa possa usar o serviço de outro). Meu primeiro instinto foi procurar essa chave: fui checar se o arquivo .env (onde guardamos variáveis e senhas) tinha sido copiado e se o arquivo ~/.config/api-keys.env estava no lugar. Foi aí que veio a primeira surpresa: a chave não estava perdida. Todas as senhas estavam intactas. O problema era outro.

Verificando o que estava (e não estava) perdido

Em TI, o primeiro passo é testar antes de tirar conclusões. As chaves ficavam guardadas num arquivo chamado ~/.config/api-keys.env, neste formato:

export ZHIPUAI_API_KEY="sua_chave_aqui"
export ZHIPU_CODING_PLAN_API_KEY="sua_chave_aqui"
export DEEPSEEK_API_KEY="sua_chave_aqui"
export OPENROUTER_API_KEY="sua_chave_aqui"

(Esses textos "sua_chave_aqui" são apenas exemplos. No arquivo de verdade ficam as senhas secretas, que nunca devemos mostrar publicamente!)

O arquivo .bashrc (um script que o sistema roda assim que abrimos o terminal) carregava essas senhas automaticamente. Usei o comando env | grep -i zhipu (que serve para filtrar e listar as variáveis de ambiente ativas) e vi que as chaves estavam lá, prontas para uso. Então, não era perda de chave. O Kilo só não estava lendo essas informações do jeito certo ou estava procurando no lugar errado.

O verdadeiro problema: provedor nativo obsoleto

Demorei um pouco para entender essa parte. O Kilo tem duas formas de conversar com o servidor da Zhipu: usando um provedor nativo (uma conexão “de fábrica” embutida nele) ou usando um caminho genérico no padrão OpenAI-compatible (que aponta para um endereço de web específico, chamado de endpoint).

O provedor nativo do Kilo para a Zhipu usava um método antigo de identificação baseado em tokens JWT (pense nisso como um crachá temporário com hora para expirar). Esse era o padrão da Zhipu anos atrás. O sistema pegava a chave e criava esse crachá para mandar na mensagem.

Só que a Zhipu mudou as regras! Hoje, a API deles exige o formato padrão de mercado: Authorization: Bearer <api_key> (que é como apresentar a chave/senha diretamente no cabeçalho da mensagem). O provedor nativo do Kilo nunca foi atualizado para acompanhar essa mudança.

Resultado: toda vez que o Kilo tentava usar a conexão nativa, o servidor da Zhipu respondia com a mensagem "Header中未收到Authorization参数" (que significa “parâmetro de autorização não recebido no cabeçalho”). O erro aparece em chinês porque o servidor da Zhipu fica na China, e ele estava apenas avisando que aquele crachá (JWT) antigo não era mais aceito.

Aí veio a virada do diagnóstico: A chave nunca esteve perdida. O programa que tentava ler a chave é que estava desatualizado (obsoleto).

A solução: usar o caminho OpenAI-compatible

A solução (que a IA Claude já tinha configurado no PC antigo e que recriei na VM) foi parar de usar o provedor nativo. Em vez disso, cadastramos cada serviço como uma entrada genérica compatível com o padrão OpenAI no arquivo de configuração ~/.config/kilo/kilo.jsonc:

{
  "providers": {
    "zhipuai": {
      "baseUrl": "https://open.bigmodel.cn/api/paas/v4",
      "apiKey": "${ZHIPUAI_API_KEY}",
      "models": ["glm-4-plus", "glm-4.7", "glm-4v"]
    },
    "zhipu-coding-plan": {
      "baseUrl": "https://open.bigmodel.cn/api/paas/v4",
      "apiKey": "${ZHIPU_CODING_PLAN_API_KEY}",
      "models": ["glm-coding-plan"]
    },
    "deepseek": {
      "baseUrl": "https://api.deepseek.com",
      "apiKey": "${DEEPSEEK_API_KEY}",
      "models": ["deepseek-chat", "deepseek-reasoner"]
    },
    "openrouter": {
      "baseUrl": "https://openrouter.ai/api/v1",
      "apiKey": "${OPENROUTER_API_KEY}",
      "models": ["anthropic/claude-3.5-sonnet"]
    }
  }
}

O “pulo do gato” aqui é a linha baseUrl (o endereço web para onde o programa manda as solicitações). Cada provedor ganha seu endereço correto no formato OpenAI (que internamente busca por /v1/chat/completions), e a senha é chamada usando ${VARIAVEL} em vez de ser escrita diretamente no texto.

Isso resolve dois problemas: o Kilo nunca expõe a senha real (ele só lê a variável de ambiente) e a chave fica salva em um arquivo .env seguro, sem o risco de ir parar acidentalmente num repositório público do Git.

A cilada do crédito avulso vs coding plan

O detalhe que transformou essa tarefa num quebra-cabeça foi entender que a Zhipu trabalha com dois tipos de créditos diferentes:

  • Créditos avulsos (você paga conforme usa, associados à ZHIPUAI_API_KEY)
  • O Coding Plan (uma assinatura mensal fixa, associada à ZHIPU_CODING_PLAN_API_KEY)

A Zhipu separa essas duas coisas rigidamente. O plano de assinatura (Coding Plan) só funciona se você usar um modelo específico (glm-coding-plan). Se eu tentar usar a chave da assinatura para chamar o modelo avulso glm-4-plus, dá erro. Se tentar usar a chave avulsa no modelo glm-coding-plan, também dá erro!

São dois mundos separados. Por isso, o Kilo precisa de duas configurações de provedor separadas para conseguir enxergar os dois tipos de conta.

Na configuração original, o Claude tinha criado esses dois provedores. Na migração para a VM, eu tinha recriado apenas um deles. Foi por isso que pareceu que “tudo tinha parado de funcionar” — na verdade, metade da configuração tinha ficado para trás.

A migração que não quebrou (de novo)

Depois de arrumar o arquivo kilo.jsonc com os provedores corretos e testar com o comando kilo config check (que confirmou que não havia mais avisos de erro, retornando No config warnings), veio a dúvida: vale a pena refazer a migração do zero?

A resposta foi não. A migração da VM não tinha quebrado o sistema. O problema foi a falta de um runbook (um passo a passo documentado) antes de mover as coisas.

O checklist que guardei para as próximas migrações:

  1. Confirmar se as variáveis de ambiente foram carregadas (env | grep -i key).
  2. Garantir que o kilo.jsonc usa ${VARIAVEL} e não o valor da senha direto no texto.
  3. Rodar kilo config check — se der aviso (warning), o problema é na configuração do JSON, não na chave.
  4. Testar a conexão direta com cada serviço usando um comando curl (um comando de terminal que faz uma requisição de teste para a web):
curl https://open.bigmodel.cn/api/paas/v4/chat/completions \
  -H "Authorization: Bearer $ZHIPUAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"glm-4-plus","messages":[{"role":"user","content":"ping"}]}'

Se o teste retornar o código 200 acompanhado de um texto JSON, a chave e o endereço estão perfeitos. Se retornar erro de Authorization, a chave está errada. Se retornar aquele erro em chinês citando “Header中”, significa que o programa está tentando enviar o formato antigo (JWT) em vez do formato atual (Bearer) — e o culpado é o provedor nativo desatualizado.

O que aprendi

A primeira lição é sobre investigação: “chave perdida” quase sempre é “configuração que foi copiada incompleta”. Antes de achar que a senha sumiu, verifique se a variável está ativa no sistema e se o programa está apontando para o endereço de internet certo. Na grande maioria das vezes, o que sumiu foi apenas uma linha de configuração.

A segunda é sobre software: conexões “nativas” de ferramentas de terceiros podem ficar obsoletas. O Kilo tinha um conector próprio para a Zhipu que funcionava no passado, mas parou de funcionar porque a API da Zhipu evoluiu. A melhor estratégia é sempre usar conectores genéricos (compatíveis com o padrão OpenAI usando a baseUrl), pois o mercado sempre mantém esse padrão funcionando.

A terceira lição: diferentes tipos de planos no mesmo serviço exigem configurações separadas. A Zhipu não junta a assinatura mensal com os créditos avulsos. Para usar ambos, é preciso entender qual chave liga para qual modelo e deixar isso muito bem documentado. O preço de não anotar é perder uma tarde inteira achando que perdeu a senha, quando na verdade só faltava uma linha no seu arquivo JSON.

Leia também

Comentários

Carregando comentários…

Deixe um comentário