<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://doc.ruscomtech.ru/index.php?action=history&amp;feed=atom&amp;title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3_%D0%BD%D0%B0%D0%B1%D0%BB%D1%8E%D0%B4%D0%B0%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D0%B8_RAG%E2%80%91%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D0%B9%D0%B5%D1%80%D0%BE%D0%B2</id>
	<title>Мониторинг наблюдаемости RAG‑конвейеров - История изменений</title>
	<link rel="self" type="application/atom+xml" href="https://doc.ruscomtech.ru/index.php?action=history&amp;feed=atom&amp;title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3_%D0%BD%D0%B0%D0%B1%D0%BB%D1%8E%D0%B4%D0%B0%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D0%B8_RAG%E2%80%91%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D0%B9%D0%B5%D1%80%D0%BE%D0%B2"/>
	<link rel="alternate" type="text/html" href="https://doc.ruscomtech.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3_%D0%BD%D0%B0%D0%B1%D0%BB%D1%8E%D0%B4%D0%B0%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D0%B8_RAG%E2%80%91%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D0%B9%D0%B5%D1%80%D0%BE%D0%B2&amp;action=history"/>
	<updated>2026-09-16T15:25:34Z</updated>
	<subtitle>История изменений этой страницы в вики</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://doc.ruscomtech.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3_%D0%BD%D0%B0%D0%B1%D0%BB%D1%8E%D0%B4%D0%B0%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D0%B8_RAG%E2%80%91%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D0%B9%D0%B5%D1%80%D0%BE%D0%B2&amp;diff=6134&amp;oldid=prev</id>
		<title>IKuznetsov: Новая страница: «Большие языковые модели (&#039;&#039;&#039;LLM&#039;&#039;&#039;) обучаются на огромных объемах данных. Однако они могут им...»</title>
		<link rel="alternate" type="text/html" href="https://doc.ruscomtech.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3_%D0%BD%D0%B0%D0%B1%D0%BB%D1%8E%D0%B4%D0%B0%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D0%B8_RAG%E2%80%91%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D0%B9%D0%B5%D1%80%D0%BE%D0%B2&amp;diff=6134&amp;oldid=prev"/>
		<updated>2026-01-29T19:48:18Z</updated>

		<summary type="html">&lt;p&gt;Новая страница: «Большие языковые модели (&amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039;) обучаются на огромных объемах данных. Однако они могут им...»&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Большие языковые модели (&amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039;) обучаются на огромных объемах данных. Однако они могут иметь определенные ограничения.&lt;br /&gt;
&lt;br /&gt;
* Данные для обучения являются статическими и ограничены датой актуализации знаний.&lt;br /&gt;
* Большие языковые модели могут генерировать недостоверные сведения в случаях, когда ответ отсутствует в их базе знаний.&lt;br /&gt;
&lt;br /&gt;
Этот пример иллюстрирует распространенный подход к преодолению этих ограничений, который заключается в использовании конвейера генерации с расширенным поиском (&amp;#039;&amp;#039;&amp;#039;Retrieval-Augmented Generation&amp;#039;&amp;#039;&amp;#039;, &amp;#039;&amp;#039;&amp;#039;RAG&amp;#039;&amp;#039;&amp;#039;) для предоставления &amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039; дополнительной контекстной информации из авторитетного источника знаний, что приводит к более точным ответам и большему контролю над генерируемым результатом.&lt;br /&gt;
&lt;br /&gt;
== Чему вы научитесь? ==&lt;br /&gt;
В этом уроке мы создадим простой &amp;#039;&amp;#039;&amp;#039;API&amp;#039;&amp;#039;&amp;#039; на &amp;#039;&amp;#039;&amp;#039;Python&amp;#039;&amp;#039;&amp;#039;, который использует [https://www.langchain.com/ LangChain]﻿ для реализации чат-бота, предлагающего туристические направления для вашей следующей поездки.&lt;br /&gt;
&lt;br /&gt;
* Чат-бот представляет собой конвейер &amp;#039;&amp;#039;&amp;#039;RAG&amp;#039;&amp;#039;&amp;#039;, использующий [https://www.pinecone.io/ Pinecone]﻿ для получения релевантной информации для желаемого пользователем места назначения.&lt;br /&gt;
* Мы получаем ответ, используя [https://ollama.com/ Ollama]﻿ в качестве линейной модели.&lt;br /&gt;
* Мы используем &amp;#039;&amp;#039;&amp;#039;OpenTelemetry&amp;#039;&amp;#039;&amp;#039; для мониторинга кода, чтобы получить подробную информацию о производительности нашего &amp;#039;&amp;#039;&amp;#039;API&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
== Прежде чем начать ==&lt;br /&gt;
&lt;br /&gt;
=== Предварительные требования ===&lt;br /&gt;
&lt;br /&gt;
* Доступ к вашей среде &amp;#039;&amp;#039;&amp;#039;Kubernetes&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
* Бесплатный аккаунт &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
== Шаги ==&lt;br /&gt;
Общие этапы следующие:&lt;br /&gt;
&lt;br /&gt;
# Создание API-ключей для подключения к &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039; и Ключ-АСТРОМ.&lt;br /&gt;
# Развертка нашего приложение в кластере &amp;#039;&amp;#039;&amp;#039;Kubernetes&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
# Визуализация важных сигналов приложения, чтобы отслеживать затраты и качество ответов.&lt;br /&gt;
&lt;br /&gt;
Подробности каждого этапа см. ниже.&lt;br /&gt;
&lt;br /&gt;
=== Подготовка ключей API ===&lt;br /&gt;
На этом этапе мы создадим два API-ключа и сохраним их в качестве секретов &amp;#039;&amp;#039;&amp;#039;Kubernetes&amp;#039;&amp;#039;&amp;#039;. API-ключи будут использоваться для подключения к Ключ-АСТРОМ и &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
==== Создание токена Ключ-АСТРОМ ====&lt;br /&gt;
Для создания токена Ключ-АСТРОМ&lt;br /&gt;
&lt;br /&gt;
# В Ключ-АСТРОМ перейдите в раздел &amp;#039;&amp;#039;&amp;#039;Токены доступа&amp;#039;&amp;#039;&amp;#039;. &amp;lt;br /&amp;gt;Чтобы найти &amp;#039;&amp;#039;&amp;#039;Токены доступа&amp;#039;&amp;#039;&amp;#039;, нажмите &amp;#039;&amp;#039;&amp;#039;CTRL+K&amp;#039;&amp;#039;&amp;#039; для поиска и выберите &amp;#039;&amp;#039;&amp;#039;Токены доступа&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
# В разделе &amp;#039;&amp;#039;&amp;#039;Токены доступа&amp;#039;&amp;#039;&amp;#039; выберите &amp;#039;&amp;#039;&amp;#039;Сгенерировать новый токен&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
# Введите имя для вашего нового токена.&lt;br /&gt;
# Предоставьте своему новому токену следующие права доступа:&lt;br /&gt;
# Найдите и выберите все следующие области применения.&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Метрики приема&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;metrics.ingest&amp;lt;/code&amp;gt;)&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Логи загрузки&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;logs.ingest&amp;lt;/code&amp;gt;)&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;События приема&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;events.ingest&amp;lt;/code&amp;gt;)&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Приём трассировок OpenTelemetry&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;openTelemetryTrace.ingest&amp;lt;/code&amp;gt;)&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Чтение метрик&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;metrics.read&amp;lt;/code&amp;gt;)&lt;br /&gt;
#* &amp;#039;&amp;#039;&amp;#039;Настройки записи&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;settings.write&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Выберите &amp;#039;&amp;#039;&amp;#039;Сгенерировать токен&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
# Скопируйте сгенерированный токен в буфер обмена. Сохраните токен в менеджере паролей для дальнейшего использования.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|Вы можете получить доступ к своему токену только один раз при его создании. После этого вы не сможете его раскрыть.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Сохранение ключа API в качестве секрета Kubernetes ====&lt;br /&gt;
Теперь, когда у вас есть токен с необходимыми правами доступа, вы можете использовать следующую команду для сохранения ключа &amp;#039;&amp;#039;&amp;#039;API&amp;#039;&amp;#039;&amp;#039; Ключ-АСТРОМ в качестве секрета &amp;#039;&amp;#039;&amp;#039;Kubernetes&amp;#039;&amp;#039;&amp;#039;. Наше приложение на &amp;#039;&amp;#039;&amp;#039;Python&amp;#039;&amp;#039;&amp;#039; будет использовать его для отправки данных мониторинга вашему клиенту.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|kubectl create secret generic astromkey --from-literal token=&amp;lt;your-api-key&amp;gt; -n travel-advisor&lt;br /&gt;
|}&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Если ошибка вызвана отсутствием пространства имен&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Если команда возвращает ошибку из-за отсутствия пространства имен, вы можете создать его, выполнив команду &amp;lt;code&amp;gt;kubectl create namespace travel-advisor&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Подключение к Pinecone ====&lt;br /&gt;
Для подключения к &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
# Создайте новый индекс &amp;lt;code&amp;gt;travel-advisor&amp;lt;/code&amp;gt; с размерами 3200 и метрикой &amp;lt;code&amp;gt;cosine&amp;lt;/code&amp;gt;.  &amp;lt;br /&amp;gt;Индекс будет хранить наш источник знаний, который конвейер &amp;#039;&amp;#039;&amp;#039;RAG&amp;#039;&amp;#039;&amp;#039; будет использовать для расширения выходных данных &amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039;, касающихся рекомендаций по путешествиям. Обоснование выбора параметров будет обсуждаться далее, в разделе развертывания .&lt;br /&gt;
# После создания и запуска индекса мы можем создать ключ &amp;#039;&amp;#039;&amp;#039;API&amp;#039;&amp;#039;&amp;#039; для подключения.  &amp;lt;br /&amp;gt;Следуйте [https://docs.pinecone.io/reference/api/authentication инструкциям в документации Pinecone по аутентификации]﻿, чтобы получить ключ &amp;#039;&amp;#039;&amp;#039;API&amp;#039;&amp;#039;&amp;#039; для подключения к вашему индексу &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039; и сохранить его в качестве секретов &amp;#039;&amp;#039;&amp;#039;Kubernetes&amp;#039;&amp;#039;&amp;#039; с помощью следующей команды:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|kubectl create secret generic pinecone --from-literal api-key=&amp;lt;your-api-key&amp;gt; -n travel-advisor&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Создание и развертка конвейера RAG ===&lt;br /&gt;
В нашем демонстрационном приложении мы используем [https://ollama.com/ Ollama]﻿ для генерации ответа.&lt;br /&gt;
&lt;br /&gt;
Мы также используем &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039; для &amp;#039;&amp;#039;эмбеддинга&amp;#039;&amp;#039; — процесса преобразования текста в векторы, которые отражают его семантическое значение. Эмбеддинг позволяет представить источник знаний в виде математических объектов, хранящихся в индексе &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039;. Аналогичным образом мы можем обработать ввод пользователя, найти схожие векторы в индексе &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039; и предоставить дополнительной информации большой языковой модели (&amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039;) для формирования итогового ответа.&lt;br /&gt;
&lt;br /&gt;
1. Создайте новое пространство имен &amp;#039;&amp;#039;&amp;#039;Kubernetes&amp;#039;&amp;#039;&amp;#039; с именем &amp;lt;code&amp;gt;ollama&amp;lt;/code&amp;gt;.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|apiVersion: v1&lt;br /&gt;
&lt;br /&gt;
kind: Namespace&lt;br /&gt;
&lt;br /&gt;
metadata:&lt;br /&gt;
&lt;br /&gt;
  name: ollama&lt;br /&gt;
&lt;br /&gt;
  labels:&lt;br /&gt;
&lt;br /&gt;
    name: ollama&lt;br /&gt;
|}&lt;br /&gt;
2. Разверните последнюю версию &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039;, работающую на порту &amp;#039;&amp;#039;&amp;#039;11434&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
По умолчанию контейнер &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039; не содержит никакой модели. Нам необходимо указать контейнеру, какую модель следует загрузить, и сделать её доступной через его &amp;#039;&amp;#039;&amp;#039;API&amp;#039;&amp;#039;&amp;#039;. Для этого мы указываем в &amp;#039;&amp;#039;&amp;#039;Kubernetes&amp;#039;&amp;#039;&amp;#039; команду &amp;lt;code&amp;gt;ollama run orca-mini:3b&amp;lt;/code&amp;gt; после запуска контейнера, которая, в свою очередь, указывает &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039; загрузить модель﻿ LLM [https://ollama.com/library/orca-mini orca-mini:3b].&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|apiVersion: apps/v1&lt;br /&gt;
&lt;br /&gt;
kind: Deployment&lt;br /&gt;
&lt;br /&gt;
metadata:&lt;br /&gt;
&lt;br /&gt;
  name: ollama&lt;br /&gt;
&lt;br /&gt;
  namespace: ollama&lt;br /&gt;
&lt;br /&gt;
spec:&lt;br /&gt;
&lt;br /&gt;
  selector:&lt;br /&gt;
&lt;br /&gt;
    matchLabels:&lt;br /&gt;
&lt;br /&gt;
      name: ollama&lt;br /&gt;
&lt;br /&gt;
  template:&lt;br /&gt;
&lt;br /&gt;
    metadata:&lt;br /&gt;
&lt;br /&gt;
      labels:&lt;br /&gt;
&lt;br /&gt;
        name: ollama&lt;br /&gt;
&lt;br /&gt;
    spec:&lt;br /&gt;
&lt;br /&gt;
      containers:&lt;br /&gt;
&lt;br /&gt;
        - name: ollama&lt;br /&gt;
&lt;br /&gt;
          image: ollama/ollama:latest&lt;br /&gt;
&lt;br /&gt;
          ports:&lt;br /&gt;
&lt;br /&gt;
            - name: http&lt;br /&gt;
&lt;br /&gt;
              containerPort: 11434&lt;br /&gt;
&lt;br /&gt;
              protocol: TCP&lt;br /&gt;
&lt;br /&gt;
          lifecycle:&lt;br /&gt;
&lt;br /&gt;
            postStart:&lt;br /&gt;
&lt;br /&gt;
              exec:&lt;br /&gt;
&lt;br /&gt;
                command: [ &amp;quot;/bin/sh&amp;quot;, &amp;quot;-c&amp;quot;, &amp;quot;ollama run orca-mini:3b&amp;quot; ]&lt;br /&gt;
|}&lt;br /&gt;
3. Укажите &amp;#039;&amp;#039;&amp;#039;Kubernetes&amp;#039;&amp;#039;&amp;#039;, чтобы он предоставлял доступ к этим &amp;#039;&amp;#039;&amp;#039;API&amp;#039;&amp;#039;&amp;#039; другим контейнерам через сервис &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;http://ollama.ollama&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|apiVersion: v1&lt;br /&gt;
&lt;br /&gt;
kind: Service&lt;br /&gt;
&lt;br /&gt;
metadata:&lt;br /&gt;
&lt;br /&gt;
  name: ollama&lt;br /&gt;
&lt;br /&gt;
  namespace: ollama&lt;br /&gt;
&lt;br /&gt;
spec:&lt;br /&gt;
&lt;br /&gt;
  type: ClusterIP&lt;br /&gt;
&lt;br /&gt;
  selector:&lt;br /&gt;
&lt;br /&gt;
    name: ollama&lt;br /&gt;
&lt;br /&gt;
  ports:&lt;br /&gt;
&lt;br /&gt;
    - port: 80&lt;br /&gt;
&lt;br /&gt;
      name: http&lt;br /&gt;
&lt;br /&gt;
      targetPort: 11434&lt;br /&gt;
&lt;br /&gt;
      protocol: TCP&lt;br /&gt;
|}&lt;br /&gt;
4. Теперь, когда &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039; запущен, мы можем создать наш конвейер &amp;#039;&amp;#039;&amp;#039;LangChain RAG&amp;#039;&amp;#039;&amp;#039; с помощью некоторого кода на &amp;#039;&amp;#039;&amp;#039;Python&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Создайте объект, который будет использоваться для связи с &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039; для выполнения этапа встраивания. &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039; возвращает векторы &amp;lt;code&amp;gt;orca-mini:3b&amp;lt;/code&amp;gt; фиксированного размера &amp;#039;&amp;#039;&amp;#039;3200&amp;#039;&amp;#039;&amp;#039;. Именно поэтому мы установили свойство &amp;lt;code&amp;gt;dimensions&amp;lt;/code&amp;gt; нашего индекса &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039; равным &amp;#039;&amp;#039;&amp;#039;3200&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|from langchain_community.embeddings import OllamaEmbeddings&lt;br /&gt;
&lt;br /&gt;
embeddings = OllamaEmbeddings(model=&amp;quot;orca-mini:3b&amp;quot;, base_url=&amp;quot;&amp;lt;nowiki&amp;gt;http://ollama.ollama&amp;lt;/nowiki&amp;gt;&amp;quot;)&lt;br /&gt;
|}&lt;br /&gt;
5. Загрузите документы из локальной файловой системы.&lt;br /&gt;
&lt;br /&gt;
В данном примере у нас имеется несколько HTML‑страниц с рекомендациями о том, какие места стоит посетить в этих городах.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|# Retrieve the source data&lt;br /&gt;
&lt;br /&gt;
docs_list = []&lt;br /&gt;
&lt;br /&gt;
for item in os.listdir(path=&amp;quot;destinations&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
    if item.endswith(&amp;quot;.html&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
        item_docs_list = BSHTMLLoader(file_path=f&amp;quot;destinations/{item}&amp;quot;).load()&lt;br /&gt;
&lt;br /&gt;
        for item in item_docs_list:&lt;br /&gt;
&lt;br /&gt;
            docs_list.append(item)&lt;br /&gt;
|}&lt;br /&gt;
6. Разбейте документы на фрагменты.&lt;br /&gt;
&lt;br /&gt;
Разделение текста на фрагменты важно, поскольку большие языковые модели (&amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039;) имеют известное ограничение — окно контекста (&amp;#039;&amp;#039;context window&amp;#039;&amp;#039;), определяющее границы объёма текста, который модель способна обработать и осмыслить. Разбиение документов на фрагменты позволяет &amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039;‑модели эффективно анализировать их содержимое и использовать его для формирования ответа.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|# Split Document into tokens&lt;br /&gt;
&lt;br /&gt;
text_splitter = RecursiveCharacterTextSplitter()&lt;br /&gt;
&lt;br /&gt;
documents = text_splitter.split_documents(docs_list)&lt;br /&gt;
&lt;br /&gt;
logger.info(&amp;quot;Loading documents from PineCone...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
vector = PineconeVectorStore.from_documents(&lt;br /&gt;
&lt;br /&gt;
    documents,&lt;br /&gt;
&lt;br /&gt;
    index_name=&amp;quot;travel-advisor&amp;quot;, # PineCone index to use&lt;br /&gt;
&lt;br /&gt;
    embedding=embeddings # we&amp;#039;re telling LangChain to use Ollama for the embedding step&lt;br /&gt;
&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
retriever = vector.as_retriever()&lt;br /&gt;
|}&lt;br /&gt;
7. Инициализируйте модель &amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039; и оформите ввод пользователя в виде промпта, который задаёт ожидаемый от модели ответ.&lt;br /&gt;
&lt;br /&gt;
Мы используем шаблон с двумя переменными:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;input&amp;lt;/code&amp;gt;: это поле заполняется текстом, введенным пользователем.&lt;br /&gt;
* &amp;lt;code&amp;gt;context&amp;lt;/code&amp;gt;: этот раздел содержит актуальную информацию, полученную из индекса Pinecone.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|llm = ChatOllama(model=&amp;quot;orca-mini:3b&amp;quot;, base_url=&amp;quot;&amp;lt;nowiki&amp;gt;http://ollama.ollama&amp;lt;/nowiki&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
prompt = ChatPromptTemplate.from_template(&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
1. Use the following pieces of context to answer the question as travel advise at the end.&lt;br /&gt;
&lt;br /&gt;
2. Keep the answer crisp and limited to 3,4 sentences.&lt;br /&gt;
&lt;br /&gt;
Context: {context}&lt;br /&gt;
&lt;br /&gt;
Question: {input}&lt;br /&gt;
&lt;br /&gt;
Helpful Answer:&amp;quot;&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
document_prompt = PromptTemplate(&lt;br /&gt;
&lt;br /&gt;
    input_variables=[&amp;quot;page_content&amp;quot;, &amp;quot;source&amp;quot;],&lt;br /&gt;
&lt;br /&gt;
    template=&amp;quot;content:{page_content}\nsource:{source}&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
)&lt;br /&gt;
|}&lt;br /&gt;
8. Соберите все воедино и создайте наш конвейер &amp;#039;&amp;#039;&amp;#039;RAG&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Процесс конвейера выполняет следующие шаги:&lt;br /&gt;
&lt;br /&gt;
# Обращается к &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039; для создания векторного эмбеддинга ввода пользователя.&lt;br /&gt;
# Обращается к &amp;#039;&amp;#039;&amp;#039;Pinecone&amp;#039;&amp;#039;&amp;#039; для поиска релевантных документов на основе полученного векторного эмбеддинга.&lt;br /&gt;
# Обращается к &amp;#039;&amp;#039;&amp;#039;Ollama&amp;#039;&amp;#039;&amp;#039; для генерации ответа туристического консультанта с использованием промпта, содержащего контекст, соответствующий вводу пользователя.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|document_chain = create_stuff_documents_chain(&lt;br /&gt;
&lt;br /&gt;
    llm=llm,&lt;br /&gt;
&lt;br /&gt;
    prompt=prompt,&lt;br /&gt;
&lt;br /&gt;
    document_prompt=document_prompt,&lt;br /&gt;
&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
chain = create_retrieval_chain(retriever, document_chain)&lt;br /&gt;
&lt;br /&gt;
response = chain.invoke({&amp;quot;input&amp;quot;: prompt})&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable mw-collapsible mw-collapsed&amp;quot;&lt;br /&gt;
!Полный пример кода&lt;br /&gt;
|-&lt;br /&gt;
|from langchain_core.prompts import ChatPromptTemplate, PromptTemplate&lt;br /&gt;
&lt;br /&gt;
from langchain_community.document_loaders import BSHTMLLoader&lt;br /&gt;
&lt;br /&gt;
from langchain_community.chat_models import ChatOllama&lt;br /&gt;
&lt;br /&gt;
from langchain_community.embeddings import OllamaEmbeddings&lt;br /&gt;
&lt;br /&gt;
from langchain_text_splitters import RecursiveCharacterTextSplitter&lt;br /&gt;
&lt;br /&gt;
from langchain.chains.combine_documents import create_stuff_documents_chain&lt;br /&gt;
&lt;br /&gt;
from langchain.chains import create_retrieval_chain&lt;br /&gt;
&lt;br /&gt;
from langchain_pinecone import PineconeVectorStore&lt;br /&gt;
&lt;br /&gt;
import logging&lt;br /&gt;
&lt;br /&gt;
import os&lt;br /&gt;
&lt;br /&gt;
from fastapi import FastAPI&lt;br /&gt;
&lt;br /&gt;
from fastapi.staticfiles import StaticFiles&lt;br /&gt;
&lt;br /&gt;
import uvicorn&lt;br /&gt;
&lt;br /&gt;
from opentelemetry import trace&lt;br /&gt;
&lt;br /&gt;
from opentelemetry.sdk.trace import TracerProvider&lt;br /&gt;
&lt;br /&gt;
from opentelemetry.sdk.resources import Resource&lt;br /&gt;
&lt;br /&gt;
from opentelemetry.sdk.trace.export import BatchSpanProcessor&lt;br /&gt;
&lt;br /&gt;
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter&lt;br /&gt;
&lt;br /&gt;
from traceloop.sdk import Traceloop&lt;br /&gt;
&lt;br /&gt;
from traceloop.sdk.decorators import workflow&lt;br /&gt;
&lt;br /&gt;
from telemetry.token_count import TokenUsageCallbackHandler&lt;br /&gt;
&lt;br /&gt;
from telemetry.langchain import LangchainInstrumentor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; Read secrets from the mounted volume&lt;br /&gt;
&lt;br /&gt;
def read_token():&lt;br /&gt;
&lt;br /&gt;
    return read_secret(&amp;#039;token&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
def read_pinecone_key():&lt;br /&gt;
&lt;br /&gt;
    return read_secret(&amp;#039;api-key&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
def read_secret(secret: str):&lt;br /&gt;
&lt;br /&gt;
    try:&lt;br /&gt;
&lt;br /&gt;
        with open(f&amp;quot;/etc/secrets/{secret}&amp;quot;, &amp;quot;r&amp;quot;) as f:&lt;br /&gt;
&lt;br /&gt;
            return f.read().rstrip()&lt;br /&gt;
&lt;br /&gt;
    except Exception as e:&lt;br /&gt;
&lt;br /&gt;
        print(&amp;quot;No token was provided&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        print(e)&lt;br /&gt;
&lt;br /&gt;
        return &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; Expose the PineCone key as env var for initialization by LangChain&lt;br /&gt;
&lt;br /&gt;
os.environ[&amp;#039;PINECONE_API_KEY&amp;#039;] = read_pinecone_key()&lt;br /&gt;
&lt;br /&gt;
OTEL_ENDPOINT = os.environ.get(&amp;quot;OTEL_ENDPOINT&amp;quot;, &amp;quot;&amp;lt;nowiki&amp;gt;http://localhost:4317&amp;lt;/nowiki&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
OLLAMA_ENDPOINT = os.environ.get(&amp;quot;OLLAMA_ENDPOINT&amp;quot;, &amp;quot;&amp;lt;nowiki&amp;gt;http://localhost:11434&amp;lt;/nowiki&amp;gt;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; GLOBALS&lt;br /&gt;
&lt;br /&gt;
AI_MODEL = os.environ.get(&amp;quot;AI_MODEL&amp;quot;, &amp;quot;orca-mini:3b&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
AI_SYSTEM = &amp;quot;ollama&amp;quot;&lt;br /&gt;
&lt;br /&gt;
AI_EMBEDDING_MODEL = os.environ.get(&amp;quot;AI_EMBEDDING_MODEL&amp;quot;, &amp;quot;orca-mini:3b&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
MAX_PROMPT_LENGTH = 50&lt;br /&gt;
&lt;br /&gt;
retrieval_chain = None&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; Initialise the logger&lt;br /&gt;
&lt;br /&gt;
logging.basicConfig(level=logging.INFO, filename=&amp;quot;run.log&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
logger = logging.getLogger(__name__)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; ################&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; # CONFIGURE OPENTELEMETRY&lt;br /&gt;
&lt;br /&gt;
resource = Resource.create({&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;service.name&amp;quot;: &amp;quot;travel-advisor&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;service.version&amp;quot;: &amp;quot;0.1.0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
TOKEN = read_token()&lt;br /&gt;
&lt;br /&gt;
headers = {&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;Authorization&amp;quot;: f&amp;quot;Api-Token {TOKEN}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
provider = TracerProvider(resource=resource)&lt;br /&gt;
&lt;br /&gt;
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint=f&amp;quot;{OTEL_ENDPOINT}&amp;quot;, headers=headers))&lt;br /&gt;
&lt;br /&gt;
provider.add_span_processor(processor)&lt;br /&gt;
&lt;br /&gt;
trace.set_tracer_provider(provider)&lt;br /&gt;
&lt;br /&gt;
otel_tracer = trace.get_tracer(&amp;quot;travel-advisor&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Traceloop.init(app_name=&amp;quot;travel-advisor&amp;quot;, api_endpoint=OTEL_ENDPOINT, disable_batch=True, headers=headers)&lt;br /&gt;
&lt;br /&gt;
def prep_system():&lt;br /&gt;
&lt;br /&gt;
    # Create the embedding&lt;br /&gt;
&lt;br /&gt;
    embeddings = OllamaEmbeddings(model=AI_EMBEDDING_MODEL, base_url=OLLAMA_ENDPOINT)&lt;br /&gt;
&lt;br /&gt;
    # Retrieve the source data&lt;br /&gt;
&lt;br /&gt;
    docs_list = []&lt;br /&gt;
&lt;br /&gt;
    for item in os.listdir(path=&amp;quot;destinations&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
        if item.endswith(&amp;quot;.html&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
            item_docs_list = BSHTMLLoader(file_path=f&amp;quot;destinations/{item}&amp;quot;).load()&lt;br /&gt;
&lt;br /&gt;
            for item in item_docs_list:&lt;br /&gt;
&lt;br /&gt;
                docs_list.append(item)&lt;br /&gt;
&lt;br /&gt;
    # Split Document into tokens&lt;br /&gt;
&lt;br /&gt;
    text_splitter = RecursiveCharacterTextSplitter()&lt;br /&gt;
&lt;br /&gt;
    documents = text_splitter.split_documents(docs_list)&lt;br /&gt;
&lt;br /&gt;
    logger.info(&amp;quot;Loading documents from PineCone...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    vector = PineconeVectorStore.from_documents(&lt;br /&gt;
&lt;br /&gt;
        documents,&lt;br /&gt;
&lt;br /&gt;
        index_name=&amp;quot;travel-advisor&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
        embedding=embeddings&lt;br /&gt;
&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    retriever = vector.as_retriever()&lt;br /&gt;
&lt;br /&gt;
    logger.info(&amp;quot;Initialising Llama LLM...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    llm = ChatOllama(model=AI_MODEL, base_url=OLLAMA_ENDPOINT)&lt;br /&gt;
&lt;br /&gt;
    prompt = ChatPromptTemplate.from_template(&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    1. Use the following pieces of context to answer the question as travel advise at the end.&lt;br /&gt;
&lt;br /&gt;
    2. Keep the answer crisp and limited to 3,4 sentences.&lt;br /&gt;
&lt;br /&gt;
    Context: {context}&lt;br /&gt;
&lt;br /&gt;
    Question: {input}&lt;br /&gt;
&lt;br /&gt;
    Helpful Answer:&amp;quot;&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    document_prompt = PromptTemplate(&lt;br /&gt;
&lt;br /&gt;
        input_variables=[&amp;quot;page_content&amp;quot;, &amp;quot;source&amp;quot;],&lt;br /&gt;
&lt;br /&gt;
        template=&amp;quot;content:{page_content}\nsource:{source}&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    document_chain = create_stuff_documents_chain(&lt;br /&gt;
&lt;br /&gt;
        llm=llm,&lt;br /&gt;
&lt;br /&gt;
        prompt=prompt,&lt;br /&gt;
&lt;br /&gt;
        document_prompt=document_prompt,&lt;br /&gt;
&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    return create_retrieval_chain(retriever, document_chain)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;############&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; CONFIGURE ENDPOINTS&lt;br /&gt;
&lt;br /&gt;
app = FastAPI()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;####################################&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@app.get(&amp;quot;/api/v1/completion&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
def submit_completion(prompt: str):&lt;br /&gt;
&lt;br /&gt;
    with otel_tracer.start_as_current_span(name=&amp;quot;/api/v1/completion&amp;quot;) as span:&lt;br /&gt;
&lt;br /&gt;
        return submit_completion(prompt, span)&lt;br /&gt;
&lt;br /&gt;
@workflow(name=&amp;quot;travelgenerator&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
def submit_completion(prompt: str, span):&lt;br /&gt;
&lt;br /&gt;
        if prompt:&lt;br /&gt;
&lt;br /&gt;
            logger.info(f&amp;quot;Calling RAG to get the answer to the question: {prompt}...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            response = retrieval_chain.invoke({&amp;quot;input&amp;quot;: prompt}, config={&lt;br /&gt;
&lt;br /&gt;
                &amp;quot;callbacks&amp;quot;: [TokenUsageCallbackHandler()],&lt;br /&gt;
&lt;br /&gt;
            })&lt;br /&gt;
&lt;br /&gt;
            # Log information for DQL to grab&lt;br /&gt;
&lt;br /&gt;
            logger.info(f&amp;quot;Response: {response}. Using RAG. model={AI_MODEL}. prompt={prompt}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            return {&amp;quot;message&amp;quot;: response[&amp;#039;answer&amp;#039;]}&lt;br /&gt;
&lt;br /&gt;
        else:  # No, or invalid prompt given&lt;br /&gt;
&lt;br /&gt;
            span.add_event(f&amp;quot;No prompt provided or prompt too long (over {MAX_PROMPT_LENGTH} chars)&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            return {&amp;quot;message&amp;quot;: f&amp;quot;No prompt provided or prompt too long (over {MAX_PROMPT_LENGTH} chars)&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;####################################&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
@app.get(&amp;quot;/api/v1/thumbsUp&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
@otel_tracer.start_as_current_span(&amp;quot;/api/v1/thumbsUp&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
def thumbs_up(prompt: str):&lt;br /&gt;
&lt;br /&gt;
    logger.info(f&amp;quot;Positive user feedback for search term: {prompt}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
@app.get(&amp;quot;/api/v1/thumbsDown&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
@otel_tracer.start_as_current_span(&amp;quot;/api/v1/thumbsDown&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
def thumbs_down(prompt: str):&lt;br /&gt;
&lt;br /&gt;
    logger.info(f&amp;quot;Negative user feedback for search term: {prompt}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    retrieval_chain = prep_system()&lt;br /&gt;
&lt;br /&gt;
    # Mount static files at the root&lt;br /&gt;
&lt;br /&gt;
    app.mount(&amp;quot;/&amp;quot;, StaticFiles(directory=&amp;quot;./public&amp;quot;, html=True), name=&amp;quot;public&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    #app.mount(&amp;quot;/destinations&amp;quot;, StaticFiles(directory=&amp;quot;destinations&amp;quot;, html = True), name=&amp;quot;destinations&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    # Run the app using uvicorn&lt;br /&gt;
&lt;br /&gt;
    uvicorn.run(app, host=&amp;quot;0.0.0.0&amp;quot;, port=8080)&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable mw-collapsible mw-collapsed&amp;quot;&lt;br /&gt;
!Пример манифеста развертки Kubernetes&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;---&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
apiVersion: v1&lt;br /&gt;
&lt;br /&gt;
kind: Namespace&lt;br /&gt;
&lt;br /&gt;
metadata:&lt;br /&gt;
&lt;br /&gt;
  name: travel-advisor&lt;br /&gt;
&lt;br /&gt;
  labels:&lt;br /&gt;
&lt;br /&gt;
    name: travel-advisor&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
apiVersion: apps/v1&lt;br /&gt;
&lt;br /&gt;
kind: Deployment&lt;br /&gt;
&lt;br /&gt;
metadata:&lt;br /&gt;
&lt;br /&gt;
  name: travel-advisor&lt;br /&gt;
&lt;br /&gt;
  namespace: travel-advisor&lt;br /&gt;
&lt;br /&gt;
spec:&lt;br /&gt;
&lt;br /&gt;
  selector:&lt;br /&gt;
&lt;br /&gt;
    matchLabels:&lt;br /&gt;
&lt;br /&gt;
      name: travel-advisor&lt;br /&gt;
&lt;br /&gt;
  template:&lt;br /&gt;
&lt;br /&gt;
    metadata:&lt;br /&gt;
&lt;br /&gt;
      labels:&lt;br /&gt;
&lt;br /&gt;
        name: travel-advisor&lt;br /&gt;
&lt;br /&gt;
    spec:&lt;br /&gt;
&lt;br /&gt;
      containers:&lt;br /&gt;
&lt;br /&gt;
        - name: travel-advisor&lt;br /&gt;
&lt;br /&gt;
          image: travel-advisor:v0.1.3&lt;br /&gt;
&lt;br /&gt;
          ports:&lt;br /&gt;
&lt;br /&gt;
            - name: http&lt;br /&gt;
&lt;br /&gt;
              containerPort: 8080&lt;br /&gt;
&lt;br /&gt;
              protocol: TCP&lt;br /&gt;
&lt;br /&gt;
          env:&lt;br /&gt;
&lt;br /&gt;
            - name: OTEL_ENDPOINT&lt;br /&gt;
&lt;br /&gt;
              value: &amp;quot;https://&amp;lt;YOUR_ENV&amp;gt;.live.astromkey.com/api/v2/otlp&amp;quot;&lt;br /&gt;
&lt;br /&gt;
            - name: OLLAMA_ENDPOINT&lt;br /&gt;
&lt;br /&gt;
              value: &amp;quot;&amp;lt;nowiki&amp;gt;http://ollama.ollama&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
            - name: TRACELOOP_TELEMETRY&lt;br /&gt;
&lt;br /&gt;
              value: &amp;quot;false&amp;quot;&lt;br /&gt;
&lt;br /&gt;
          imagePullPolicy: Always&lt;br /&gt;
&lt;br /&gt;
          volumeMounts:&lt;br /&gt;
&lt;br /&gt;
            - name: secrets&lt;br /&gt;
&lt;br /&gt;
              readOnly: true&lt;br /&gt;
&lt;br /&gt;
              mountPath: &amp;quot;/etc/secrets&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      volumes:&lt;br /&gt;
&lt;br /&gt;
        - name: secrets&lt;br /&gt;
&lt;br /&gt;
          projected:&lt;br /&gt;
&lt;br /&gt;
            sources:&lt;br /&gt;
&lt;br /&gt;
              - secret:&lt;br /&gt;
&lt;br /&gt;
                  name: astromkey&lt;br /&gt;
&lt;br /&gt;
              - secret:&lt;br /&gt;
&lt;br /&gt;
                  name: pinecone&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
apiVersion: v1&lt;br /&gt;
&lt;br /&gt;
kind: Service&lt;br /&gt;
&lt;br /&gt;
metadata:&lt;br /&gt;
&lt;br /&gt;
  name: travel-advisor&lt;br /&gt;
&lt;br /&gt;
  namespace: travel-advisor&lt;br /&gt;
&lt;br /&gt;
spec:&lt;br /&gt;
&lt;br /&gt;
  type: LoadBalancer&lt;br /&gt;
&lt;br /&gt;
  selector:&lt;br /&gt;
&lt;br /&gt;
    name: travel-advisor&lt;br /&gt;
&lt;br /&gt;
  ports:&lt;br /&gt;
&lt;br /&gt;
    - port: 80&lt;br /&gt;
&lt;br /&gt;
      name: http&lt;br /&gt;
&lt;br /&gt;
      targetPort: 8080&lt;br /&gt;
&lt;br /&gt;
      protocol: TCP&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Проанализируйте свой конвейер RAG ===&lt;br /&gt;
В данном примере мы представили упрощённый &amp;#039;&amp;#039;&amp;#039;RAG&amp;#039;&amp;#039;&amp;#039;‑конвейер, однако он уже включает интенсивное взаимодействие с внешними сервисами. Комплексная наблюдаемость (observability) обязательна для контроля производительности, затрат и качества ответов, предоставляемых большой языковой моделью (&amp;#039;&amp;#039;&amp;#039;LLM&amp;#039;&amp;#039;&amp;#039;).&lt;br /&gt;
&lt;br /&gt;
К счастью, нам не требуется вручную инструментировать кодовую базу и собирать ключевые сигналы. Мы можем использовать &amp;#039;&amp;#039;&amp;#039;OpenTelemetry&amp;#039;&amp;#039;&amp;#039; для получения трейсов и метрик — в частности, [https://github.com/traceloop/openllmetry/tree/main OpenLLMetry].&lt;br /&gt;
&lt;br /&gt;
1. Добавьте следующую строку в наш код, и мы сможем использовать возможности Ключ-АСТРОМ для мониторинга наших рабочих нагрузок в области искусственного интеллекта.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|headers = { &amp;quot;Authorization&amp;quot;: &amp;quot;Api-Token &amp;lt;YOUR_DT_API_TOKEN&amp;gt;&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
Traceloop.init(&lt;br /&gt;
&lt;br /&gt;
    app_name=&amp;quot;travel-advisor&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
    api_endpoint=&amp;quot;https://&amp;lt;YOUR_ENV&amp;gt;.live.astromkey.com/api/v2/otlp&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
    disable_batch=True,&lt;br /&gt;
&lt;br /&gt;
    headers=headers&lt;br /&gt;
&lt;br /&gt;
)&lt;br /&gt;
|}&lt;br /&gt;
2. Теперь мы можем просматривать трассировки, описывающие каждый шаг, выполняемый конвейером &amp;#039;&amp;#039;&amp;#039;LangChain&amp;#039;&amp;#039;&amp;#039; &amp;#039;&amp;#039;&amp;#039;RAG&amp;#039;&amp;#039;&amp;#039;, и выявлять узкие места, предлагать улучшения или отслеживать, если сервис больше недоступен.&lt;br /&gt;
&lt;br /&gt;
Однако одной трассировки недостаточно для оценки работоспособности наших AI‑нагрузок. Для этого мы можем настроить дашборд, отображающие ключевые метрики сервисов. Например, можно отслеживать количество входных/выходных токенов, задержку сервисов или настроить &amp;#039;&amp;#039;&amp;#039;SLO&amp;#039;&amp;#039;&amp;#039; (цели уровня обслуживания) при достижении порогового значения потребления токенов.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;OpenTelemetry&amp;#039;&amp;#039;&amp;#039; предлагает [https://github.com/open-telemetry/semantic-conventions/tree/main/docs/gen-ai семантическую конвенцию GenAI (GenAI Semantic Convention)], которую можно использовать для написания &amp;#039;&amp;#039;&amp;#039;DQL&amp;#039;&amp;#039;&amp;#039;‑запросов и визуализации значимых сигналов AI‑нагрузок. Соответствующие атрибуты в этой области начинаются с префикса &amp;lt;code&amp;gt;gen_ai&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Например, мы можем вывести список названий используемых моделей.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|fetch spans&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; summarize models = collectDistinct(gen_ai.request.model)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; expand models&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; sort models&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable mw-collapsible mw-collapsed&amp;quot;&lt;br /&gt;
!Пример оповещения о превышении лимита обслуживания (SLO) на основе потребления токенов&lt;br /&gt;
|-&lt;br /&gt;
|fetch spans&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; filter gen_ai.response.model == &amp;quot;orca-mini:3b&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; makeTimeseries total = max(gen_ai.usage.output_tokens + gen_ai.usage.input_tokens), baseline = avg(gen_ai.usage.output_tokens + gen_ai.usage.input_tokens)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; fieldsAdd sli = (baseline[]/total[])*100&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; fieldsRemove baseline, total&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable mw-collapsible mw-collapsed&amp;quot;&lt;br /&gt;
!Пример построения графика времени отклика для различных типов вызовов LLM&lt;br /&gt;
|-&lt;br /&gt;
|fetch spans&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; filter gen_ai.request.model == &amp;quot;orca-mini:3b&amp;quot; and llm.request.type != &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; fieldsKeep duration, gen_ai.request.model, llm.request.type, end_time&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; makeTimeseries avg(duration), time: end_time, by: {llm.request.type}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; append [&lt;br /&gt;
&lt;br /&gt;
  fetch spans&lt;br /&gt;
&lt;br /&gt;
  | filter gen_ai.request.model == &amp;quot;orca-mini:3b&amp;quot; and llm.request.type != &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  | makeTimeseries requests=count()&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable mw-collapsible mw-collapsed&amp;quot;&lt;br /&gt;
!Пример сопоставления входных данных и подсказок для ответа&lt;br /&gt;
|-&lt;br /&gt;
|fetch spans&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; filter gen_ai.request.model == &amp;quot;orca-mini:3b&amp;quot; and llm.request.type == &amp;quot;chat&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; fieldsAdd prompt = gen_ai.prompt.0.content&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; fieldsAdd response = gen_ai.completion.0.content&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt; fields prompt, response&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>IKuznetsov</name></author>
	</entry>
</feed>