Главная / Статьи / Десять способов устранить галлюцинации без финтюнинга

Десять способов устранить галлюцинации без финтюнинга

Циклы закрепления, ограничений, извлечения и оценки, снижающие количество выдуманных фактов в готовых ответах.

2855 слов

В этом руководстве пошагово описывается процесс создания рабочей системы из сырьевых материалов для проекта «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. Сначала получайте данные, затем генерируйте

  1. Подход «Собрать данные перед генерацией» работает наилучшим образом, если рассматривать его как измеримую величину. Соберите один идеальный пример вывода, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объема работ. Храните конфигурацию вне кода приложения. Файлы среды, хранилища секретов и флаги функций должны находиться в одном месте, чтобы операторы могли их проверять, не читая весь код. Установите лимиты на количество токенов за один ход и за сессию. Инструменты типа агентов активно расширяют объем контекста; жесткие ограничения предотвращают появление неожиданных счетов при демонстрациях.
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. Сокращение шума в контексте

  1. Метод «Снижение шума контекста» работает наилучшим образом, когда его рассматривают как измеримый показатель. Соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию перед расширением объёма задачи. Документируйте одновременно успешный и восстановительный сценарии работы. Повторные попытки, проверки человеком и обработка неработающих сообщений являются частью продукта, а не этапом последующей доработки. Установите лимиты на количество токенов за один запрос и за сессию. Инструменты типа агентов активно расширяют объём контекста; жесткие ограничения предотвращают появление неожиданных счетов при демонстрации функций.
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. Использование графа знаний для структурированных данных

  1. Использование графа знаний для структурированных фактов дает наилучшие результаты, когда его рассматривают как измеримую поверхность. Сначала соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию, прежде чем расширять объем работ. Предпочитайте небольшие, тестируемые единицы кода вместо обширных скриптов. При сбое какого-либо шага причина должна быть связана с конкретной ответственностью, а не с запутанной цепочкой операций. Установите лимиты на количество токенов за один ход и за сессию. Инструменты агентов активно расширяют объем контекста; жесткие ограничения помогают избежать неожиданных счетов.
  2. Использование графа знаний для структурированных фактов дает наилучшие результаты, когда его рассматривают как измеримую поверхность. Сначала соберите один идеальный пример работы, один случай сбоя и запись о возврате к предыдущему состоянию, прежде чем расширять объем работ. Записывайте время выполнения операций, а также стоимость токенов или запросов вместе с функциональными результатами. Отслеживание затрат на раннем этапе предотвращает неожиданные счета при переходе от демо-версии к общим средам.
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: не хранить ключи поставщиков в репозитории, установить лимит токенов на сессию и сохранять транскрипции рядом с фиксами для оценки, чтобы последующие замены моделей оставались сопоставимыми.