---
read_when:
    - คุณกำลังเปลี่ยนการจัดรูปแบบ Markdown หรือการแบ่งชิ้นสำหรับช่องทางขาออก
    - คุณกำลังเพิ่มตัวจัดรูปแบบช่องทางใหม่หรือการแมปสไตล์ใหม่
    - คุณกำลังดีบัก regression ของการจัดรูปแบบข้ามหลายช่องทาง
summary: ไปป์ไลน์การจัดรูปแบบ Markdown สำหรับช่องทางขาออก
title: การจัดรูปแบบ Markdown
x-i18n:
    generated_at: "2026-04-23T05:30:21Z"
    model: gpt-5.4
    provider: openai
    source_hash: f3794674e30e265208d14a986ba9bdc4ba52e0cb69c446094f95ca6c674e4566
    source_path: concepts/markdown-formatting.md
    workflow: 15
---

# การจัดรูปแบบ Markdown

OpenClaw จัดรูปแบบ Markdown ขาออกโดยแปลงเป็นการแทนค่าแบบกลางร่วม (IR)
ก่อนจะเรนเดอร์ผลลัพธ์เฉพาะของแต่ละช่องทาง IR จะเก็บข้อความต้นฉบับไว้เหมือนเดิม พร้อมพกช่วงของสไตล์/ลิงก์ไว้ เพื่อให้การแบ่งชิ้นและการเรนเดอร์
ทำงานได้อย่างสม่ำเสมอข้ามหลายช่องทาง

## เป้าหมาย

- **ความสม่ำเสมอ:** แยกวิเคราะห์หนึ่งครั้ง แล้วเรนเดอร์ได้หลายแบบ
- **การแบ่งชิ้นอย่างปลอดภัย:** แยกข้อความก่อนเรนเดอร์ เพื่อไม่ให้การจัดรูปแบบแบบ inline
  แตกกลางชิ้น
- **ความเหมาะสมกับช่องทาง:** แมป IR เดียวกันไปเป็น Slack mrkdwn, Telegram HTML และ
  ช่วงสไตล์ของ Signal โดยไม่ต้องแยกวิเคราะห์ Markdown ซ้ำ

## ไปป์ไลน์

1. **แยกวิเคราะห์ Markdown -> IR**
   - IR คือข้อความธรรมดาพร้อมช่วงของสไตล์ (bold/italic/strike/code/spoiler) และช่วงลิงก์
   - offsets ใช้หน่วยเป็น UTF-16 code units เพื่อให้ช่วงสไตล์ของ Signal ตรงกับ API ของมัน
   - ตารางจะถูกแยกวิเคราะห์เฉพาะเมื่อช่องทางนั้นเปิดใช้การแปลงตาราง
2. **แบ่งชิ้น IR (จัดรูปแบบก่อน)**
   - การแบ่งชิ้นเกิดขึ้นบนข้อความ IR ก่อนการเรนเดอร์
   - การจัดรูปแบบแบบ inline จะไม่ถูกแบ่งกลางชิ้น; spans จะถูกตัดแยกตามแต่ละชิ้น
3. **เรนเดอร์แยกตามช่องทาง**
   - **Slack:** โทเค็น mrkdwn (bold/italic/strike/code), ลิงก์เป็น `<url|label>`
   - **Telegram:** แท็ก HTML (`<b>`, `<i>`, `<s>`, `<code>`, `<pre><code>`, `<a href>`)
   - **Signal:** ข้อความธรรมดา + ช่วง `text-style`; ลิงก์จะกลายเป็น `label (url)` เมื่อ label ต่างจาก URL

## ตัวอย่าง IR

Markdown ขาเข้า:

```markdown
Hello **world** — see [docs](https://docs.openclaw.ai).
```

IR (เชิงโครงร่าง):

```json
{
  "text": "Hello world — see docs.",
  "styles": [{ "start": 6, "end": 11, "style": "bold" }],
  "links": [{ "start": 19, "end": 23, "href": "https://docs.openclaw.ai" }]
}
```

## ตำแหน่งที่ใช้งาน

- ตัวปรับขาออกของ Slack, Telegram และ Signal เรนเดอร์จาก IR
- ช่องทางอื่นๆ (WhatsApp, iMessage, Microsoft Teams, Discord) ยังคงใช้ข้อความธรรมดาหรือ
  กฎการจัดรูปแบบของตนเอง โดยจะใช้การแปลงตาราง Markdown ก่อน
  การแบ่งชิ้นเมื่อเปิดใช้งาน

## การจัดการตาราง

ตาราง Markdown ไม่ได้รองรับอย่างสม่ำเสมอในไคลเอนต์แชตต่างๆ ใช้
`markdown.tables` เพื่อควบคุมการแปลงแยกตามช่องทาง (และแยกตามบัญชี)

- `code`: เรนเดอร์ตารางเป็น code blocks (ค่าเริ่มต้นสำหรับช่องทางส่วนใหญ่)
- `bullets`: แปลงแต่ละแถวเป็น bullet points (ค่าเริ่มต้นสำหรับ Signal + WhatsApp)
- `off`: ปิดการแยกวิเคราะห์และการแปลงตาราง; ข้อความตารางดิบจะผ่านไปตรงๆ

คีย์การตั้งค่า:

```yaml
channels:
  discord:
    markdown:
      tables: code
    accounts:
      work:
        markdown:
          tables: off
```

## กฎการแบ่งชิ้น

- ขีดจำกัดของชิ้นมาจาก adapters/config ของช่องทาง และจะถูกนำไปใช้กับข้อความ IR
- code fences จะถูกเก็บไว้เป็นบล็อกเดียวพร้อม newline ปิดท้าย เพื่อให้ช่องทางต่างๆ
  เรนเดอร์ได้ถูกต้อง
- คำนำหน้าของลิสต์และบล็อก quote เป็นส่วนหนึ่งของข้อความ IR ดังนั้นการแบ่งชิ้น
  จะไม่ตัดกลางคำนำหน้า
- สไตล์แบบ inline (bold/italic/strike/inline-code/spoiler) จะไม่ถูกตัดข้าม
  ระหว่างชิ้น; ตัวเรนเดอร์จะเปิดสไตล์ใหม่ภายในแต่ละชิ้น

หากคุณต้องการรายละเอียดเพิ่มเติมเกี่ยวกับพฤติกรรมการแบ่งชิ้นข้ามหลายช่องทาง โปรดดู
[Streaming + chunking](/th/concepts/streaming)

## นโยบายลิงก์

- **Slack:** `[label](url)` -> `<url|label>`; URL เปล่าจะคงเป็น URL เปล่า โดยปิดการทำ autolink
  ระหว่างการแยกวิเคราะห์เพื่อหลีกเลี่ยงการลิงก์ซ้ำ
- **Telegram:** `[label](url)` -> `<a href="url">label</a>` (โหมดแยกวิเคราะห์ HTML)
- **Signal:** `[label](url)` -> `label (url)` เว้นแต่ label จะตรงกับ URL

## สปอยเลอร์

เครื่องหมายสปอยเลอร์ (`||spoiler||`) จะถูกแยกวิเคราะห์เฉพาะสำหรับ Signal ซึ่งจะแมปไปยัง
ช่วงสไตล์ SPOILER ช่องทางอื่นจะถือว่าเป็นข้อความธรรมดา

## วิธีเพิ่มหรืออัปเดตตัวจัดรูปแบบช่องทาง

1. **แยกวิเคราะห์ครั้งเดียว:** ใช้ตัวช่วย `markdownToIR(...)` แบบใช้ร่วมกันพร้อมตัวเลือก
   ที่เหมาะกับช่องทางนั้น (autolink, heading style, blockquote prefix)
2. **เรนเดอร์:** สร้าง renderer ด้วย `renderMarkdownWithMarkers(...)` และ
   แผนที่ style marker (หรือช่วงสไตล์ของ Signal)
3. **แบ่งชิ้น:** เรียก `chunkMarkdownIR(...)` ก่อนเรนเดอร์; แล้วเรนเดอร์แต่ละชิ้น
4. **เชื่อม adapter:** อัปเดต outbound adapter ของช่องทางให้ใช้ chunker
   และ renderer ใหม่
5. **ทดสอบ:** เพิ่มหรืออัปเดตการทดสอบรูปแบบ และการทดสอบการส่งขาออก หาก
   ช่องทางนั้นใช้การแบ่งชิ้น

## จุดที่พลาดกันบ่อย

- โทเค็นวงเล็บมุมของ Slack (`<@U123>`, `<#C123>`, `<https://...>`) ต้อง
  ถูกรักษาไว้; ให้ escape raw HTML อย่างปลอดภัย
- HTML ของ Telegram ต้อง escape ข้อความนอกแท็กเพื่อหลีกเลี่ยง markup ที่เสียหาย
- ช่วงสไตล์ของ Signal ขึ้นกับ offsets แบบ UTF-16; อย่าใช้ offsets แบบ code point
- ให้คง newlines ปิดท้ายไว้สำหรับ fenced code blocks เพื่อให้เครื่องหมายปิดอยู่
  ในบรรทัดของตัวเอง
