docs: refresh translations for recent English changes (#3379)
This commit is contained in:
parent
d8b638304e
commit
c5d7d0b6d0
1 changed files with 3149 additions and 1047 deletions
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
translation:
|
||||
sections: [e33d441f12d50535, 7099694c603e0f5f, c1df4cf9673433e6, c9cd294541422e6e, 6cec073617bfd037, efa92b8f99e908c8, 6a22a29e27fb4601]
|
||||
sections: [7be05607887e6853, e7375894888d9750, c36f73fc7e3af13b, 2fec2d7e129e62fe, 809b0e0a7c27295a, b4395a04d2a5d906, 1a436007f5f54779, c6b2078ed1e63ba5]
|
||||
tool: 1
|
||||
---
|
||||
# Обробка помилок {#handling-errors}
|
||||
|
||||
Інструмент може завершитися невдачею двома способами, і SDK обробляє їх зовсім по-різному.
|
||||
Інструмент може завершитися невдачею трьома способами, і SDK обробляє кожен по-різному.
|
||||
|
||||
Викиньте звичайний виняток — і його побачить **модель**. Викиньте `MCPError` — і його побачить **протокол**.
|
||||
Викиньте `ToolError` — і ваше повідомлення побачить **модель**. Викиньте `MCPError` — і його побачить **протокол**. Викиньте будь-що інше — і це збій: модель дізнається лише, що виклик не вдався, а трасування потрапить у ваш лог.
|
||||
|
||||
Ця сторінка — про те, як вибрати.
|
||||
|
||||
|
|
@ -15,11 +15,11 @@ translation:
|
|||
|
||||
Візьмімо інструмент, який щось шукає, і нехай пошук нічого не знайде:
|
||||
|
||||
```python title="server.py" hl_lines="11-12"
|
||||
```python title="server.py" hl_lines="2 12-13"
|
||||
--8<-- "docs_src/handling_errors/tutorial001.py"
|
||||
```
|
||||
|
||||
У цих двох рядках немає нічого специфічного для MCP. `get_author` викидає звичайний `ValueError`, як це зробила б будь-яка функція Python.
|
||||
`ToolError` з `mcp.server.mcpserver.exceptions` — це спосіб, яким інструмент повідомляє моделі, що щось пішло не так.
|
||||
|
||||
Викличте його з назвою, якої немає в каталозі, і подивіться на результат:
|
||||
|
||||
|
|
@ -30,13 +30,15 @@ result.structured_content # None
|
|||
```
|
||||
|
||||
* Запит **виконався успішно**. Результат є; на боці того, хто викликав, нічого не викинуто.
|
||||
* `is_error` дорівнює `True`, а повідомлення вашого винятку (з назвою інструмента на початку) лежить у `content` — саме там, де читає модель.
|
||||
* `is_error` дорівнює `True`, а ваше повідомлення (з назвою інструмента на початку) лежить у `content` — саме там, де читає модель.
|
||||
* `structured_content` дорівнює `None`. У невдалого виклику немає значення, яке можна було б структурувати.
|
||||
|
||||
Це **помилка інструмента**, і так за замовчуванням обробляється *будь-який* виняток, який викидає ваш інструмент. І майже завжди це саме те, що потрібно.
|
||||
Це **помилка інструмента**, і майже завжди це саме те, що потрібно.
|
||||
|
||||
Ваш інструмент викликає саме модель. Це вона обрала аргументи. Тож помилка інструмента — це репліка в розмові: модель читає *«No book titled 'Nothing' in the catalog.»*, розуміє, що не вгадала назву, і викликає знову з кращою. Один `raise` — і маєте агента, що сам виправляє свої помилки.
|
||||
|
||||
На сервері `ToolError` — це один рядок рівня `INFO` у лозі, без трасування. Ви цього очікували, тож розслідувати нічого.
|
||||
|
||||
!!! tip
|
||||
Ніколи не повертайте повідомлення про помилку з інструмента через `return`. Повернутий рядок має `is_error=False`, тож для
|
||||
моделі (і для кожного клієнтського інтерфейсу) це виглядає так, ніби інструмент спрацював і цей рядок і є відповіддю.
|
||||
|
|
@ -44,7 +46,7 @@ result.structured_content # None
|
|||
|
||||
## Помилка, яку модель не може виправити {#an-error-the-model-cannot-fix}
|
||||
|
||||
Тепер замініть `ValueError` на `MCPError`.
|
||||
Тепер замініть `ToolError` на `MCPError`.
|
||||
|
||||
```python title="server.py" hl_lines="1 3 14"
|
||||
--8<-- "docs_src/handling_errors/tutorial002.py"
|
||||
|
|
@ -77,10 +79,10 @@ result.structured_content # None
|
|||
|
||||
Ці два шляхи відповідають на два різні запитання.
|
||||
|
||||
* **Викидайте будь-який виняток** у разі збою *виконання*: те, що інструмент намагався зробити, не вдалося. Виклик обрала модель, тож саме модель має побачити наслідок і отримати шанс виправитися. Назва з помилкою, зовнішній API, що не відповів вчасно, рядок, якого не існує, — усе це помилки інструмента.
|
||||
* **Викидайте `ToolError`** у разі збою *виконання*: те, що інструмент намагався зробити, не вдалося. Виклик обрала модель, тож саме модель має побачити наслідок і отримати шанс виправитися. Назва з помилкою, зовнішній API, що не відповів вчасно, рядок, якого не існує, — усе це помилки інструмента.
|
||||
* **Викидайте `MCPError`**, коли слід відхилити *сам запит*: клієнтові бракує можливості, від якої залежить інструмент, сервер не в тому стані, щоб обслуговувати будь-кого, той, хто викликає, пропустив обов'язковий крок. Жодна повторна спроба моделі нічого з цього не виправить, тож передавати їй повідомлення немає сенсу.
|
||||
|
||||
Вирішує одне запитання: **чи могла б розумніша модель цього уникнути?** Так -> звичайний виняток. Ні -> `MCPError`.
|
||||
Вирішує одне запитання: **чи могла б розумніша модель цього уникнути?** Так -> `ToolError`. Ні -> `MCPError`.
|
||||
|
||||
За цим критерієм друга версія `get_author` зробила хибний вибір: краща назва все виправляє, тож модель заслуговувала побачити повідомлення. Ця версія тут, щоб показати механізм, а не щоб його рекомендувати.
|
||||
|
||||
|
|
@ -89,6 +91,25 @@ result.structured_content # None
|
|||
корисне навантаження `data`. Усе, що ви в них покладете, клієнт і отримає: SDK пересилає викинутий
|
||||
`MCPError` дослівно, не очищуючи його.
|
||||
|
||||
## Будь-який інший виняток {#any-other-exception}
|
||||
|
||||
Тепер приберіть перевірку й дайте пошуку в словнику завершитися невдачею самому по собі:
|
||||
|
||||
```python title="server.py" hl_lines="11"
|
||||
--8<-- "docs_src/handling_errors/tutorial004.py"
|
||||
```
|
||||
|
||||
`CATALOG[title]` викидає `KeyError`. Ви його не передбачали, тож SDK вважає це збоєм:
|
||||
|
||||
```python
|
||||
result.is_error # True
|
||||
result.content # [TextContent(text="Error executing tool get_author")]
|
||||
```
|
||||
|
||||
Виклик усе одно повертає `is_error=True`, тож модель знає, що він не вдався, і може рухатися далі. Чого вона не отримує — то це тексту винятку: `KeyError` з вашого коду чи купа SQL від драйвера на три бібліотеки глибше можуть описувати нутрощі вашого сервера, тому за його межі вони ніколи не виходять.
|
||||
|
||||
Натомість їх отримуєте ви. Сервер записує збій у лог на рівні `ERROR` з повним трасуванням як `Tool 'get_author' raised an unexpected exception`. Тож лог робочого середовища на рівні `WARNING` мовчить під час кожної `ToolError` і озивається, щойно щось справді зламалося.
|
||||
|
||||
## Ресурс, якого не існує {#a-resource-that-doesnt-exist}
|
||||
|
||||
Ресурси проводять ту саму межу й мають один іменований виняток для типового випадку.
|
||||
|
|
@ -109,7 +130,7 @@ result.structured_content # None
|
|||
}
|
||||
```
|
||||
|
||||
Зверніть увагу: тут немає напіврезультату з `is_error=True`. Читання ресурсу або повертає вміст, або завершується помилкою: у ресурсів є лише протокольний шлях. Про шаблони й усе інше, що стосується ресурсів, — на сторінці **[Ресурси](resources.md)**.
|
||||
Зверніть увагу: тут немає напіврезультату з `is_error=True`. Читання ресурсу або повертає вміст, або завершується помилкою: у ресурсів є лише протокольний шлях. `ResourceError` — те саме для збою, який не є «не знайдено» (`-32603`, ваше повідомлення), і обидва — це один рядок рівня `INFO` у вашому лозі. Будь-який інший виняток, окрім `MCPError`, — це збій: клієнт отримує `-32603`, де вказано лише URI, а трасування йде у ваш лог на рівні `ERROR`. Про шаблони й усе інше, що стосується ресурсів, — на сторінці **[Ресурси](resources.md)**.
|
||||
|
||||
## Помилки, які ви ніколи не викидаєте {#errors-you-never-raise}
|
||||
|
||||
|
|
@ -120,19 +141,21 @@ result.structured_content # None
|
|||
Це означає цілий клас інструкцій `raise`, які писати не треба: не перевіряйте повторно власні анотації типів.
|
||||
|
||||
!!! info
|
||||
Усе на цій сторінці — те, що бачить **клієнт**, і `Client` у пам'яті, з яким ви писатимете
|
||||
тести, бачить рівно те саме. Навіть `raise_exceptions=True` не перетворює помилку інструмента
|
||||
назад на трасування: до моменту, коли цей прапорець міг би спрацювати, ваш виняток уже став
|
||||
результатом з `is_error=True`. Перевіряйте результат через assert. Цей підхід описано на сторінці **[Тестування](../get-started/testing.md)**.
|
||||
Усе, що на цій сторінці бачить **клієнт**, бачить і `Client` у пам'яті, з яким ви писатимете
|
||||
тести. Навіть `raise_exceptions=True` не повертає виняток інструмента, що впав,
|
||||
тому, хто викликав: до моменту, коли цей прапорець міг би спрацювати, ваш виняток уже став
|
||||
результатом з `is_error=True`. Перевіряйте результат через assert. Якщо потрібне трасування збою, воно
|
||||
в лозі сервера, і `caplog` з pytest його перехоплює. Цей підхід описано на сторінці **[Тестування](../get-started/testing.md)**.
|
||||
|
||||
## Підсумки {#recap}
|
||||
|
||||
* Викиньте **будь-який виняток** в інструменті -> виклик повертає `is_error=True` з вашим повідомленням у `content`. Модель читає його й може повторити спробу. Це поведінка за замовчуванням.
|
||||
* Викиньте **`ToolError`** в інструменті -> виклик повертає `is_error=True` з вашим повідомленням у `content`. Модель читає його й може повторити спробу.
|
||||
* Викиньте **`MCPError`** -> сам виклик завершується помилкою JSON-RPC. Модель нічого не бачить; розбирається хост. `code`, `message` і `data` доходять без змін.
|
||||
* Вирішальне запитання: *чи могла б розумніша модель цього уникнути?* Так -> виняток. Ні -> `MCPError`.
|
||||
* Вирішальне запитання: *чи могла б розумніша модель цього уникнути?* Так -> `ToolError`. Ні -> `MCPError`.
|
||||
* Будь-який **інший виняток** — це збій -> `is_error=True` лише з `Error executing tool <name>` для моделі та запис рівня `ERROR` із трасуванням для вас.
|
||||
* `ResourceNotFoundError` з обробника ресурсу -> протокольний `-32602` з URI в `data`.
|
||||
* Некоректні аргументи відхиляються за схемою ще до запуску вашої функції; для них `raise` не потрібен.
|
||||
* `from mcp import MCPError`; константи кодів помилок — з `mcp.types`.
|
||||
* Імпорти: `from mcp import MCPError`, `from mcp.server.mcpserver.exceptions import ToolError, ResourceError, ResourceNotFoundError` і константи кодів помилок з `mcp.types`.
|
||||
|
||||
З помилками розібралися. Це все, що сервер *надає назовні*. Про те, що кожен обробник може читати і що робити у відповідь клієнтові під час роботи, — наступний розділ: **[Усередині обробника](../handlers/index.md)**.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue