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:
- Confirmar se as variáveis de ambiente foram carregadas (
env | grep -i key). - Garantir que o
kilo.jsoncusa${VARIAVEL}e não o valor da senha direto no texto. - Rodar
kilo config check— se der aviso (warning), o problema é na configuração do JSON, não na chave. - 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.
Comentários
Carregando comentários…