Comments 5
Какая LLM позволит дать ответ в точности с переданной JSON схемой?
Так как шаблонизаторы движков open source языковых моделей не очень, я бы рекомендовал вам использовать для этого рекурсивный вызов инструмента с наводящими вопросами.
Доверять параметру enum
так же не стоит, он сериализуется на вход языковой моделе, но не проверяется движком, который запускает gguf
, на своей стороне
import {
addTool,
commitToolOutput,
commitToolOutputForce,
execute,
Schema,
} from "agent-swarm-kit";
import { str, Subject } from "functools-kit";
import { z } from "zod";
import { ToolName } from "src/enum/ToolName";
import commitAppAction from "src/utils/commitAppAction";
import { IPizzaOrder } from "src/model/interfaces";
// См https://deepwiki.com/tripolskypetr/functools-kit/3.2-subject-and-behaviorsubject
const pizzaSubject = new Subject<{ district: string; size: string; clientId: string }>()
// Список районов Москвы
const MOSCOW_DISTRICTS = [
"АРБАТ",
"БАСМАННЫЙ",
"ЗАМОСКВОРЕЧЬЕ",
"КРАСНОГОРСК",
"ПРЕСНЕНСКИЙ",
"ТАГАНСКИЙ",
"ТВЕРСКОЙ",
"ХАМОВНИКИ",
"МЕЩАНСКИЙ",
"ЯКИМАНКА",
];
// Доступные размеры пиццы в сантиметрах
const PIZZA_SIZES = [25, 30, 35, 40];
addTool({
toolName: ToolName.OrderPizzaTool,
type: "function",
call: async ({ toolId, clientId, agentName, params }) => {
const { district, size } = params;
// Проверка наличия района
if (!district) {
await commitToolOutput(
toolId,
"Пожалуйста, укажите район Москвы для доставки пиццы",
clientId,
agentName
);
await execute(`Узнай недостающие данные и вызови инструмент ${ToolName.OrderPizzaTool} еще раз!`, clientId, agentName);
return;
}
// Проверка наличия размера
if (!size) {
await commitToolOutput(
toolId,
"Пожалуйста, укажите размер пиццы в сантиметрах",
clientId,
agentName
);
await execute(`Узнай недостающие данные и вызови инструмент ${ToolName.OrderPizzaTool} еще раз!`, clientId, agentName);
return;
}
// Проверка валидности района
if (!MOSCOW_DISTRICTS.includes(String(district).toUpperCase())) {
await commitToolOutput(
toolId,
str.newline("Доставка возможна только в следующие районы:", MOSCOW_DISTRICTS),
clientId,
agentName
);
await execute(`Попроси пользователя указать верный район для доставки. Как получишь новый район, вызови инструмент ${ToolName.OrderPizzaTool} еще раз`, clientId, agentName);
return;
}
// Проверка валидности размера
if (!PIZZA_SIZES.includes(Number(size))) {
await commitToolOutput(
toolId,
str.newline("Доступны только следующие размеры пиццы (в см):", PIZZA_SIZES),
clientId,
agentName
);
await execute(`Попроси пользователя указать верный размер пиццы. Как получишь новый район, вызови инструмент ${ToolName.OrderPizzaTool} еще раз`, clientId, agentName);
return;
}
// Сохранение данных заказа в памяти для последующих заказов
await Schema.updateSessionMemory(clientId, {
district: district,
size: size,
});
// Логирование параметров заказа
console.log(`Заказ пиццы: Район - ${district}, Размер - ${size} см`);
// Отправка действия для обработки заказа
await pizzaSubject.next({ clientId, district, size })
// Уведомление об успешном оформлении заказа
await commitToolOutput(
toolId,
str.newline(["Заказ пиццы успешно оформлен. Перейди к оплате."]),
clientId,
agentName
);
await execute(`Заказ сформирован успешно. Более не вызывай инструмент ${oolName.OrderPizzaTool}`, clientId, agentName);
},
function: {
name: ToolName.OrderPizzaTool,
description: "Инструмент для заказа пиццы с доставкой по Москве",
parameters: {
type: "object",
properties: {
district: {
type: "string",
description: "Район Москвы для доставки пиццы",
enum: MOSCOW_DISTRICTS,
},
size: {
type: "number",
description: "Размер пиццы в сантиметрах",
enum: PIZZA_SIZES,
},
},
required: ["district", "size"],
},
},
});
Вам потребуется использовать этот код внутри context scope
, чтобы задать отдельный subject
на каждый запрос пользователя. Более подробно по ссылке
посмотрите outlines. ollama его поддерживает из коробки.
про plutus не знал, надо смотреть
ОЧЕНЬ! Вредный совет
Если говнодвижок, в том числа в облаке с оплатой за токены, не может спарсить JSON, он буквально сделает while(true) на ваши деньги!
{"level":30,"time":1751304487079,"pid":17864,"hostname":"DESKTOP-UDO3RQB","logLevel":"log","createdAt":"2025-06-30T17:28:07.079Z","createdBy":"http_predict.log","args":["/predict_1m error",{"request":{"requestId":"16ea422e-33e9-404f-9c42-e330edd2a515","serviceName":"trend-app","symbol":"XRPUSDT"},"error":{"stack":"AI_NoObjectGeneratedError: No object generated: could not parse the response.\n at processResult (file:///C:/Users/User/Documents/GitHub/signals/node_modules/ai/dist/index.mjs:2965:17)\n at fn (file:///C:/Users/User/Documents/GitHub/signals/node_modules/ai/dist/index.mjs:2996:19)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async file:///C:/Users/User/Documents/GitHub/signals/node_modules/ai/dist/index.mjs:470:22\n at async predictCryptoTrend.U.maxExec (file:///C:/Users/User/Documents/GitHub/signals/build/index.mjs:1:24906)\n at async execute (file:///C:/Users/User/Documents/GitHub/signals/node_modules/functools-kit/build/index.mjs:589:16)\n at async InstanceAccessor.wrappedFn [as predictCryptoTrend] (file:///C:/Users/User/Documents/GitHub/signals/node_modules/functools-kit/build/index.mjs:621:13)\n at async file:///C:/Users/User/Documents/GitHub/signals/build/index.mjs:1:327933\n at async dispatch (file:///C:/Users/User/Documents/GitHub/signals/node_modules/hono/dist/compose.js:22:17)\n at async dispatch (file:///C:/Users/User/Documents/GitHub/signals/node_modules/hono/dist/compose.js:22:17)","message":"No object generated: could not parse the response.","name":"AI_NoObjectGeneratedError","cause":{"name":"AI_JSONParseError", ... ,"response":{"id":"07575e7b-03d2-aa75-d762-2f81141fc60e","timestamp":"2025-06-30T17:25:05.000Z","modelId":"grok-3"},"usage":{"promptTokens":1711,"completionTokens":112,"totalTokens":1823},"finishReason":"stop"}}]}
Если кому-то нужно, ещё одна годная модель на 12b
на русском языке. Топология сделана в коллабе Mistral и NVidia, датасет заточен под русский язык
https://huggingface.co/tripolskypetr/Vikhr-Nemo-12B-Instruct
Русскоязычные LLM для вызова инструментов, переводов и финансовой аналитики