Динамический промпт
Секции из прошлого урока сейчас - здоровенная f-строка в
main.py. Будет другая папка, другой набор tools, ветка git -
и вы снова лезете в середину многострочника с ножницами. Давайте починим это, вынесем сборку в функцию:
на входе факты о запуске, на выходе текст промпта.
prompts.py с build_system_prompt(ctx).
В main.py вместо простыни будет
instructions=build_system_prompt({...}) - вызов функции с контекстом.
Слова по делу
- Контекст промпта - обычный словарь/TypedDict: cwd, тип песочницы, имена tools, опционально ветка и текст из AGENTS.md.
-
Чистая функция - одни и те же входные данные ->
один и тот же текст. Без чтения диска внутри (чтение AGENTS.md
сделаем в
main.pyна уроке 3.4).
Быстрый путь
- Создать
prompts.py. - Перенести туда Agency / Guardrails из
main.py. - В
main.pyвызватьbuild_system_prompt(...)- вызов функции с контекстом. - Один раз
printготового текста и посмотреть глазами, как выглядит промпт.
Какие файлы трогаем
| Файл | Что делать |
|---|---|
prompts.py |
Создать. PromptContext + build_system_prompt. |
main.py |
Править. Убрать длинный f-string; вызвать билдер. |
| остальное | Не трогать. |
Шаг 1. Создайте prompts.py
prompts.py (целиком)
from typing import TypedDict, NotRequired
class PromptContext(TypedDict):
working_directory: str
sandbox_type: str
tool_names: list[str]
git_branch: NotRequired[str]
project_context: NotRequired[str]
def build_system_prompt(ctx: PromptContext) -> str:
parts: list[str] = []
parts.append(f"Ты coding-агент. Рабочая директория: {ctx['working_directory']}")
parts.append(f"Песочница (sandbox): {ctx['sandbox_type']}")
tools = ", ".join(ctx["tool_names"])
parts.append(f"""
# Agency
- ПОЛЬЗУЙСЯ инструментами: читай, ищи, запускай — потом отвечай.
- НЕ объясняй, что собираешься сделать. Сделай, потом коротко отчитайся.
- Доступные инструменты: {tools}
- Для поиска — grep, для файла — read; bash — только если без него никак.
""")
if branch := ctx.get("git_branch"):
parts.append(f"- Текущая ветка git: {branch}")
parts.append("""
# Guardrails
- Меняй по минимуму.
- Сначала поищи существующий паттерн в проекте.
- Новые зависимости — только по явной просьбе пользователя.
""")
if project := ctx.get("project_context"):
parts.append(f"""
# Инструкции проекта (из AGENTS.md)
{project}
""")
return "\n".join(parts)
Никакого Jinja и «фреймворка промптов». Список строк +
join. Условные куски — обычный if.
Скучно? Отлично: так и должно быть.
Шаг 2. Подключите в main.py
Удалите здоровенный instructions = f"""..."""
из прошлого урока. Вместо него:
main.py — фрагмент
from prompts import build_system_prompt
# имена так, как вы реально регистрируете tools
tool_names = ["read", "grep", "bash"]
instructions = build_system_prompt({
"working_directory": str(cwd),
"sandbox_type": "local",
"tool_names": tool_names,
# позже: "git_branch": "...", "project_context": "..."
})
# временно — убедиться, что секции на месте:
# print(instructions)
agent = Agent(
"deepseek:deepseek-chat",
deps_type=Path,
tools=[Tool(bash_fn, takes_ctx=False)],
instructions=instructions,
)
Проверьте
uv run python main.py . "Найди все TODO-комментарии в проекте"
Поведение как в 3.1 (текст промпта тот же по смыслу).
Раскомментируйте print(instructions): должны быть
cwd, sandbox local, Agency, Guardrails и список tools.
Бонус: передайте "git_branch": "main" и снова
print — строка про ветку есть. Уберите ключ —
строки нет.
Готово, если:
- Есть файл
prompts.pyсbuild_system_prompt - В
main.pyinstructions собирается через эту функцию, а не гигантским f-string git_branchиproject_contextопциональны и появляются только если переданы- В распечатке промпта видны Agency, Guardrails и имена tools