Десять способов устранить галлюцинации без финтюнинга
Циклы закрепления, ограничений, извлечения и оценки, снижающие количество выдуманных фактов в готовых ответах.
В этом руководстве пошагово описывается процесс создания рабочей системы из сырьевых материалов для проекта «10 способов снижения галлюцинаций ИИ без доработки модели». Основное внимание уделяется практическим шагам, четким проверкам и коду, который можно просто добавить в репозиторий без необходимости угадывать его назначение. Для получения обзора необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед внесением изменений в код. Сотрудники должны иметь возможность перезапустить шаг с известной точки контроля, не пытаясь угадать скрытое состояние системы. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение затрат с самого начала помогает избежать неожиданных расходов при переходе от демо-версии к общедоступным средам.
Основная проблема
При работе над «Основной проблемой» сначала запишите условия работы: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает избегать ошибок при последующих изменениях кода. Храните конфигурацию отдельно от кода приложения. Файлы с настройками окружения, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Храните в кэше стабильные инструкции системы и схемы инструментов. Повторная отправка одинаковых данных является распространенной причиной избыточных затрат ресурсов.
const response = await client.responses.create({
model: "gpt-5",
input: `
Where is order #48291?
`
});
console.log(response.output_text);
Customer
↓
AI Agent
↓
Order System
↓
Actual Order State
↓
AI Agent
↓
Response
1. Предоставьте модели лучший контекст
При работе над разделом «1. Дайте модели лучший контекст» сначала запишите контракт: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой чек-лист помогает сохранять честность при последующих изменениях кода. Документируйте одновременно путь успешного выполнения и путь восстановления. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не элементами последующей доработки. Храните в кэше стабильные инструкции системы и схемы инструментов. Пересылка одинаковых заголовков — распространенная причина избыточных ресурсов.
{
"orderId": "48291",
"status": "SHIPPED",
"carrier": "FedEx",
"trackingNumber": "784512963",
"estimatedDelivery": "2026-08-25"
}
const context = {
order: {
id: "48291",
status: "SHIPPED",
carrier: "FedEx",
trackingNumber: "784512963",
estimatedDelivery: "2026-08-25"
}
};
const response = await client.responses.create({
model: "gpt-5",
input: `
Answer the customer using only the supplied order information.
Context:
${JSON.stringify(context, null, 2)}
Customer:
Where is my order #48291?
`
});
Шаблон
При работе с данной схемой сначала запишите условия взаимодействия: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Предпочитайте небольшие, тестируемые модули большим скриптам. Если какой-то шаг не сработает, причина должна быть связана с конкретной функцией, а не с запутанной цепочкой операций. Храните в кэше стабильные инструкции системы и схемы инструментов. Повторная отправка одинаковых данных — распространённая причина избыточных затрат.
Bad:
Customer → LLM → Answer
Better:
Customer
↓
Retrieve state
↓
Build context
↓
LLM
↓
Answer
При работе с данной схемой сначала запишите условия взаимодействия: необходимые входные данные, сигнал о успешном выполнении и действия при частичной неудаче. Такой список помогает сохранять честность при последующих изменениях кода. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды.
2. Сначала получайте данные, затем генерируйте
- Подход «Собрать данные перед генерацией» работает наилучшим образом, если рассматривать его как измеримую величину. Соберите один идеальный пример вывода, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за один ход и за сессию. Инструменты типа агентов активно расширяют объем контекста; жесткие ограничения предотвращают появление неожиданных счетов при демонстрациях.
Customer Question
↓
Retrieve
↓
Rank
↓
Build Context
↓
LLM
↓
Answer
const results = await vectorStore.search({
query: customerQuestion,
topK: 10
});
const relevant = results
.filter(item => item.score > 0.8)
.slice(0, 5);
const context = relevant
.map(item => item.content)
.join("\n\n");
const answer = await generateAnswer(
customerQuestion,
context
);
3. Сокращение шума в контексте
- Метод «Снижение шума контекста» работает наилучшим образом, когда его рассматривают как измеримый показатель. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма задачи. Документируйте одновременно успешный и восстановительный сценарии работы. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не этапом последующей доработки. Установите лимиты на количество токенов за один запрос и за сессию. Инструменты типа агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов при демонстрации функций.
20 retrieved documents
+
15 previous messages
+
10 previous tool responses
+
customer profile
+
product catalog
+
order history
+
promotion metadata
Available Information
↓
Relevance Filtering
↓
Metadata Filtering
↓
Ranking
↓
Deduplication
↓
Context Compression
↓
LLM
const context = results
.filter(x => x.score >= 0.82)
.filter(x => x.metadata.category === "returns")
.filter(x => x.metadata.region === customer.region)
.sort((a, b) => b.score - a.score)
.slice(0, 5)
.map(x => x.content);
4. Использование графа знаний для структурированных данных
- Использование графа знаний для структурированных фактов дает наилучшие результаты, когда его рассматривают как измеримую поверхность. Сначала соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию, прежде чем расширять объем работ. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое какого-либо шага причина должна быть связана с конкретной ответственностью, а не с запутанной цепочкой операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объем контекста; жесткие ограничения помогают избежать неожиданных счетов.
- Использование графа знаний для структурированных фактов дает наилучшие результаты, когда его рассматривают как измеримую поверхность. Сначала соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию, прежде чем расширять объем работ. Записывайте время выполнения операций, а также стоимость токенов или запросов вместе с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-версии к общим средам.
Customer
│
└── PLACED → Order
│
├── CONTAINS → Product
│
├── PAID_BY → Payment
│
├── FULFILLED_BY → Warehouse
│
└── SHIPPED_BY → Carrier
Order #48291
↓
FULFILLED_BY
↓
Warehouse #17
MATCH (o:Order {id: "48291"})
-[:FULFILLED_BY]->
(w:Warehouse)
RETURN w.id, w.name, w.location;
{
"orderId": "48291",
"warehouse": {
"id": "WH-17",
"name": "Delhi Fulfillment Center",
"location": "Delhi"
}
}
Without structured knowledge:
User → LLM
↓
Guess
With Knowledge Graph:
User
↓
Entity Identification
↓
Graph Traversal
↓
Verified Relationship
↓
Context
↓
LLM
5. Ответы с обоснованием на основе доказательств
Для раздела 5 «Ответы с обоснованием на основе доказательств» необходимо заранее определить входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Конфигурацию следует хранить отдельно от кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. При следующем шаге, представляющем собой выполнение кода или вызов инструмента, предпочтительнее использовать структурированные выводы с проверкой схемы вместо свободного текста.
{
"answer": "Your order is being fulfilled by Warehouse WH-17.",
"confidence": 0.98,
"evidence": [
{
"type": "order_record",
"source": "orders_db",
"orderId": "48291"
},
{
"type": "warehouse_relationship",
"source": "knowledge_graph",
"warehouseId": "WH-17"
}
]
}
For every factual claim:
1. Identify supporting evidence.
2. Use only available evidence.
3. Never invent a source.
4. If evidence is unavailable, say so.
5. Clearly distinguish facts from inference.
if (result.confidence < 0.7) {
return escalateToHuman(result);
}
LLM → Answer
LLM
↓
Answer
↓
Evidence
↓
Confidence
↓
Decision
6. Предоставьте агенту инструменты вместо того, чтобы заставлять его догадываться
Для пункта 6. Вместо того чтобы заставлять агента догадываться, предоставьте ему необходимые инструменты: определите входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не пытаясь угадать скрытое состояние. Документируйте как успешный, так и восстановительный пути выполнения. Повторные попытки, проверки человеком и обработка неработоспособных сообщений являются частью продукта, а не последующими улучшениями. Предпочитайте структурированные выходные данные с проверкой по схеме вместо свободного текста, когда следующим шагом является выполнение кода или вызов инструмента.
const tools = [{
name: "get_refund_status",
description: "Retrieve the current refund status for an order",
parameters: {
type: "object",
properties: {
orderId: {
type: "string"
}
},
required: ["orderId"]
}
}];
Customer
↓
LLM
↓
get_refund_status()
↓
Payment System
↓
Actual Refund State
↓
LLM
↓
Customer
7. Проверяйте как входные, так и выходные данные инструментов
Для пункта 7. Проверка входных и выходных данных инструмента: перед изменением кода необходимо определить входные данные, ответственного за выполнение шага и критерии завершения. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Лучше использовать небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое шага он должен указывать на конкретную причину, а не на сложную структуру обработки данных. При следующем шаге, являющемся кодом или вызовом инструмента, предпочтительнее структурированные выходные данные с проверкой соответствия шаблону вместо свободного текста. Для пункта 7. Проверка входных и выходных данных инструмента: перед изменением кода необходимо определить входные данные, ответственного за выполнение шага и критерии завершения. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Рядом с функциональными результатами следует записывать время выполнения и стоимость токенов или запросов. Отображение затрат на раннем этапе предотвращает неожиданные расходы при переходе с демо-среды в общедоступные среды.
{
"orderId": "48291",
"amount": "one hundred",
"currency": "dollars"
}
{
"orderId": "48291",
"amount": 100,
"currency": "USD"
}
import { z } from "zod";
const RefundRequest = z.object({
orderId: z.string(),
amount: z.number().positive(),
currency: z.enum(["USD", "EUR", "GBP", "INR"])
});
const refundRequest = RefundRequest.parse(
modelOutput
);
if (refundRequest.amount > order.total) {
throw new Error(
"Refund amount exceeds order total"
);
}
LLM
↓
Schema Validation
↓
Business Validation
↓
Permission Check
↓
Execute
↓
Response Validation
↓
Accept / Retry / Escalate
8. Разделяйте факты и логику
При работе над пунктом 8. Разделяйте факты и логику сначала запишите условия работы: необходимые входные данные, сигнал успешного выполнения и действия при частичной неудаче. Такой список помогает избегать ошибок при последующих изменениях кода. Храните конфигурацию отдельно от кода приложения. Файлы с настройками окружения, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять без необходимости просмотра всей структуры. Храните в кэше постоянные инструкции системы и схемы инструментов. Повторная отправка одинаковых данных является распространенной причиной избыточных затрат ресурсов.
{
"facts": [
"Order 48291 is shipped",
"Order 48291 is fulfilled by Warehouse WH-17",
"Warehouse WH-17 is currently operating"
],
"reasoning": [
"The order is likely to remain on schedule"
],
"conclusion": "The order is currently expected to arrive on time."
}
Was the fact wrong?
OR
Was the reasoning wrong?
FACT
→ Order shipped
FACT
→ Estimated delivery: Aug 25
INFERENCE
→ Delivery is currently expected on schedule
9. Учитесь на успешных и неудачных запусках
При работе над разделом «9. Учиться на успешных и неудачных попытках выполнения» сначала запишите условия контракта: необходимые входные данные, сигнал успеха и действия при частичной неудаче. Такой список поможет сохранять честность при последующих изменениях кода. Документируйте одновременно путь успешного выполнения и путь восстановления. Повторные попытки, проверки со стороны человека и обработка неработоспособных сообщений являются частью продукта, а не элементами последующей доработки. Храните в кэше стабильные инструкции системы и схемы инструментов. Пересылка одинакового вступительного блока — частая причина избыточных расходов.
{
"orderId": "48291",
"status": "PROCESSING",
"cancelable": true
}
cancel_order(48291)
{
"success": true,
"cancellationId": "CAN-83921"
}
{
"task": "Cancel order",
"orderState": "PROCESSING",
"action": "cancel_order",
"result": "SUCCESS",
"cancellationId": "CAN-83921"
}
New Request
↓
Find Similar Successful Execution
↓
Retrieve Relevant Pattern
↓
Check Current Order State
↓
Generate Action
↓
Validate
↓
Execute
Attempt 1
↓
cancel_order()
↓
Rejected: Order already shipped
↓
Agent retrieves shipping information
↓
Explains cancellation is unavailable
Execute
↓
Observe
↓
Evaluate
↓
Store Experience
↓
Improve Future Context
10. Оценивайте каждую изменение
При работе над пунктом 10 «Оцените каждую изменение» сначала запишите контракт: необходимые входные данные, сигнал о успехе и что происходит при частичной неудаче. Такой чек-лист обеспечивает прозрачность последующих изменений в коде. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. Когда какой-то шаг терпит неудачу, она должна указывать на конкретную ответственность, а не на запутанную цепочку операций. Храните в кэше стабильные инструкции системы и схемы инструментов. Повторная отправка одинакового преамбула — частая причина избыточных затрат. При работе над пунктом 10 «Оцените каждую изменение» сначала запишите контракт: необходимые входные данные, сигнал о успехе и что происходит при частичной неудаче. Такой чек-лист обеспечивает прозрачность последующих изменений в коде. Регистрируйте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-среды к общедоступным средам.
[
{
"question": "Where is order 48291?",
"expected": "SHIPPED"
},
{
"question": "Which warehouse fulfills order 48291?",
"expected": "WH-17"
},
{
"question": "Can order 48291 be cancelled?",
"expected": false
}
]
Answer Accuracy
Groundedness
Retrieval Precision
Tool Selection Accuracy
Tool Success Rate
Task Success Rate
Recovery Rate
Hallucination Rate
Latency
Cost
Before After
Answer Accuracy 72% 95%
Groundedness 69% 97%
Tool Success 81% 98%
Hallucination Rate 17% 3%
Change
↓
Test
↓
Measure
↓
Compare
↓
Improve
Собирание всего воедино
Метод «Собирание всего воедино» работает наилучшим образом, если рассматривать его как измеримую структуру. Сначала соберите один идеальный пример работы, один случай сбоя и записку о возврате к предыдущему состоянию, прежде чем расширять объем работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за раунд и за сессию. Инструменты типа агентов активно расширяют контекст; жесткие ограничения предотвращают появление неожиданных счетов во время демонстраций.
┌──────────────────┐
│ Knowledge Graph │
└────────┬─────────┘
│
┌────────▼─────────┐
│ RAG / Search │
└────────┬─────────┘
│
Customer → Intent → Context Engine → LLM
↑ │
│ ▼
Memory Tool Selection
↑ │
│ ▼
│ Validation
│ │
│ ▼
│ Real Systems
│ │
│ ▼
└─────── Feedback
│
▼
Evaluation
Более важный урок
Метод «Большего урока» работает наилучшим образом, когда его рассматривают как измеримую поверхность. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма задачи. Документируйте одновременно успешный и восстановительный пути выполнения. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не последующими доработками. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; строгие ограничения предотвращают появление неожиданных счетов при демонстрациях.
LLM — это лишь одна часть системы
Книга «LLM — это лишь одна часть системы» работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример транскрипции, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Предпочитайте небольшие, тестируемые единицы вместо обширных скриптов. Когда какой-то шаг терпит неудачу, причина сбоя должна указывать на конкретную ответственность, а не на запутанную цепочку операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объём контекста; строгие ограничения помогают избежать неожиданных счетов. Книга «LLM — это лишь одна часть системы» работает наилучшим образом, когда её рассматривают как измеримую поверхность. Соберите один идеальный пример транскрипции, один случай сбоя и записку о возврате к предыдущему состоянию перед расширением объёма работ. Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-версии к общим средам.
┌───────────────────┐
│ Knowledge + RAG │
└─────────┬─────────┘
↓
Customer → Context → LLM → Tools → Real World
↑ ↓ ↓
Memory Reasoning Validation
↑ ↓
└──── Feedback
↓
Evaluation
Заключение
В заключение определите входные данные, ответственного за выполнение шага и критерии завершения перед изменением кода. Операторы должны иметь возможность перезапустить шаг с известной точки контроля, не догадываясь о скрытом состоянии. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, которое операторы могут проверять, не читая весь граф задач. Предпочитайте структурированные выходные данные с проверкой схемы вместо свободного текста, когда следующим шагом является выполнение кода или вызов инструмента.
Чек-лист операционной деятельности
Чек-лист работает наилучшим образом, когда рассматривается как измеримая структура. Соберите один эталонный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ.
Рассматривайте этот этап как контракт между входными данными и проверенными выходными данными. Дайте названия результатам работы, определите критерии успеха и не допускайте безответственного частичного выполнения задач.
Лимит токенов на ход и за сессию. Инструменты агентного типа активно расширяют контекст; жесткие ограничения предотвращают превращение демо-версий в неожиданные счета.
При наличии бюджетных возможностей добавьте тест на работоспособность, который проверяет критический путь в системе CI с использованием фикстчеров, а не реальных платных API.
Записывайте время выполнения и стоимость токенов или запросов рядом с функциональными результатами. Отслеживание затрат на раннем этапе помогает избежать неожиданных счетов при переходе от демо-версии к общим средам.
Лимит токенов на ход и за сессию. Инструменты агентного типа активно расширяют контекст; жесткие ограничения предотвращают превращение демо-версий в неожиданные счета.
Перед тем как перейти на более сложную стек-технологию, заморозьте версии, сохраните эталонный отчет для критического пути и уточните шаги возврата к предыдущей версии. В общих средах необходимы ограничения на количество запросов, проверки прав доступа и четко определенный ответственный за обновление секретов. Лучше выбирать надежность, чем креативные, но единоразовые демонстрации.
Примечание к пакету d3bfab080c19: не хранить ключи поставщиков в репозитории, установить лимит токенов на сессию и сохранять транскрипции рядом с фиксами для оценки, чтобы последующие замены моделей оставались сопоставимыми.