<НА ГЛАВНУЮ

Безопасный Cipher-воркфлоу с памятью и автоматическим выбором LLM

'Шаг за шагом: как построить безопасный Cipher-воркфлоу с автоматическим выбором LLM и долгосрочной памятью, включая примеры Python для управления ключами и развертывания API.'

Безопасный ввод API-ключей

В Colab используйте getpass, чтобы Gemini API key не сохранялся в явном виде и не отображался в выводе блокнота. Пример устанавливает GEMINI_API_KEY в окружение.

import os, getpass
os.environ["GEMINI_API_KEY"] = getpass.getpass("Enter your Gemini API key: ").strip()

Динамический выбор LLM

Функция choose_llm() автоматически выбирает OpenAI, Gemini или Anthropic в зависимости от доступных переменных окружения. Это позволяет одному и тому же коду работать в разных средах без изменений.

import subprocess, tempfile, pathlib, textwrap, time, requests, shlex
 
 
def choose_llm():
   if os.getenv("OPENAI_API_KEY"):
       return "openai", "gpt-4o-mini", "OPENAI_API_KEY"
   if os.getenv("GEMINI_API_KEY"):
       return "gemini", "gemini-2.5-flash", "GEMINI_API_KEY"
   if os.getenv("ANTHROPIC_API_KEY"):
       return "anthropic", "claude-3-5-haiku-20241022", "ANTHROPIC_API_KEY"
   raise RuntimeError("Set one API key before running.")

Помощник для выполнения shell-команд

Небольшая функция run() выполняет команды оболочки из Python, печатает stdout и stderr для прозрачности и выбрасывает ошибку при неудаче — это полезно для логов в блокнотах и CI.

def run(cmd, check=True, env=None):
   print("▸", cmd)
   p = subprocess.run(cmd, shell=True, text=True, capture_output=True, env=env)
   if p.stdout: print(p.stdout)
   if p.stderr: print(p.stderr)
   if check and p.returncode != 0:
       raise RuntimeError(f"Command failed: {cmd}")
   return p

Установка Node.js и Cipher CLI

Убедитесь, что в окружении установлены Node.js, npm и Cipher CLI, прежде чем работать с Cipher.

def ensure_node_and_cipher():
   run("sudo apt-get update -y && sudo apt-get install -y nodejs npm", check=False)
   run("npm install -g @byterover/cipher")

Генерация cipher.yml с включенной памятью

Программа записывает cipher.yml в папку memAgent. Конфигурация задает провайдера и модель, ссылается на переменную окружения с API-ключом, включает systemPrompt для долгосрочной памяти и регистрирует файловую MCP-службу.

def write_cipher_yml(workdir, provider, model, key_env):
   cfg = """
llm:
 provider: {provider}
 model: {model}
 apiKey: ${key_env}
systemPrompt:
 enabled: true
 content: |
   You are an AI programming assistant with long-term memory of prior decisions.
embedding:
 disabled: true
mcpServers:
 filesystem:
   type: stdio
   command: npx
   args: ['-y','@modelcontextprotocol/server-filesystem','.']
""".format(provider=provider, model=model, key_env=key_env)
 
 
   (workdir / "memAgent").mkdir(parents=True, exist_ok=True)
   (workdir / "memAgent" / "cipher.yml").write_text(cfg.strip() + "n")

Выполнение разовой команды Cipher

cipher_once() запускает одну команду Cipher из Python, печатает ответ и возвращает его для дальнейшей обработки.

def cipher_once(text, env=None, cwd=None):
   cmd = f'cipher {shlex.quote(text)}'
   p = subprocess.run(cmd, shell=True, text=True, capture_output=True, env=env, cwd=cwd)
   print("Cipher says:n", p.stdout or p.stderr)
   return p.stdout.strip() or p.stderr.strip()

Запуск Cipher в режиме API

start_api() запускает Cipher как подпроцесс в режиме API и опрашивает /health до тех пор, пока сервис не станет доступен.

def start_api(env, cwd):
   proc = subprocess.Popen("cipher --mode api", shell=True, env=env, cwd=cwd,
                           stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
   for _ in range(30):
       try:
           r = requests.get("http://127.0.0.1:3000/health", timeout=2)
           if r.ok:
               print("API /health:", r.text)
               break
       except: pass
       time.sleep(1)
   return proc

Оркестрация демо

main() связывает все шаги: выбирает провайдера, устанавливает зависимости, пишет cipher.yml, сохраняет решения проекта в памяти Cipher, запрашивает их и кратко запускает API-сервер.

def main():
   provider, model, key_env = choose_llm()
   ensure_node_and_cipher()
   workdir = pathlib.Path(tempfile.mkdtemp(prefix="cipher_demo_"))
   write_cipher_yml(workdir, provider, model, key_env)
   env = os.environ.copy()
 
 
   cipher_once("Store decision: use pydantic for config validation; pytest fixtures for testing.", env, str(workdir))
   cipher_once("Remember: follow conventional commits; enforce black + isort in CI.", env, str(workdir))
 
 
   cipher_once("What did we standardize for config validation and Python formatting?", env, str(workdir))
 
 
   api_proc = start_api(env, str(workdir))
   time.sleep(3)
   api_proc.terminate()
 
 
if __name__ == "__main__":
   main()

Практическая ценность

Такой компактный воркфлоу защищает ключи, автоматически выбирает доступного LLM-провайдера, разворачивает агент с долгосрочной памятью в Cipher и открывает API для интеграций. Он удобен для блокнотов и CI, помогает программно фиксировать и запрашивать решения проекта.

🇬🇧

Switch Language

Read this article in English

Switch to English