エンジン提案API

Max PrilutskiyCEO 兼 共同創業者Updated 先月 · 2 min read

翻訳へのフィードバックが、ダッシュボード上のクリックとして届くことはほとんどありません。実際には、自社のサポートツールにある1行のメモだったり、評価者からのコメントだったり、自社のQAキューに並ぶ1件だったりします。たとえば「製品名は翻訳しない」「ドイツ語では丁寧体を使う」といった内容です。Engine Suggestions APIは、そうした自由記述のテキストを、コードからエンジンの変更に変えます。フィードバックをテキストで送ると、プラットフォームがその内容を読み取り、エンジンの用語集、ルール、またはブランドボイスに反映できる、具体的で構造化された編集案を返します。

これは、ダッシュボード機能に対応するプログラム向けの仕組みです。ダッシュボードでは、AI評価者 が翻訳を低く採点したときに提案が自動生成されますが、こちらではそのシグナルを あなた自身 がテキストで与えます。どちらの場合も出力は同じで、レビューして適用できる保留中の提案が得られます。

流れは大きく2つに分かれます。生成 は非同期です。フィードバックを渡すと、プラットフォームがバックグラウンドで内容を判断し、保留中の提案をエンジン上に作成します。レビュー は同期です。保留中の提案を一覧し、それぞれの提案内容を確認して、適用または却下します。このページではその両方を扱います。ダッシュボードでの体験、つまり低いレビュースコアからの自動生成、Suggestions タブ、通知については、Engine Suggestions を参照してください。

翻訳ではなく、設定を扱うエンドポイント

これらのエンドポイントは、エンジンの設定(用語集、ルール、ブランドボイス)を読み取り、変更します。対象は:idで指定された単一のエンジンに限定され、認証にはAPI全体と同じ、組織スコープのX-API-Keyを使用します。コンテンツを翻訳したり、過去の翻訳を書き換えたりすることはありません。適用した提案は、エンジンによる次回の翻訳から反映されます。

認証

APIキーは X-API-Key ヘッダーで渡します。キーは組織スコープで、組織内のすべてのエンジンにアクセスできます。詳しくは Authentication を、ここにある各エンドポイントで共通のエラーモデルについては Errors and status codes を参照してください。

フィードバックから生成する#

text
POST /engines/:id/suggestions/from-text

エンジンのどこに問題があるのかを、プレーンテキストで送信します。プラットフォームは そのテキスト と現在のエンジン設定をもとに判断し、最小単位の編集案を提案します。エンジンにすでに存在する内容を重ねて提案することはありません。生成は非同期で実行されるため、この呼び出しが返るのは提案の準備完了時ではなく、処理が受け付けられた時点です。

パラメータ説明
id (path)string提案を生成する対象のエンジンです。
textstringエンジンの出力に対する自由記述のフィードバックです。1〜10,000文字で、空白以外の文字を少なくとも1文字含む必要があります。
javascript
const response = await fetch(
  `https://api.lingo.dev/engines/${engineId}/suggestions/from-text`,
  {
    method: "POST",
    headers: {
      "X-API-Key": process.env.LINGO_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      text: "Our German (de-DE) translations keep using the informal 'du'. For our B2B audience they must always use the formal 'Sie'.",
    }),
  },
);

const { enqueued } = await response.json();
console.log(enqueued); // true – generation accepted, running in the background
json
{ "enqueued": true }

enqueued: true が意味するのは、プラットフォームが処理を受け付けたということだけで、まだ提案が存在するとは限りません。生成は1回のバックグラウンド処理で行われ、テキストを読み取り、設定を踏まえて判断し、既存の内容との重複を除外したうえで、提案した内容を保存します。結果として、何も提案されないこともあります。たとえばフィードバックが曖昧だったり、エンジンがすでにその内容をカバーしていたりする場合です。結果を確認するには、少し待ってから エンジンの提案を一覧表示する を実行してください。

空のフィードバックは受け付けられません

text には実際のメッセージが必要です。空文字列や空白だけの文字列は 400 で拒否され、別種のリクエストとして暗黙に扱われることはありません。モデルが実際に判断できる内容を送ってください。

代わりにレビュースコアから生成する

ダッシュボードで使われている低スコアのトリガーは、コードからも利用できます。POST /engines/:id/suggestions/generate(空のボディ)を呼び出すと、テキストではなく、エンジンの最近の低スコアな AI評価 をもとに、プラットフォームが編集案を提案します。レスポンスは同じ { "enqueued": true } で、生成される保留中の提案も同じです。具体的な文章のフィードバックがあるなら from-text を、レビュー担当者がすでに指摘している内容から提案を引き出したいなら generate を使ってください。

保留中の提案を一覧表示する#

text
GET /engines/:id/suggestions

エンジンの提案を返します。対象は、テキストからの生成、手動ボタンによる生成、低いレビュースコアからの自動生成など、あらゆる生成実行の結果です。各エントリには、提案された編集内容とその理由が含まれます。

json
[
  {
    "id": "egs_A1b2C3d4E5f6G7h8",
    "ownerOrganizationId": "org_X1y2Z3a4B5c6D7e8",
    "ownerEngineId": "eng_X1y2Z3a4B5c6D7e8",
    "actionType": "add_instruction",
    "targetKind": "instruction",
    "targetId": null,
    "targetLocale": "de-DE",
    "payload": { "instruction": "Use the formal 'Sie' form in all German translations; never use the informal 'du'." },
    "reasoning": "Feedback states the B2B audience requires formal address, but the engine has no rule enforcing it.",
    "sourceReviewLogIds": [],
    "status": "pending",
    "appliedTargetId": null,
    "createdAt": "2026-06-18T10:30:00.000Z"
  }
]
フィールド説明
idegs_ で始まる提案IDです。これを apply または dismiss に渡します。
actionTypeadd_glossary_itemupdate_glossary_itemadd_instructionupdate_instructionadd_brand_voiceupdate_brand_voice のいずれかです。
targetKindこの編集が作用するエンジン上の対象です。glossary_iteminstruction、または brand_voice のいずれかです。
targetIdupdate_* アクションでは、変更対象エントリの id(gli_ / ins_ / bvc_)です。null アクションでは add_* になります。
targetLocaleこの提案が適用されるロケールです。
payloadそのまま適用できる編集内容です。フィールドは targetKind によって異なりますが、create/update 操作に必要な内容と完全に一致しています。つまり、適用時に追加の入力は不要です。
reasoningこの編集が提案されている理由を簡潔に説明したものです。
sourceReviewLogIdsこの提案のきっかけになった失敗を含むレビューログ(esrl_ id)です。フィードバックテキストから生成された提案では空になります。
statuspendingapplied、または dismissed
appliedTargetId提案の適用後に作成または更新されるエントリです。保留中は null です。

payload があるからこそ、適用は軽く済みます。提案される変更は生成時点で完全に構造化されているため、適用は単なる書き込みであり、AIをもう一度回す処理ではありません。判断するのはあなたであり、プラットフォームが再度推論することはありません。

提案を適用する#

text
POST /engine-suggestions/:id/apply

提案された変更をエンジンに書き込み、その提案をappliedとしてマークします。これは、一覧ですでに確認したpayloadをそのまま確定的に書き込む処理です。2回目のAI呼び出しはないため、確認した内容がそのまま書き込まれます。add_*の提案では、新しい用語集項目、ルール、またはブランドボイスが作成されます。update_*の提案では、targetIdで指定された既存の項目が更新されます。

javascript
const response = await fetch(
  `https://api.lingo.dev/engine-suggestions/${suggestionId}/apply`,
  {
    method: "POST",
    headers: { "X-API-Key": process.env.LINGO_API_KEY },
  },
);

const applied = await response.json();
console.log(applied.status);          // "applied"
console.log(applied.appliedTargetId); // "ins_…" – the rule it just created

レスポンスとして返るのは、applied状態になった提案で、appliedTargetIdは作成または更新された実際のエンジン項目を指すようになります。その項目は、この時点から通常の用語集項目、ルール、またはブランドボイスとして扱えます。ほかの項目と同じように、開いて、編集して、削除できます。

適用で変わるのは設定であり、過去の翻訳ではありません

適用で編集されるのは、あくまでエンジンの設定です。すでに翻訳済みのコンテンツは現在の出力のままで、変更が反映されるのはエンジンが次に翻訳するときです。apply 自体が何かを再ローカライズすることはありません。

提案を却下する#

text
POST /engine-suggestions/:id/dismiss

不要な提案を破棄し、dismissed としてマークします。エンジンには何も変更されません。提案が自社製品に合わないときに使ってください。エンジンはそのままで、その提案は保留中一覧にも表示されなくなります。

javascript
await fetch(
  `https://api.lingo.dev/engine-suggestions/${suggestionId}/dismiss`,
  {
    method: "POST",
    headers: { "X-API-Key": process.env.LINGO_API_KEY },
  },
);
// The suggestion is now "dismissed"; nothing was written to the engine.

一連の流れ#

この4つのエンドポイントで、コードだけですべてを回せる1つのサイクルが完成します。フィードバックを送り、提案内容を確認し、納得した編集だけを反映できます。

1

生成

文章でのフィードバックを使って POST …/suggestions/from-text を呼び出します(または、低いレビュースコアをもとにするなら …/suggestions/generate を使います)。レスポンスとして { "enqueued": true } がすぐ返ります。

2

一覧表示

少し待ってから GET /engines/:id/suggestions を呼び出し、各提案の payloadreasoning を確認しながら、保留中の提案を読みます。

3

適用または却下

編集を反映するなら POST /engine-suggestions/:id/apply、見送るなら …/dismiss を使います。適用した変更は、エンジンの次回の翻訳から反映されます。

次のステップ#