Паттерны графов
В этом разделе вы найдете примеры паттернов графов агентов sample-ts и ai-disrupt .
Полный агент с инструментами и подсказками
Паттерн из sample-ts : агент с инструментами, циклом вызовов и генерацией подсказок.
__start__ → agent → [tool_calls?] → tools → agent (цикл)
→ [нет tool_calls] → suggests → END
import { StateGraph, MessagesAnnotation, END } from "@langchain/langgraph";
import { ToolNode } from "@langchain/langgraph/prebuilt";
const workflow = new StateGraph(MessagesAnnotation)
.addNode("agent", agentNode)
.addNode("tools", new ToolNode(TOOLS))
.addNode("suggests", suggestNode)
.addEdge("__start__", "agent")
.addConditionalEdges("agent", routeNext, {
tools: "tools",
suggests: "suggests",
})
.addEdge("tools", "agent")
.addEdge("suggests", END);
export const graph = workflow.compile();
Маршрутизация
function routeNext(
state: typeof MessagesAnnotation.State,
): "tools" | "suggests" {
const last = state.messages[state.messages.length - 1] as any;
const hasToolCalls =
(last?.tool_calls && last.tool_calls.length > 0) ||
(last?.additional_kwargs?.function_call);
return hasToolCalls ? "tools" : "suggests";
}
Узел агента
Всегда передавайте config вторым аргументом в invoke() — это обеспечивает корректную работу потоковой передачи токенов и отслеживания (tracing):
async function agentNode(
state: typeof MessagesAnnotation.State,
config: LangGraphRunnableConfig,
) {
const systemPrompt = buildSystemPrompt();
const messages = [new SystemMessage(systemPrompt), ...state.messages];
await ensureFreshToken(llm, TOKEN_MANAGER_OPTS);
const llmWithTools = llm.bind({
tools: GIGACHAT_FUNCTIONS,
tool_choice: "auto",
} as any);
const response = await llmWithTools.invoke(messages, config);
return { messages: [response] };
}
Простой валидатор
Паттерн из ai-disrupt : один узел, без инструментов, structured output.
__start__ → validator → END
const workflow = new StateGraph(MessagesAnnotation)
.addNode("validator", validatorNode)
.addEdge("__start__", "validator")
.addEdge("validator", END);
export const graph = workflow.compile();
Узел валидатора с parsed JSON
Для валидатора отключайте потоковую передачу токенов streaming: false.
В противном случае при обработке JSON-ответов парсер SSE может сломаться на экранированных кавычках:
async function validatorNode(
state: typeof MessagesAnnotation.State,
config: LangGraphRunnableConfig,
) {
const systemPrompt = getSystemPrompt() + STRUCTURED_OUTPUT_INSTRUCTION;
const messagesWithSystem = [new SystemMessage(systemPrompt), ...state.messages];
await ensureFreshToken(gigaChat, TOKEN_MANAGER_OPTS);
const response = await gigaChat.invoke(messagesWithSystem, config);
const responseText = typeof response.content === "string"
? response.content
: JSON.stringify(response.content);
const structuredOutput = parseStructuredOutput(responseText);
return {
messages: [
new AIMessage({
content: structuredOutput.summary,
additional_kwargs: { structuredOutput },
}),
],
};
}
State и типы
Используйте MessagesAnnotation для состояний графа:
import { MessagesAnnotation } from "@langchain/langgraph";
// Тип state в узлах:
state: typeof MessagesAnnotation.State
// Эквивалентно: { messages: BaseMessage[] }
Состояние автоматически аккумулирует сообщения с помощью add_messages.
Обработка ошибок
Если узел выбросит исключение, LangGraph запишет ошибку в checkpoint и вернет ее клиенту через SSE.
async function agentNode(state, config) {
try {
await ensureFreshToken(llm, TOKEN_MANAGER_OPTS);
const response = await llmWithTools.invoke(messages, config);
return { messages: [response] };
} catch (e: any) {
const errMsg = e?.message || String(e);
console.error(`[agent] LLM invoke failed: ${errMsg}`);
throw new Error(`LLM invoke failed: ${errMsg}`);
}
}