Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Создайте интеллектуального помощника по управлению персоналом с помощью LangChain.js и служб Azure. Этот агент помогает сотрудникам вымышленной компании NorthWind найти ответы на вопросы о персонале, выполнив поиск по документации компании.
Вы будете использовать поиск ИИ Azure для поиска соответствующих документов и Azure OpenAI для создания точных ответов. Платформа LangChain.js обрабатывает сложность оркестрации агентов, позволяя сосредоточиться на конкретных бизнес-требованиях.
Из этого руководства вы узнаете, как выполнять такие задачи:
- Развертывание ресурсов Azure с помощью Интерфейса командной строки разработчика Azure
- Создание агента LangChain.js, который интегрируется со службами Azure
- Реализация генерации, дополненной извлечением, для поиска документов
- Тестирование и отладка агента локально и в Azure
К концу этого руководства у вас есть рабочий REST API, который отвечает на вопросы отдела кадров с помощью документации вашей компании.
Обзор архитектуры
NorthWind использует два источника данных:
- Документация по персоналу, доступная всем сотрудникам
- Конфиденциальная база данных отдела кадров, содержащая конфиденциальные данные сотрудников.
В этом руководстве основное внимание уделяется созданию агента LangChain.js, который определяет, можно ли ответить на вопрос сотрудника с помощью общедоступных документов отдела кадров. В этом случае агент LangChain.js предоставляет ответ напрямую.
Предпосылки
Чтобы использовать этот пример в Codespace или локальном контейнере разработки, включая сборку и запуск агента LangChain.js, вам потребуется следующее:
- Активная учетная запись Azure. Создайте бесплатную учетную запись, если у вас нет учетной записи.
Если вы запускаете пример кода локально без контейнера разработки, вам также потребуется:
- Node.js LTS установлен в вашей системе.
- TypeScript для написания и компиляции кода TypeScript.
- Интерфейс командной строки разработчика Azure (azd) установлен и настроен.
- LangChain.js библиотеку для создания агента.
- Необязательно: LangSmith для мониторинга использования ИИ. Вам потребуется имя проекта, ключ и конечная точка.
- Необязательно: LangGraph Studio для отладки цепей LangGraph и агентов LangChain.js.
Ресурсы Azure
Требуются следующие ресурсы Azure. В этой статье они создаются с использованием Azure Developer CLI и шаблонов Bicep, а также с применением сертифицированных модулей Azure (AVM). Ресурсы создаются с помощью доступа без пароля и ключа для целей обучения. В этом руководстве используется локальная учетная запись разработчика для проверки подлинности без пароля:
- Управляемое удостоверение для аутентификации без пароля в службах Azure.
- Реестр контейнеров Azure для хранения образа Docker для сервера API Fastify Node.js.
- Приложение-контейнер Azure для размещения сервера API Fastify Node.js.
- Ресурс поиска ИИ Azure для векторного поиска.
-
Ресурс Azure OpenAI со следующими моделями:
- Эмбеддинговая модель, как
text-embedding-3-small. - Большая языковая модель (LLM), как
'gpt-4.1-mini.
- Эмбеддинговая модель, как
Архитектура агента
Фреймворк LangChain.js предоставляет схему принятия решений для создания интеллектуальных агентов в виде LangGraph. В этом руководстве вы создадите агент LangChain.js, который интегрируется с поисковым сервисом Azure AI и Azure OpenAI, чтобы ответить на вопросы, касающиеся отдела кадров. Архитектура агента предназначена для того, чтобы:
- Определите, относится ли вопрос ко всей документации по персоналу, доступной всем сотрудникам.
- Извлеките соответствующие документы из службы "Поиск ИИ Azure" на основе запроса пользователя.
- Используйте Azure OpenAI для создания ответа на основе извлеченных документов и модели LLM.
Ключевые компоненты:
Структура графа: агент LangChain.js представлен в виде графа, где:
- Узлы выполняют определенные задачи, такие как принятие решений или получение данных.
- Ребра определяют поток между узлами, определяя последовательность операций.
Интеграция поиска ИИ Azure:
- Использует модель вложений для создания векторов.
- Вставляет документы кадрового учета (*.md, *.pdf) в векторное хранилище. К документам относятся:
- Сведения о компании
- Справочник по сотрудникам
- Руководство по преимуществам
- Библиотека ролей сотрудника
- Извлекает соответствующие документы на основе запроса пользователя.
-
Интеграция Azure OpenAI:
- Использует большую языковую модель для:
- Определяет, можно ли ответить на вопрос на основании безличных документов отдела кадров.
- Генерирует ответ на основе подсказки, используя контекст из документов и вопрос пользователя.
- Использует большую языковую модель для:
В следующей таблице приведены примеры вопросов пользователей, которые являются и не являются актуальными и на которые можно или нельзя ответить с помощью общих документов о персонале.
| Вопрос | Уместный | Explanation |
|---|---|---|
Does the NorthWind Health Plus plan cover eye exams? |
Да | Документы отдела кадров, такие как руководство сотрудника, должны предоставить ответ. |
How much of my perks + benefits have I spent? |
нет | Этот вопрос требует доступа к конфиденциальным данным сотрудника, который находится вне области действия этого агента. |
Используя фреймворк LangChain.js, вы избегаете написания большей части типового кода для агентов и интеграции с службами Azure, что позволяет вам сосредоточиться на достижении ваших бизнес-целей.
Клонирование примера репозитория кода
В новом каталоге клонируйте пример репозитория кода и перейдите к новому каталогу:
git clone https://github.com/Azure-Samples/azure-typescript-langchainjs.git
cd azure-typescript-langchainjs
В этом примере предоставляется код, который необходим для создания защищенных ресурсов Azure, разработки агента LangChain.js с использованием Azure AI Search и Azure OpenAI, а также для использования агента с сервера API Fastify Node.js.
Проверка подлинности в Azure CLI и Azure Developer CLI
Войдите в Azure с помощью интерфейса командной строки разработчика Azure, создайте ресурсы Azure и разверните исходный код. Так как процесс развертывания использует Azure CLI и Azure Developer CLI, войдите в Azure CLI, а затем настройте интерфейс командной строки разработчика Azure для использования проверки подлинности из Azure CLI:
az login
azd config set auth.useAzCliAuth true
Создание ресурсов и развертывание кода с помощью Интерфейса командной строки разработчика Azure
Запустите процесс развертывания, выполнив azd up команду:
azd up
Во время выполнения команды azd up ответьте на вопросы:
-
Новое имя среды: введите уникальное имя среды, например
langchain-agent. Это имя среды используется в составе группы ресурсов Azure. - Выберите подписку Azure: выберите подписку, в которой создаются ресурсы.
-
Выберите регион: например
eastus2.
Развертывание занимает около 10–15 минут. Интерфейс командной строки разработчика Azure (CLI) организует процесс с помощью этапов и хуков, определенных в файле azure.yaml:
Этап подготовки (эквивалентно azd provision):
- Создает ресурсы Azure, определенные в
infra/main.bicep:- Приложение контейнера Azure
- Открытый ИИ
- Поиск ИИ
- Реестр контейнеров
- Управляемая идентичность
-
Хук после развертывания: проверяет, существует ли уже индекс
northwindпоиска Azure AI- Если индекс не существует: выполняются
npm installиnpm run load_dataдля загрузки документов отдела кадров с помощью загрузчика PDF LangChain.js и интеграции клиента. - Если индекс существует: пропускается загрузка данных, чтобы избежать дублирования (вы можете вручную перезагрузить, удалив индекс или выполнив
npm run load_data) этап развертывания (эквивалентноazd deploy):
- Если индекс не существует: выполняются
- Перехватчик предварительного развертывания: создает образ Docker для сервера API Fastify и отправляет его в реестр контейнеров Azure.
- Развертывание контейнерного сервера API в приложениях контейнеров Azure
После завершения развертывания переменные среды и сведения о ресурсах сохраняются .env в файле в корневом каталоге репозитория. Ресурсы можно просмотреть на портале Azure.
Ресурсы создаются с помощью доступа без пароля и ключа для целей обучения. В этом вводном руководстве используется учетная запись локального разработчика для проверки подлинности без пароля. Для рабочих приложений используйте только проверку подлинности без пароля с управляемыми удостоверениями. Дополнительные сведения о проверке подлинности без пароля.
Используйте пример кода локально
Теперь, когда ресурсы Azure созданы, вы можете запустить агент LangChain.js локально.
Установка зависимостей
Установите пакеты Node.js для этого проекта.
npm installЭта команда устанавливает зависимости, определенные в двух
package.jsonфайлах в каталогеpackages-v1, в том числе:-
./packages-v1/server-api:- Использование Fastify для веб-сервера
-
./packages-v1/langgraph-agent:- LangChain.js для создания агента
- Клиентская библиотека Azure SDK
@azure/search-documentsдля интеграции с ресурсом Azure AI Search. Справочная документация приведена здесь.
-
Создайте два пакета: сервер API и агент ИИ.
npm run buildЭта команда создает связь между двумя пакетами, чтобы сервер API смог вызвать агент ИИ.
Локальное выполнение сервера API
Интерфейс командной строки разработчика Azure создал необходимые ресурсы Azure и настроил переменные среды в корневом .env файле. Эта конфигурация включала в себя крючок после завершения подготовки для загрузки данных в векторное хранилище. Теперь можно запустить сервер API Fastify, на котором размещен агент LangChain.js. Запустите сервер API Fastify.
npm run dev
Сервер запускается и прослушивает порт 3000. Вы можете протестировать сервер, перейдя по адресу [http://localhost:3000] в веб-браузере. Должно появиться приветственное сообщение, указывающее, что сервер запущен.
Использование API для ответов на вопросы
Вы можете использовать средство, например REST Client , или curl отправить запрос POST в /ask конечную точку с текстом JSON, содержащим ваш вопрос.
Запросы REST-клиента доступны в каталоге packages-v1/server-api/http.
Пример с использованием curl:
curl -X POST http://localhost:3000/answer -H "Content-Type: application/json" -d "{\"question\": \"Does the NorthWind Health Plus plan cover eye exams?\"}"
Вы должны получить ответ в формате JSON от агента LangChain.js.
{
"answer": "Yes, the NorthWind Health Plus plan covers eye exams. According to the Employee Handbook, employees enrolled in the Health Plus plan are eligible for annual eye exams as part of their vision benefits."
}
В каталоге packages-v1/server-api/http доступны несколько примеров вопросов. Откройте файлы в Visual Studio Code с помощью клиента REST , чтобы быстро протестировать их.
Общие сведения о коде приложения
В этом разделе объясняется, как агент LangChain.js интегрируется со службами Azure. Приложение репозитория организовано как рабочая область npm с двумя основными пакетами:
Project Root
│
├── packages-v1/
│ │
│ ├── langgraph-agent/ # Core LangGraph agent implementation
│ │ ├── src/
│ │ │ ├── azure/ # Azure service integrations
│ │ │ │ ├── azure-credential.ts # Centralized auth with DefaultAzureCredential
│ │ │ │ ├── embeddings.ts # Azure OpenAI embeddings + PDF loading + rate limiting
│ │ │ │ ├── llm.ts # Azure OpenAI chat completion (key-based & passwordless)
│ │ │ │ └── vector_store.ts # Azure AI Search vector store + indexing + similarity search
│ │ │ │
│ │ │ ├── langchain/ # LangChain agent logic
│ │ │ │ ├── node_get_answer.ts # RAG: retrieves docs + generates answers
│ │ │ │ ├── node_requires_hr_documents.ts # Determines if HR docs needed
│ │ │ │ ├── nodes.ts # LangGraph node definitions + state management
│ │ │ │ └── prompt.ts # System prompts + conversation templates
│ │ │ │
│ │ │ └── scripts/ # Utility scripts
│ │ │ └── load_vector_store.ts # Uploads PDFs to Azure AI Search
│ │ │
│ │ └── data/ # Source documents (PDFs) for vector store
│ │
│ └── server-api/ # Fastify REST API server
│ └── src/
│ └── server.ts # HTTP server with /answer endpoint
│
├── infra/ # Infrastructure as Code
│ └── main.bicep # Azure resources: Container Apps, OpenAI, AI Search, ACR, managed identity
│
├── azure.yaml # Azure Developer CLI config + deployment hooks
├── Dockerfile # Multi-stage Docker build for containerized deployment
└── package.json # Workspace configuration + build scripts
Ключевые архитектурные решения:
- Структура Monorepo: рабочие области npm разрешают общие зависимости и связанные пакеты
-
Разделение проблем: логика агента (
langgraph-agent) не зависит от сервера API (server-api) -
Централизованная проверка подлинности: файлы в
./langgraph-agent/src/azureобрабатывают как проверку подлинности на основе ключей, так и без пароля, а также интеграцию служб Azure
Проверка подлинности в службах Azure
Приложение поддерживает методы проверки подлинности на основе ключей и без пароля, контролируемые переменной SET_PASSWORDLESS среды. API DefaultAzureCredential из библиотеки удостоверений Azure используется для проверки подлинности без пароля, что позволяет приложению легко работать в локальных средах разработки и Azure. Эта проверка подлинности отображается в следующем фрагменте кода:
import { DefaultAzureCredential } from "@azure/identity";
export const CREDENTIAL = new DefaultAzureCredential();
export const SCOPE_OPENAI = "https://cognitiveservices.azure.com/.default";
export async function azureADTokenProvider_OpenAI() {
const tokenResponse = await CREDENTIAL.getToken(SCOPE_OPENAI);
return tokenResponse.token;
}
При использовании сторонних библиотек, таких как LangChain.js или библиотека OpenAI для доступа к Azure OpenAI, требуется функция поставщика маркеров вместо передачи объекта учетных данных напрямую. Функция getBearerTokenProvider из библиотеки удостоверений Azure решает эту проблему путем создания поставщика маркеров, который автоматически извлекает и обновляет маркеры носителя OAuth 2.0 для определенной области ресурсов Azure (например, "https://cognitiveservices.azure.com/.default"). Вы настраиваете область один раз во время установки, а поставщик маркеров автоматически обрабатывает все управление маркерами. Этот подход работает с любой библиотекой идентификации Azure, включая управляемую идентификацию и учетные данные Azure CLI. Хотя библиотеки пакета SDK Azure принимают DefaultAzureCredential напрямую, сторонние библиотеки, такие как LangChain.js, требуют этого шаблона поставщика токенов, чтобы устранить разрыв аутентификации.
Интеграция поиска ИИ Azure
Ресурс поиска ИИ Azure хранит внедренные документы и обеспечивает семантический поиск соответствующего содержимого. Приложение использует LangChain AzureAISearchVectorStore для управления хранилищем векторов без необходимости определять схему индекса.
Хранилище векторов создается с конфигурацией для операций администратора (записи) и запросов (чтения), чтобы загрузка документов и запросы могли использовать разные конфигурации. Это важно, используете ли вы ключи или проверку подлинности без пароля с управляемыми удостоверениями.
Развертывание Интерфейса командной строки разработчика Azure включает в себя крюк пост-развертывания, который отправляет документы в векторное хранилище с LangChain.js загрузчиком PDF и клиентом для встраивания. Этот постразвертывательный хук является последним шагом команды azd up после создания ресурса поиска Azure AI. Скрипт загрузки документов использует пакетную обработку и логику повторных попыток для работы с ограничениями скорости обслуживания.
postdeploy:
posix:
sh: bash
run: |
echo "Checking if vector store data needs to be loaded..."
# Check if already loaded
INDEX_CREATED=$(azd env get-values | grep INDEX_CREATED | cut -d'=' -f2 || echo "false")
if [ "$INDEX_CREATED" = "true" ]; then
echo "Index already created. Skipping data load."
echo "Current document count: $(azd env get-values | grep INDEX_DOCUMENT_COUNT | cut -d'=' -f2)"
else
echo "Loading vector store data..."
npm install
npm run build
npm run load_data
# Get document count from the index
SEARCH_SERVICE=$(azd env get-values | grep AZURE_AISEARCH_ENDPOINT | cut -d'/' -f3 | cut -d'.' -f1)
DOC_COUNT=$(az search index show --service-name $SEARCH_SERVICE --name northwind --query "documentCount" -o tsv 2>/dev/null || echo "0")
# Mark as loaded
azd env set INDEX_CREATED true
azd env set INDEX_DOCUMENT_COUNT $DOC_COUNT
echo "Data loading complete! Indexed $DOC_COUNT documents."
fi
Используйте корневой .env файл, созданный интерфейсом командной строки разработчика Azure, вы можете пройти проверку подлинности в ресурсе поиска ИИ Azure и создать клиент AzureAISearchVectorStore :
const endpoint = process.env.AZURE_AISEARCH_ENDPOINT;
const indexName = process.env.AZURE_AISEARCH_INDEX_NAME;
const adminKey = process.env.AZURE_AISEARCH_ADMIN_KEY;
const queryKey = process.env.AZURE_AISEARCH_QUERY_KEY;
export const QUERY_DOC_COUNT = 3;
const MAX_INSERT_RETRIES = 3;
const shared_admin = {
endpoint,
indexName,
};
export const VECTOR_STORE_ADMIN_KEY: AzureAISearchConfig = {
...shared_admin,
key: adminKey,
};
export const VECTOR_STORE_ADMIN_PASSWORDLESS: AzureAISearchConfig = {
...shared_admin,
credentials: CREDENTIAL,
};
export const VECTOR_STORE_ADMIN_CONFIG: AzureAISearchConfig =
process.env.SET_PASSWORDLESS == "true"
? VECTOR_STORE_ADMIN_PASSWORDLESS
: VECTOR_STORE_ADMIN_KEY;
const shared_query = {
endpoint,
indexName,
search: {
type: AzureAISearchQueryType.Similarity,
},
};
// Key-based config
export const VECTOR_STORE_QUERY_KEY: AzureAISearchConfig = {
key: queryKey,
...shared_query,
};
export const VECTOR_STORE_QUERY_PASSWORDLESS: AzureAISearchConfig = {
credentials: CREDENTIAL,
...shared_query,
};
export const VECTOR_STORE_QUERY_CONFIG =
process.env.SET_PASSWORDLESS == "true"
? VECTOR_STORE_QUERY_PASSWORDLESS
: VECTOR_STORE_QUERY_KEY;
При запросе векторное хранилище преобразует запрос пользователя в внедрение, выполняет поиск документов с аналогичными векторными представлениями и возвращает наиболее релевантные фрагменты.
export function getReadOnlyVectorStore(): AzureAISearchVectorStore {
const embeddings = getEmbeddingClient();
return new AzureAISearchVectorStore(embeddings, VECTOR_STORE_QUERY_CONFIG);
}
export async function getDocsFromVectorStore(
query: string,
): Promise<Document[]> {
const store = getReadOnlyVectorStore();
// @ts-ignore
//return store.similaritySearchWithScore(query, QUERY_DOC_COUNT);
return store.similaritySearch(query, QUERY_DOC_COUNT);
}
Так как хранилище векторов построено на основе LangChain.js, оно абстрагирует сложность непосредственного взаимодействия с хранилищем векторов. После изучения интерфейса векторного хранилища LangChain.js можно легко переключиться на другие реализации хранилища векторов в будущем.
Интеграция Azure OpenAI
Приложение использует Azure OpenAI для встраивания и возможностей большой языковой модели (LLM). Класс AzureOpenAIEmbeddings из LangChain.js используется для создания векторов для документов и запросов. После создания клиента для эмбеддингов LangChain.js использует его для создания эмбеддингов.
Интеграция Azure OpenAI для внедрения
Используйте корневой .env файл, созданный интерфейсом командной строки разработчика Azure, для проверки подлинности в ресурсе Azure OpenAI и создания клиента AzureOpenAIEmbeddings :
const shared = {
azureOpenAIApiInstanceName: instance,
azureOpenAIApiEmbeddingsDeploymentName: model,
azureOpenAIApiVersion: apiVersion,
azureOpenAIBasePath,
dimensions: 1536, // for text-embedding-3-small
batchSize: EMBEDDING_BATCH_SIZE,
maxRetries: 7,
timeout: 60000,
};
export const EMBEDDINGS_KEY_CONFIG = {
azureOpenAIApiKey: key,
...shared,
};
export const EMBEDDINGS_CONFIG_PASSWORDLESS = {
azureADTokenProvider: azureADTokenProvider_OpenAI,
...shared,
};
export const EMBEDDINGS_CONFIG =
process.env.SET_PASSWORDLESS == "true"
? EMBEDDINGS_CONFIG_PASSWORDLESS
: EMBEDDINGS_KEY_CONFIG;
export function getEmbeddingClient(): AzureOpenAIEmbeddings {
return new AzureOpenAIEmbeddings({ ...EMBEDDINGS_CONFIG });
}
Интеграция Azure OpenAI для LLM
Используйте корневой .env файл, созданный интерфейсом командной строки разработчика Azure, для проверки подлинности в ресурсе Azure OpenAI и создания клиента AzureChatOpenAI :
const shared = {
azureOpenAIApiInstanceName: instance,
azureOpenAIApiDeploymentName: model,
azureOpenAIApiVersion: apiVersion,
azureOpenAIBasePath,
maxTokens: maxTokens ? parseInt(maxTokens, 10) : 1000,
maxRetries: 7,
timeout: 60000,
temperature: 0,
};
export const LLM_KEY_CONFIG = {
azureOpenAIApiKey: key,
...shared,
};
export const LLM_CONFIG_PASSWORDLESS = {
azureADTokenProvider: azureADTokenProvider_OpenAI,
...shared,
};
export const LLM_CONFIG =
process.env.SET_PASSWORDLESS == "true"
? LLM_CONFIG_PASSWORDLESS
: LLM_KEY_CONFIG;
Приложение использует AzureChatOpenAI класс из LangChain.js @langchain/openai для взаимодействия с моделями Azure OpenAI.
export const callChatCompletionModel = async (
state: typeof StateAnnotation.State,
_config: RunnableConfig,
): Promise<typeof StateAnnotation.Update> => {
const llm = new AzureChatOpenAI({
...LLM_CONFIG,
});
const completion = await llm.invoke(state.messages);
completion;
return {
messages: [
...state.messages,
{
role: "assistant",
content: completion.content,
},
],
};
};
Рабочий процесс агента LangGraph
Агент использует LangGraph для определения рабочего процесса принятия решений, который определяет, можно ли ответить на вопрос с помощью документов отдела кадров.
Структура графа:
import { StateGraph } from "@langchain/langgraph";
import {
START,
ANSWER_NODE,
DECISION_NODE,
route as endRoute,
StateAnnotation,
} from "./langchain/nodes.js";
import { getAnswer } from "./langchain/node_get_answer.js";
import {
requiresHrResources,
routeRequiresHrResources,
} from "./langchain/node_requires_hr_documents.js";
const builder = new StateGraph(StateAnnotation)
.addNode(DECISION_NODE, requiresHrResources)
.addNode(ANSWER_NODE, getAnswer)
.addEdge(START, DECISION_NODE)
.addConditionalEdges(DECISION_NODE, routeRequiresHrResources)
.addConditionalEdges(ANSWER_NODE, endRoute);
export const hr_documents_answer_graph = builder.compile();
hr_documents_answer_graph.name = "Azure AI Search + Azure OpenAI";
Рабочий процесс состоит из следующих этапов:
- Начало: пользователь отправляет вопрос.
- узел requires_hr_documents: LLM определяет, можно ли ответить на вопрос с использованием общих документов отдела кадров.
-
Условная маршрутизация:
- Если да, переходит к
get_answerузлу. - Если нет, то возвращается сообщение, что вопрос требует персональных данных из отдела кадров.
- Если да, переходит к
- узел get_answer: извлекает документы и создает ответ.
- Конец: возвращает ответ пользователю.
Эта проверка релевантности важна, так как не на все вопросы по персоналу можно ответить, основываясь на общих документах. Личные вопросы, такие как "Сколько PTO у меня есть?", требуют доступа к базам данных сотрудников, содержащим отдельные данные сотрудника. Сначала проверяя релевантность, агент избегает придумывания ответов на вопросы, требующих личной информации, к которой он не имеет доступа.
Определите, требуется ли наличие документов отдела кадров для вопроса.
Узел requires_hr_documents использует LLM, чтобы определить, можно ли ответить на вопрос пользователя с помощью общих документов отдела кадров. Он использует шаблон подсказки, который инструктирует модель реагировать с YES или NO на основе релевантности вопроса. Он возвращает ответ в структурированном сообщении, которое можно передать по рабочему процессу. Следующий узел использует этот ответ для маршрутизации рабочего процесса либо в END, либо в ANSWER_NODE.
// @ts-nocheck
import { getLlmChatClient } from "../azure/llm.js";
import { StateAnnotation } from "../langchain/state.js";
import { RunnableConfig } from "@langchain/core/runnables";
import { BaseMessage } from "@langchain/core/messages";
import { ANSWER_NODE, END } from "./nodes.js";
const PDF_DOCS_REQUIRED = "Answer requires HR PDF docs.";
export async function requiresHrResources(
state: typeof StateAnnotation.State,
_config: RunnableConfig,
): Promise<typeof StateAnnotation.Update> {
const lastUserMessage: BaseMessage = [...state.messages].reverse()[0];
let pdfDocsRequired = false;
if (lastUserMessage && typeof lastUserMessage.content === "string") {
const question = `Does the following question require general company policy information that could be found in HR documents like employee handbooks, benefits overviews, or company-wide policies, then answer yes. Answer no if this requires personal employee-specific information that would require access to an individual's private data, employment records, or personalized benefits details: '${lastUserMessage.content}'. Answer with only "yes" or "no".`;
const llm = getLlmChatClient();
const response = await llm.invoke(question);
const answer = response.content.toLocaleLowerCase().trim();
console.log(`LLM question (is HR PDF documents required): ${question}`);
console.log(`LLM answer (is HR PDF documents required): ${answer}`);
pdfDocsRequired = answer === "yes";
}
// If HR documents (aka vector store) are required, append an assistant message to signal this.
if (!pdfDocsRequired) {
const updatedState = {
messages: [
...state.messages,
{
role: "assistant",
content:
"Not a question for our HR PDF resources. This requires data specific to the asker.",
},
],
};
return updatedState;
} else {
const updatedState = {
messages: [
...state.messages,
{
role: "assistant",
content: `${PDF_DOCS_REQUIRED} You asked: ${lastUserMessage.content}. Let me check.`,
},
],
};
return updatedState;
}
}
export const routeRequiresHrResources = (
state: typeof StateAnnotation.State,
): typeof END | typeof ANSWER_NODE => {
const lastMessage: BaseMessage = [...state.messages].reverse()[0];
if (lastMessage && !lastMessage.content.includes(PDF_DOCS_REQUIRED)) {
console.log("go to end");
return END;
}
console.log("go to llm");
return ANSWER_NODE;
};
Получите необходимые документы по кадровым вопросам
После того как определено, что для вопроса требуются документы отдела кадров, рабочий процесс использует getAnswer для получения соответствующих документов из векторного хранилища, добавляет их в контекст запроса и передает весь запрос в LLM.
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { getLlmChatClient } from "../azure/llm.js";
import { StateAnnotation } from "./nodes.js";
import { AIMessage } from "@langchain/core/messages";
import { getReadOnlyVectorStore } from "../azure/vector_store.js";
const EMPTY_STATE = { messages: [] };
export async function getAnswer(
state: typeof StateAnnotation.State = EMPTY_STATE,
): Promise<typeof StateAnnotation.Update> {
const vectorStore = getReadOnlyVectorStore();
const llm = getLlmChatClient();
// Extract the last user message's content from the state as input
const lastMessage = state.messages[state.messages.length - 1];
const userInput =
lastMessage && typeof lastMessage.content === "string"
? lastMessage.content
: "";
const docs = await vectorStore.similaritySearch(userInput, 3);
if (docs.length === 0) {
const noDocMessage = new AIMessage(
"I'm sorry, I couldn't find any relevant information to answer your question.",
);
return {
messages: [...state.messages, noDocMessage],
};
}
const formattedDocs = docs.map((doc) => doc.pageContent).join("\n\n");
const prompt = ChatPromptTemplate.fromTemplate(`
Use the following context to answer the question:
{context}
Question: {question}
`);
const ragChain = prompt.pipe(llm);
const result = await ragChain.invoke({
context: formattedDocs,
question: userInput,
});
const assistantMessage = new AIMessage(result.text);
return {
messages: [...state.messages, assistantMessage],
};
}
Если соответствующие документы не найдены, агент возвращает сообщение, указывающее, что не удалось найти ответ в документах отдела кадров.
Устранение неполадок
Для любых проблем с процедурой создайте проблему в примере репозитория кода.
Очистите ресурсы
Вы можете удалить группу ресурсов, которая содержит ресурс поиска ИИ Azure и ресурс Azure OpenAI или использовать интерфейс командной строки разработчика Azure для немедленного удаления всех ресурсов, созданных этим руководством.
azd down --purge