Как написать ИИ-агента для Anki на Python с Antigravity SDK: замените лень на привычку учиться с автоматическими колодами и голосовыми ответами.
Вы тоже жмёте «Good» на карточке Anki, хотя толком не вспомнили ответ? ИИ может стать честным репетитором, который не даст вам халтурить. В этой статье я покажу, как собрать агента, который проведёт вас по колоде, сравнит ваш ответ с правильным и сам выставит оценку. А главное — он умеет создавать карточки из кода и веб-статей, так что вы не будете тратить часы на ручное заполнение.
Проект построен на Antigravity SDK — библиотеке для создания агентов на Python. Мы пройдём путь от простого чата до полноценной системы с голосовым вводом через Telegram и автоматическим сбором колод из репозитория.
Первая идея — сунуть всё в системный промпт: правила сессии, стиль карточек, поведение в Telegram. Работает минут десять, а потом промпт превращается в свалку. Агент путается, когда думает о Spanish verbs, а вы ему подсовываете архитектуру кода.
Решение — вынести поведение в навыки (skills). Каждый навык — это папка с файлом SKILL.md, где описан протокол для конкретной задачи. Системный промпт остаётся маленьким: «ты дружелюбный репетитор». А детали — в навыках.
Установите библиотеку:
pip install google-antigravityПолучите API-ключ в Google AI Studio и экспортируйте:
export GEMINI_API_KEY="your-key-here"Установите дополнение AnkiConnect в Anki (номер порта 8765 по умолчанию).
import asyncio
from google.antigravity import Agent, LocalAgentConfig
async def main():
config = LocalAgentConfig()
async with Agent(config) as agent:
response = await agent.chat("Какие файлы в текущей папке?")
print(await response.text())
if __name__ == "__main__":
asyncio.run(main())Этот код запускает локального агента, который может читать файлы. Теперь дадим ему руки — инструменты для работы с Anki.
AnkiConnect — это HTTP API на localhost:8765. Оборачиваем вызовы в простые функции:
def invoke(action: str, **params):
import requests
response = requests.post("http://localhost:8765",
json={"action": action, "version": 6, "params": params},
timeout=30)
response.raise_for_status()
payload = response.json()
if payload["error"]:
raise RuntimeError(payload["error"])
return payload["result"]
def list_decks() -> str:
"""Список всех колод с количеством карточек к повторению."""
decks = invoke("deckNames")
stats = invoke("getDeckStats", decks=decks)
import json
return json.dumps(stats)
def get_due_cards(deck: str = "", limit: int = 5) -> str:
"""Возвращает карточки, ожидающие повторения, без ответа."""
query = f'deck:"{deck}" is:due' if deck else "is:due"
card_ids = invoke("findCards", query=query)[:limit]
cards = invoke("cardsInfo", cards=card_ids)
import json
return json.dumps(cards)
def rate_card(card_id: int, rating: int) -> str:
"""Оценить карточку: 1 — Again, 2 — Hard, 3 — Good, 4 — Easy."""
invoke("answerCards", answers=[{"cardId": card_id, "ease": rating}])
import json
return json.dumps({"rated": card_id, "rating": rating})Регистрируем инструменты в конфиге:
from google.antigravity import LocalAgentConfig
config = LocalAgentConfig(
tools=[list_decks, get_due_cards, rate_card]
)Теперь агент может видеть колоды, доставать карточки и выставлять оценки. Но этого мало — нужно ещё поведение.
Создаём папку .agents/skills/ и внутри — три навыка.
Файл .agents/skills/review-buddy/SKILL.md:
---
name: review-buddy
description: Playbook для интерактивной сессии повторения Anki — по одной карточке, сравнение ответов, выставление оценки.
---
1. Покажи вопрос карточки.
2. Дождись ответа пользователя.
3. Покажи правильный ответ.
4. Сравни ответ пользователя с правильным, объясни разницу.
5. Предложи оценку (Again/Hard/Good/Easy).
6. Дождись подтверждения, затем вызови rate_card.
7. Повторяй, пока не закончатся due карточки или пользователь не остановит.
8. В конце — краткий recap: сколько карточек, какие оценки.Это не код, а протокол. Агент может следовать ему и в терминале, и в Telegram.
Файл .agents/skills/plain-cards/SKILL.md:
---
name: plain-cards
description: Правила создания качественных карточек Anki — атомарность, ответ вперёд, без мусора.
---
- Один факт на карточку.
- Ответ — на лицевой стороне, вопрос — на обратной (answer-first).
- Избегай общих вопросов вроде "Что такое X?".
- Не добавляй "мусорные" детали.
- Карточка должна быть понятна через месяц.
- Проверяй, что карточка действительно проверяет знание, а не узнавание.Файл .agents/skills/codebase-cards/SKILL.md:
---
name: codebase-cards
description: Превращение кода в карточки Anki — архитектура, потоки данных, gotchas.
---
1. Исследуй репозиторий в ширину: найди ключевые абстракции.
2. Определи ответственность каждого модуля и потоки данных.
3. Выяви неочевидные решения ("почему здесь так?").
4. Создавай карточки только для полезных находок, не для синтаксиса.
5. Каждая карточка должна проверять понимание, а не память.Загружаем навыки в конфиг:
config = LocalAgentConfig(
system_instructions="Ты дружелюбный репетитор по карточкам Anki.",
tools=[list_decks, get_due_cards, rate_card, show_answer, add_notes],
skills_paths=[".agents/skills"]
)Теперь агент знает, когда включать какой навык.
Antigravity SDK поддерживает хуки — функции, которые вызываются до/после действий. Например, создаём резервную копию колоды перед записью:
async def on_before_write(context):
invoke("exportPackage", deck="*", path=f"/tmp/anki_backup_{int(time.time())}.apkg")
config = LocalAgentConfig(
lifecycle_hooks={"before_tool_call": on_before_write}
)Политики безопасности блокируют опасные действия. Например, запрещаем агенту менять расписание в режиме практики:
from google.antigravity import SafetyPolicy
class PracticeMode(SafetyPolicy):
async def check_tool_call(self, tool_name, args, context):
if tool_name == "rate_card":
raise PermissionError("Нельзя менять оценки в режиме практики")
config = LocalAgentConfig(
safety_policies=[PracticeMode()]
)Объединяем всё вместе. Вот полный код терминального тьютора:
import asyncio
from google.antigravity import Agent, LocalAgentConfig
SYSTEM_INSTRUCTIONS = "Ты дружелюбный репетитор. Используй навыки для проведения сессии."
# Инструменты (определены выше)
TOOLS = [list_decks, get_due_cards, rate_card, show_answer, add_notes]
async def main():
config = LocalAgentConfig(
system_instructions=SYSTEM_INSTRUCTIONS,
tools=TOOLS,
skills_paths=[".agents/skills"],
)
async with Agent(config) as agent:
print("Запуск сессии повторения. Введи 'стоп' для выхода.")
while True:
user_input = input("Ты: ")
if user_input.lower() == "стоп":
break
response = await agent.chat(user_input)
print(f"Агент: {await response.text()}")
if __name__ == "__main__":
asyncio.run(main())Запустите и попробуйте: Начни сессию повторения. Агент сам достанет due карточки и проведёт вас по ним.
Мы построили агента, который:
Попробуйте прямо сейчас: установите библиотеку, настройте AnkiConnect и запустите пример выше. Через 15 минут у вас будет личный ИИ-тьютор, который не даст вам жульничать.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →