Nhật ký công việc cho nhiệm vụ "Sửa trình dịch"

2 сент. 2026 г., 12:56:09

Это поправил. Проблема была в том, что агент нарушал форматирование в yaml-документе. Текстовый ответ прилетал такой:

en:
  name: |
    Growth in Specialist Productivity Requires Corresponding Development of the Business Technological Environment
description: |
  Business gets the maximum out of new technologies and strong specialists only when its own technological environment allows realizing their productivity.
content: |
  New technologies increase specialist productivity, but this productivity is not realized in a vacuum. 

Тут description и content являлись не вложенностью в en, как name, а уже новыеми разделами. В итоге получалась вот такая конечная структура ответа:

{
  en: {
    name: 'Growth in Specialist Productivity Requires Corresponding Development of the Business Technological Environment\n'
  },
  description: 'Business gets the maximum out of new technologies and strong specialists only when its own technological environment allows realizing their productivity.\n',
  content: 'New technologies increase specialist productivity, but this productivity is not realized in a vacuum.

То есть переведенным у нас тут являлось только название, а все остальное не попадало в обработку.

В итоге сделал две вещи:

1. Вынес в разные сообщения отдельно системный промпт со всеми правилась, а документ для перевода в пользовательское сообщение. При таком подходе логическая структура данных для llm более различима.

2. Усилил правила для форматирования yaml.

Получилось вот так:

const fieldsYaml = fieldsToTranslate
  .map(
    ({ field, value }) =>
      `${field}: |\n${value
        .split('\n')
        .map((line) => '  ' + line)
        .join('\n')}`,
  )
  .join('\n')

const fieldNames = fieldsToTranslate.map((f) => f.field)

const systemPrompt = `You are a professional translator specializing in technical documentation and web content.

# YAML OUTPUT RULES (CRITICAL)

You MUST output valid YAML with this EXACT structure:

\`\`\`
<lang_code>:
<field_name>: |
  <translated text line 1>
  <translated text line 2>
\`\`\`

**STRICT REQUIREMENTS:**
1. Each language code (en, de, etc.) MUST be at the ROOT level (no indentation)
2. Each field (name, description, content) MUST be indented with exactly 2 spaces under its language
3. Field values MUST use the literal block scalar (|) syntax
4. Text content MUST be indented with exactly 4 spaces (2 for field + 2 for content)
5. NEVER put fields at the root level - they MUST always be nested under a language code

# TRANSLATION RULES

1. **Translate, do not transliterate.** Convert meaning, not just letters.
2. Only include fields that were provided in the source.
3. Preserve all markdown and HTML formatting exactly.
4. Exception: Proper nouns, brand names, company names, and product names should be transliterated to Latin script.

# OUTPUT FORMAT

Respond ONLY with valid YAML. No markdown code blocks, no explanations, no comments - just raw YAML.`

const userPrompt = `Translate the following fields from Russian into: ${targetLangs.join(', ')}

## Source fields:

${fieldsYaml}

## Expected output structure:

${targetLangs
.map(
  (lang) =>
    `${lang}:\n${fieldNames.map((f) => `  ${f}: |\n    <translated ${f}>`).join('\n')}`,
)
.join('\n')}`

const chatResponse = await llmChatCompletionResolver(
  null,
  {
    input: {
      provider: LlmProvider.OpenRouter,
      messages: [
        {
          role: LLMChatMessageRole.system,
          content: systemPrompt,
        },
        {
          role: LLMChatMessageRole.user,
          content: userPrompt,
        },
      ],
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      model: LlmModel.GEMINI_3_5_FLASH_LITE as any,
    },
  },
  ctx,
)

const responseContent = chatResponse.choices?.[0]?.message?.content

Справедливости ради стоит отметить, что тут все равно в пользовательское сообщение примешены и технические инструкции, но все равно, работать стало значительно стабильней.

Nhiệm vụ: Sửa trình dịch

02.09.2026