Claude в Google Vertex AI

Подключение Claude через Google Cloud — авторизация, регионы, биллинг.

100 уроков, первые 3 бесплатно. Полный доступ: 1490 руб.

Уроки курса

  1. Welcome to the course
  2. Overview of Claude models
  3. Accessing the API
  4. Vertex AI Setup
  5. Making a request
  6. Multi-turn conversations
  7. Chat exercise
  8. System prompts
  9. System prompts exercise
  10. Temperature
  11. Course satisfaction survey
  12. Response streaming
  13. Controlling model output
  14. Structured data
  15. Structured data exercise
  16. Quiz on accessing Claude with the API
  17. Prompt evaluation
  18. A typical eval workflow
  19. Generating test datasets
  20. Running the eval
  21. Model based grading
  22. Code based grading
  23. Exercise on prompt evals
  24. Quiz on prompt evaluation
  25. Prompt engineering
  26. Being clear and direct
  27. Being specific
  28. Structure with XML tags
  29. Providing examples
  30. Exercise on prompting
  31. Quiz on prompt engineering techniques
  32. Introducing tool use
  33. Project overview
  34. Tool functions
  35. Tool schemas
  36. Handling message blocks
  37. Sending tool results
  38. Multi-turn conversations with tools
  39. Implementing multiple turns
  40. Using multiple tools
  41. The batch tool
  42. Tools for structured data
  43. The text edit tool
  44. The web search tool
  45. Quiz on tool use with Claude
  46. Introducing Retrieval Augmented Generation
  47. Text chunking strategies
  48. Text embeddings
  49. The full RAG flow
  50. Implementing the RAG flow
  51. BM25 lexical search
  52. A Multi-index RAG pipeline
  53. Reranking results
  54. Contextual retrieval
  55. Quiz on Retrieval Augmented Generation
  56. Extended thinking
  57. Image support
  58. PDF support
  59. Citations
  60. Prompt caching
  61. Rules of prompt caching
  62. Prompt caching in action
  63. Quiz on features of Claude
  64. Introducing MCP
  65. MCP clients
  66. Project setup
  67. Defining tools with MCP
  68. The server inspector
  69. Implementing a client
  70. Defining resources
  71. Accessing resources
  72. Defining prompts
  73. Prompts in the client
  74. MCP review
  75. Quiz on Model Context Protocol
  76. Anthropic apps
  77. Claude Code setup
  78. Claude Code in action
  79. Enhancements with MCP servers
  80. Parallelizing Claude Code
  81. Automated debugging
  82. Computer use
  83. How computer use works
  84. Agents and workflows
  85. Parallelization workflows
  86. Chaining workflows
  87. Routing workflows
  88. Agents and tools
  89. Environment inspection
  90. Workflows vs agents
  91. Quiz on agents and workflows
  92. Final assessment quiz
  93. Course Wrap Up
  94. Course Description
  95. Course Description
  96. Course Description
  97. Course Description
  98. Course Description
  99. Course Description
  100. Course Description

Многоходовые диалоги с использованием инструментов

При разработке приложений, использующих возможности больших языковых моделей (LLM), таких как Claude, часто возникает необходимость в интеграции различных внешних инструментов. Эти инструменты позволяют Claude выполнять действия, выходящие за рамки его собственных знаний, например, получать актуальные данные, выполнять вычисления или взаимодействовать с другими системами. Однако иногда для ответа на один, казалось бы, простой вопрос пользователя Claude может потребоваться последовательный вызов нескольких инструментов.

Представьте сценарий: пользователь спрашивает: "Какой день будет через 103 дня от сегодняшней даты?". Чтобы ответить на этот вопрос, Claude не может просто "знать" текущую дату или выполнить сложное календарное вычисление. Ему потребуется выполнить два отдельных шага:

  1. Сначала получить текущую дату, используя один инструмент (например, get_current_datetime).
  2. Затем, имея текущую дату, добавить к ней 103 дня, используя другой инструмент (например, add_duration_to_datetime).

Такой подход создает шаблон многоходового диалога, где Claude делает несколько запросов к инструментам, прежде чем предоставить окончательный ответ. Ваше приложение должно быть спроектировано таким образом, чтобы автоматически обрабатывать эту последовательность действий, обеспечивая бесшовное взаимодействие для конечного пользователя.

Многоходовый шаблон использования инструментов

Чтобы лучше понять, как это работает, давайте рассмотрим пошаговую последовательность событий, когда Claude нуждается в нескольких инструментах для выполнения задачи:

  1. Пользователь задает вопрос: "Какой день будет через 103 дня от сегодняшней даты?"
  2. Claude анализирует запрос: Модель понимает, что ей нужна текущая дата. Она генерирует блок использования инструмента, запрашивая вызов функции get_current_datetime.
  3. Ваш сервер обрабатывает запрос: Ваше приложение перехватывает этот запрос инструмента, вызывает соответствующую функцию на вашей стороне (например, обращается к системным часам) и возвращает результат (например, "2023-10-26").
  4. Claude продолжает обработку: Получив текущую дату, Claude осознает, что теперь ему нужно выполнить второе действие — добавить 103 дня. Он генерирует новый блок использования инструмента, запрашивая вызов функции add_duration_to_datetime с параметрами "2023-10-26" и "103 дня".
  5. Ваш сервер обрабатывает второй запрос: Ваше приложение снова перехватывает запрос, вызывает функцию add_duration_to_datetime и возвращает результат (например, "2024-02-06").
  6. Claude формирует окончательный ответ: Теперь у Claude есть вся необходимая информация. Он формулирует и предоставляет окончательный ответ пользователю: "Через 103 дня от сегодняшней даты будет 6 февраля 2024 года."

Этот процесс происходит "за кулисами", и для пользователя он выглядит как единый, мгновенный ответ, хотя на самом деле Claude и ваше приложение выполнили несколько итераций взаимодействия.

Создание цикла диалога

Для эффективной обработки многоходовых шаблонов использования инструментов необходимо реализовать цикл диалога, который будет продолжаться до тех пор, пока Claude не перестанет запрашивать инструменты и не предоставит окончательный ответ. Этот цикл является сердцем вашей логики взаимодействия с LLM.

Концептуально, такой цикл можно представить следующим образом:

def run_conversation(messages):
    while True:
        # Отправляем текущий набор сообщений Claude и получаем ответ
        response = chat(messages)
        
        # Добавляем ответ Claude в историю диалога
        add_assistant_message(messages, response) # Или add_user_message, если ответ содержит tool_results
        
        # Проверяем, содержит ли ответ Claude запрос на использование инструмента
        if not response_is_asking_for_a_tool(response):
            # Если нет, Claude предоставил окончательный ответ, выходим из цикла
            break
        
        # Если да, выполняем запрошенные инструменты
        tool_result_blocks = run_tools(response)
        
        # Добавляем результаты выполнения инструментов обратно в историю диалога
        add_tool_result_message(messages, tool_result_blocks) # Это будет сообщением от "пользователя" для Claude
        
    return messages # Возвращаем полную историю диалога

В этом псевдокоде функция chat(messages) отправляет историю диалога Claude и получает его ответ. Функция response_is_asking_for_a_tool(response) проверяет, содержит ли ответ Claude блок tool_use. Если да, то run_tools(response) выполняет эти инструменты, а их результаты добавляются обратно в историю диалога как новое сообщение, которое Claude затем обрабатывает на следующей итерации цикла. Этот процесс повторяется до тех пор, пока Claude не сможет дать окончательный ответ без вызова дополнительных инструментов.

Рефакторинг вспомогательных функций

Прежде чем реализовать полноценный цикл диалога, необходимо обновить вспомогательные функции, чтобы они могли корректно обрабатывать различные типы сообщений и блоков, которые могут поступать от Claude или отправляться ему. В контексте работы с инструментами сообщения становятся более сложными, чем просто текстовые строки.

Обновление обработчиков сообщений

Традиционные функции, такие как add_user_message и add_assistant_message, часто были разработаны для работы с простыми текстовыми строками. Однако ответы Claude, особенно при использовании инструментов, могут содержать не только текст, но и блоки tool_use или tool_result. Чтобы обеспечить гибкость, эти функции должны уметь принимать различные форматы:

Пример обновленной функции add_user_message:

from anthropic.types import Message

def add_user_message(messages, message):
    user_message = {
        "role": "user",
        "content": message.content if isinstance(message, Message) else message
    }
    messages.append(user_message)

Эта функция теперь позволяет передавать в качестве message либо строку, либо список блоков, либо полный объект Message. Если передан объект Message, она извлекает его содержимое (message.content); в противном случае она использует переданное значение как есть. Это значительно повышает гибкость и упрощает добавление как пользовательских запросов, так и результатов выполнения инструментов в историю диалога.

Обновление функции чата

Ваша основная функция, которая взаимодействует с API Claude (например, chat), также требует модификации. Ей необходимо:

  1. Принимать список доступных инструментов (tools), которые Claude может использовать.
  2. Возвращать полный объект сообщения (Message), а не только извлеченный текст. Это критически важно, поскольку полный объект содержит информацию о запросах инструментов.

Пример обновленной функции chat:

def chat(messages, system=None, temperature=1.0, stop_sequences=[], tools=None):
    params = {
        "model": model, # Предполагается, что 'model' определена глобально или передается
        "max_tokens": 1000,
        "messages": messages,
        "temperature": temperature,
        "stop_sequences": stop_sequences,
    }
    if tools:
        params["tools"] = tools # Добавляем список инструментов, если он предоставлен
    if system:
        params["system"] = system # Добавляем системный промпт, если он предоставлен
        
    message = client.messages.create(**params) # Вызываем API и получаем полный объект Message
    return message

Ключевые изменения здесь — это добавление параметра tools, который передается в API Claude, и то, что функция теперь возвращает полный объект Message. Этот объект может содержать различные типы блоков, включая tool_use, которые необходимы для реализации многоходового диалога.

Извлечение текста из сообщений

Поскольку функция chat теперь возвращает полные объекты Message, а не просто текст, вам понадобится вспомогательная функция для извлечения только текстового содержимого, когда это необходимо (например, для отображения окончательного ответа пользователю).

def text_from_message(message):
    return "\n".join(
        [block.text for block in message.content if block.type == "text"]
    )

Эта функция просматривает все блоки в содержимом сообщения (message.content), находит те, у которых type равен "text", и объединяет их текстовое содержимое в одну строку. Это полезно, когда вы хотите показать пользователю только читаемый текст, игнорируя внутренние блоки tool_use или tool_result.

Почему эти изменения важны

Эти шаги по рефакторингу подготавливают ваш код к реалиям диалогов с поддержкой инструментов, делая его более надежным и гибким:

С этими фундаментальными изменениями вы готовы реализовать полноценный цикл диалога, который автоматически обрабатывает множественные вызовы инструментов. Это создает бесшовный опыт, где Claude может использовать любые необходимые инструменты для полного и точного ответа на вопросы пользователей, даже если для этого требуется несколько шагов.