SO SÁNH 5 “ĐỨA CON AI” HOT NHẤT 2025

 https://www.facebook.com/AInews2023/posts/pfbid031usNyqqvstcDbFaRptkJmG3ReiTUUmGxGE5fp5PqPKqaseVRqVsoypKNS5CBRzNJl?__cft__[0]=AZUVx56Rvbt3nrEIEA1xSEjoxcgNlEUwLuafs8vTI4zZuN5l163sQ1MIggogP8qxrg5GpPxa2Ci76ftG6oPlfmCkWRjvEuBECFEvdNH9ank3Pm-XDjrjyq8xY-ljedyDA3YZFvVnnWgSdd2UJl-5mGFHSjNY0FU_mTlLhE3HMdwMBYLQOj81gdFtMOwt6R5Q2M8&__tn__=%2CO%2CP-R

🔥 SO SÁNH 5 “ĐỨA CON AI” HOT NHẤT 2025 – ĐỨA NÀO CŨNG NGON, CHỈ KHÁC GU THÔI 🔥
(không có đứa nào thắng tuyệt đối, chỉ có đứa nào hợp với mình thôi =)))
1. Gemini (Google):
�→ Nhân viên Google chính gốc, nghiêm túc, sạch sẽ�→ Làm việc nhóm, Gmail, Docs, Sheets, Drive, chỉnh video, tạo hình thì ĐỈNH CAO�→ Đọc file to bự, video 60 phút nuốt thoải mái�→ Dùng Google hàng ngày thì cứ nhắm mắt chọn nó luôn.
2. ChatGPT (OpenAI):
�→ Thằng bạn thân 10 năm, nói gì cũng hiểu, cái gì cũng làm được�→ Viết content, sáng tác, trò chuyện tự nhiên vẫn là vua�→ Giọng nói mượt, plugin đầy đủ, đa năng thật sự�→ Muốn 1 đứa “biết tuốt” thì đây.
3. Grok (xAI – Elon Musk):
�→ Thằng bạn lầy lội, cà khịa nhẹ, kiểu “đừng có giả tạo”�→ Tin nóng, drama trên X cập nhật nhanh hơn báo lá cải�→ Nói chuyện cười sập sàn, không bao giờ nhàm�→ Nghiện Twitter thì phải nuôi con này.
4. Perplexity:
�→ Ông giáo sư đại học, trả lời câu nào cũng có nguồn, trích dẫn đẹp lung linh�→ Làm luận văn, báo cáo, nghiên cứu thì tin 100%�→ Sinh viên, researcher không thể sống thiếu�→ Đừng hỏi nó viết thơ, nó sẽ cho bạn cả danh sách tài liệu tham khảo =))
5. Claude (Anthropic) :
�→ Anh chàng hiền lành, ấm áp, cẩn thận, sợ làm sai�→ Viết văn dài hơi, cảm xúc thì đang ĐÈ BẸP ChatGPT luôn (nhiều đứa bảo thế)�→ Code sạch nhất làng hiện tại, Claude 3.5 Sonnet đè đầu GPT-4o ở benchmark coding�→ Muốn AI kiểu “người yêu lý tưởng” thì đây.
Tóm cái quần lại cho dễ nhớ:
• Dùng Google Docs/Sheets/Gmail → Gemini
• Viết content, sáng tác, cần cảm xúc → Claude hoặc ChatGPT
• Code sạch, dự án lớn → Claude đang bá
• Nghiện X, thích drama, muốn cười → Grok
• Làm luận văn, cần nguồn rõ ràng → Perplexity
• Lười chọn → xài hết 5 đứa, miễn phí hết mà =))
* Kết luận: Không có AI nào “tốt nhất thế giới”, chỉ có AI “phù hợp nhất với mình” thôi.

Deeply Nested Structure

 

Đây là ví dụ điển hình của sự phức tạp trong văn bản pháp luật (đặc biệt là các Nghị định, Thông tư hướng dẫn về Thuế/Hóa đơn). Cấu trúc này được gọi là Deeply Nested Structure (Cấu trúc lồng ghép sâu).

Nếu bạn chunking hời hợt (chỉ dừng ở a, b), chunk sẽ quá dài và chứa quá nhiều logic (điện, nước, ngân hàng, xăng dầu...) lẫn lộn. Khi người dùng hỏi "Quy định về hóa đơn xăng dầu", hệ thống sẽ trả về cả đoạn về "ngân hàng", làm giảm độ chính xác.

Giải pháp là Chunking theo ngữ nghĩa phân cấp (Semantic Hierarchical Chunking).

1. Chiến lược xử lý: "Breadcrumb Context" (Ngữ cảnh vụn bánh mì)

Chúng ta sẽ cắt nhỏ đến cấp độ Đoạn văn (Paragraph) hoặc Gạch đầu dòng (Bullet), nhưng mỗi mảnh nhỏ đó phải "gánh" trên lưng toàn bộ gia phả của nó.

Công thức cho mỗi Chunk sẽ là:

[Luật] + [Điều] + [Lời dẫn Khoản 3] + [Lời dẫn Điểm a] + [Lời dẫn Tiết a.1] + [Nội dung cụ thể]

2. Code Python xử lý chuyên sâu (Deep Recursive Splitter)

Dưới đây là đoạn code được thiết kế riêng để xử lý cấu trúc: Khoản $\rightarrow$ Điểm (a,b) $\rightarrow$ Tiết (a.1, b.1) $\rightarrow$ Gạch đầu dòng/Đoạn văn.


import re


def clean_text(text):

    return re.sub(r'\s+', ' ', text).strip()


def recursive_legal_chunking(text, metadata_root):

    """

    Hàm đệ quy để đào sâu vào cấu trúc: Khoản -> Điểm -> Tiết -> Ý

    metadata_root: Chứa context cha (Luật, Điều...)

    """

    chunks = []

    

    # 1. Tách các KHOẢN (3. ...)

    # Regex: Bắt đầu dòng, số, dấu chấm, khoảng trắng

    clause_pattern = re.compile(r'(^|\n)(\d+\.\s)', re.MULTILINE)

    clause_splits = list(clause_pattern.finditer(text))

    

    if not clause_splits:

        # Nếu không chia Khoản, trả về text gốc (Base Case)

        return [{"content": text, "metadata": metadata_root}]


    # Duyệt qua từng Khoản

    for i, match in enumerate(clause_splits):

        start = match.start()

        end = clause_splits[i+1].start() if i+1 < len(clause_splits) else len(text)

        clause_full_text = text[start:end].strip()

        

        clause_id = match.group(2).strip().replace(".", "") # Lấy số "3"

        

        # Tách Lời dẫn Khoản (Phần text trước khi bắt đầu điểm a/b)

        # Regex tìm điểm a), b) hoặc a., b.

        point_pattern = re.compile(r'(^|\n)([a-zđ])[\)\.]\s', re.IGNORECASE | re.MULTILINE)

        point_match = point_pattern.search(clause_full_text)

        

        if point_match:

            # Có chia điểm a, b -> Tách context

            clause_header_text = clause_full_text[:point_match.start()].strip()

            clause_body = clause_full_text[point_match.start():]

            

            # Cập nhật Context

            current_context = f"{metadata_root['context']}\n{clause_header_text}"

            

            # --- ĐỆ QUY CẤP 2: XỬ LÝ ĐIỂM (a, b...) ---

            chunks.extend(process_points(clause_body, {

                **metadata_root, 

                "clause_id": clause_id,

                "context": current_context

            }))

        else:

            # Khoản không chia điểm -> Chunk luôn

            full_content = f"{metadata_root['context']}\n{clause_full_text}"

            chunks.append({

                "content": full_content,

                "metadata": {**metadata_root, "clause_id": clause_id, "type": "clause_full"}

            })

            

    return chunks


def process_points(text, metadata_parent):

    """ Xử lý cấp Điểm (a, b, c...) """

    chunks = []

    point_pattern = re.compile(r'(^|\n)([a-zđ])[\)\.]\s', re.IGNORECASE | re.MULTILINE)

    point_splits = list(point_pattern.finditer(text))

    

    for i, match in enumerate(point_splits):

        start = match.start()

        end = point_splits[i+1].start() if i+1 < len(point_splits) else len(text)

        point_full_text = text[start:end].strip()

        point_id = match.group(2) # a, b

        

        # Kiểm tra xem có TIẾT (a.1, a.2) không

        # Regex: a.1), a.1., b.1)

        subpoint_pattern = re.compile(r'(^|\n)([a-zđ]\.\d+)[\)\.]\s', re.IGNORECASE | re.MULTILINE)

        sub_match = subpoint_pattern.search(point_full_text)

        

        if sub_match:

            # Có tiết a.1 -> Tách Header điểm a

            point_header = point_full_text[:sub_match.start()].strip()

            point_body = point_full_text[sub_match.start():]

            

            current_context = f"{metadata_parent['context']}\n{point_header}"

            

            # --- ĐỆ QUY CẤP 3: XỬ LÝ TIẾT (a.1, b.1...) ---

            chunks.extend(process_subpoints(point_body, {

                **metadata_parent,

                "point_id": point_id,

                "context": current_context

            }))

        else:

            # Điểm a thường (không có a.1) -> Cắt theo đoạn văn/gạch đầu dòng

            # Ví dụ: Điểm b trong bài (có đoạn văn)

            point_header_match = match.group(0) # "b) "

            point_content_only = point_full_text.replace(point_header_match.strip(), "", 1).strip()

            

            # Header đầy đủ của điểm b: "b) Doanh nghiệp..."

            # Ở đây ta cần tách câu đầu tiên làm header nếu nó là câu dẫn

            # Tuy nhiên để đơn giản, ta coi toàn bộ điểm b là context nếu nó ngắn, 

            # hoặc tách paragraphs. Ở đây ta gọi hàm tách paragraph.

            

            chunks.extend(split_by_paragraphs(point_content_only, {

                 **metadata_parent,

                 "point_id": point_id,

                 "context": f"{metadata_parent['context']}\n{point_full_text.splitlines()[0]}" # Lấy dòng đầu làm context

            }))


    return chunks


def process_subpoints(text, metadata_parent):

    """ Xử lý cấp Tiết (a.1, a.2...) """

    chunks = []

    # Regex: a.1), a.1.

    sub_pattern = re.compile(r'(^|\n)([a-zđ]\.\d+)[\)\.]\s', re.IGNORECASE | re.MULTILINE)

    sub_splits = list(sub_pattern.finditer(text))

    

    for i, match in enumerate(sub_splits):

        start = match.start()

        end = sub_splits[i+1].start() if i+1 < len(sub_splits) else len(text)

        sub_full_text = text[start:end].strip()

        sub_id = match.group(2) # a.1

        

        # Tách Header của a.1 (Dòng đầu tiên)

        # VD: "a.1) Phương thức... đối với các trường hợp sau:"

        lines = sub_full_text.split('\n')

        sub_header = lines[0].strip()

        sub_body = "\n".join(lines[1:]).strip()

        

        current_context = f"{metadata_parent['context']}\n{sub_header}"

        

        # --- CẤP CUỐI: CẮT THEO GẠCH ĐẦU DÒNG HOẶC ĐOẠN VĂN ---

        chunks.extend(split_by_paragraphs(sub_body, {

            **metadata_parent,

            "subpoint_id": sub_id,

            "context": current_context

        }))

        

    return chunks


def split_by_paragraphs(text, metadata):

    """ Cắt text thành các ý nhỏ (Bullet points hoặc Paragraphs) """

    final_chunks = []

    

    # Tách theo dòng mới

    lines = text.split('\n')

    

    current_buffer = []

    

    for line in lines:

        line = line.strip()

        if not line: continue

        

        # Nếu là gạch đầu dòng "-" hoặc "+" -> Đây là một ý riêng biệt -> Chunk ngay

        if line.startswith("-") or line.startswith("+"):

            # Nếu buffer cũ có nội dung (đoạn văn trước đó), lưu lại trước

            if current_buffer:

                content = " ".join(current_buffer)

                final_chunks.append({

                    "page_content": f"{metadata['context']}\n{content}",

                    "metadata": {**metadata, "type": "paragraph"}

                })

                current_buffer = []

            

            # Chunk gạch đầu dòng này riêng

            final_chunks.append({

                "page_content": f"{metadata['context']}\n{line}",

                "metadata": {**metadata, "type": "bullet"}

            })

        else:

            # Là đoạn văn thường (Ví dụ: "Người bán lập bảng...", "Riêng đối với...")

            # Những đoạn này thường dài và chứa quy định riêng -> Nên tách riêng

            

            # Nếu đoạn văn dài > 20 từ -> Coi là 1 chunk riêng

            if len(line.split()) > 20:

                 if current_buffer: # Flush buffer cũ

                    content = " ".join(current_buffer)

                    final_chunks.append({

                        "page_content": f"{metadata['context']}\n{content}",

                        "metadata": {**metadata, "type": "paragraph"}

                    })

                    current_buffer = []

                 

                 # Chunk đoạn này

                 final_chunks.append({

                    "page_content": f"{metadata['context']}\n{line}",

                    "metadata": {**metadata, "type": "paragraph"}

                 })

            else:

                # Dòng ngắn (có thể là bị ngắt dòng) -> Gom vào buffer

                current_buffer.append(line)

    

    # Flush buffer cuối cùng

    if current_buffer:

        content = " ".join(current_buffer)

        final_chunks.append({

            "page_content": f"{metadata['context']}\n{content}",

            "metadata": {**metadata, "type": "paragraph"}

        })

        

    return final_chunks


# --- DỮ LIỆU ĐẦU VÀO TỪ CÂU HỎI CỦA BẠN ---

input_text = """

3. Chuyển dữ liệu hóa đơn điện tử không có mã... (như bạn cung cấp) ...

... (toàn bộ text bạn đã paste) ...

"""


# Cấu hình Context gốc

root_meta = {

    "law_name": "Nghị định 123/2020/NĐ-CP",

    "article": "Điều 22", # Giả sử

    "context": "Nghị định 123/2020/NĐ-CP\nĐiều 22. Trách nhiệm của người bán"

}


# Chạy hàm

result_chunks = recursive_legal_chunking(input_text, root_meta)


# --- IN KẾT QUẢ ---

print(f"Tạo được: {len(result_chunks)} chunks.\n")

for i, c in enumerate(result_chunks):

    print(f"--- CHUNK {i+1} [{c['metadata'].get('type')}] ---")

    print(c['page_content'])

    print("-" * 20)


3. Kết quả bạn sẽ nhận được (Minh họa)

Nhờ hàm split_by_paragraphs và việc xếp chồng Context, hệ thống sẽ tạo ra các chunks cực kỳ chất lượng như sau.

Chunk A (Quy định về điện nước):

Nội dung: Nghị định 123... Điều 22... 3. Chuyển dữ liệu hóa đơn... (lời dẫn Khoản 3) a) Phương thức và thời điểm... (lời dẫn Điểm a) a.1) Phương thức chuyển dữ liệu... áp dụng đối với các trường hợp sau: (lời dẫn Tiết a.1) - Bán hàng hóa là điện, nước sạch nếu có thông tin về mã khách hàng hoặc mã số thuế của khách hàng.

  • Nhận xét: Khi user search "hóa đơn tiền điện", chunk này khớp 100% và có đủ ngữ cảnh là "chuyển dữ liệu theo bảng tổng hợp" (do nằm trong a.1).

Chunk B (Quy định về Bảng tổng hợp - Đoạn văn riêng):

Nội dung: ... (Context như trên) ... a.1) Phương thức chuyển dữ liệu... Người bán lập Bảng tổng hợp dữ liệu hóa đơn điện tử hàng hóa, cung cấp dịch vụ phát sinh trong tháng hoặc quý... để gửi cơ quan thuế cùng với thời gian gửi Tờ khai thuế...

Chunk C (Quy định đặc thù về Xăng dầu - Đoạn văn riêng):

Nội dung: ... (Context như trên) ... a.1) Phương thức chuyển dữ liệu... Riêng đối với trường hợp bán xăng dầu cho khách hàng thì người bán tổng hợp dữ liệu tất cả các hóa đơn bán xăng dầu trong ngày... và chuyển bảng tổng hợp dữ liệu hóa đơn điện tử này ngay trong ngày.

  • Nhận xét: Đây là chunk "vàng". Nếu bạn không tách đoạn văn này ra, nó sẽ bị trộn lẫn với đoạn "Người bán lập bảng...". Khi user hỏi "Xăng dầu chuyển dữ liệu khi nào?", hệ thống có thể trả lời sai là "theo tháng/quý". Nhưng khi tách riêng chunk này, hệ thống sẽ trả lời đúng là "ngay trong ngày".

4. Tóm tắt kỹ thuật

Với cấu trúc Khoản 3 như trên:

  1. Context Stack (Ngăn xếp ngữ cảnh): Chúng ta đã "bơm" (inject) toàn bộ đường dẫn từ Điều -> Khoản -> Điểm a -> Tiết a.1 vào đầu mỗi đoạn văn con.

  2. Paragraph Splitting (Tách đoạn): Trong a.1, chúng ta không coi cả cụm là 1 khối. Chúng ta coi Mỗi đoạn văn (newline) là một đơn vị kiến thức độc lập nếu nó đủ dài.

  3. Bullets as Entities: Mỗi gạch đầu dòng - được coi là một chunk riêng biệt để đảm bảo sự trong sáng của dữ liệu (Atomicity).

Semantic versioning

 https://docs.n8n.io/release-notes/#how-to-update-n8n

Semantic versioning in n8n#

n8n uses semantic versioning. All version numbers are in the format MAJOR.MINOR.PATCH. Version numbers increment as follows:

  • MAJOR version when making incompatible changes which can require user action.
  • MINOR version when adding functionality in a backward-compatible manner.
  • PATCH version when making backward-compatible bug fixes.

‘Connection lost’ / ‘Invalid origin!’ Error with n8n >= 1.87.0 behind Cloudflare Tunnel

 https://community.n8n.io/t/solved-connection-lost-invalid-origin-error-with-n8n-1-87-0-behind-cloudflare-tunnel/99913/1

The Solution: The solution was to instruct Cloudflare to explicitly set the Origin header to the correct value before the request reaches your tunnel and thus n8n. This was achieved using a Cloudflare Transform Rule:

  1. In the Cloudflare Dashboard, navigate to your domain → Rules → Transform Rules.
  2. Create a “Modify Request Header” rule.
  3. Filter: Hostname equals n8n.example.com
  4. Modification: Set static Header Origin to https://n8n.example.com
  5. Deploy the rule.

After this rule was active, the Origin header was correctly transmitted to n8n, and the Invalid origin! error, along with the ‘Connection lost’ message, disappeared immediately.

I hope this helps others who encounter a similar issue when running n8n behind a Cloudflare Tunnel!

X-Forwarded-For’ header is set but the Express ‘trust proxy’ s

 https://community.n8n.io/t/x-forwarded-for-header-is-set-but-the-express-trust-proxy-s/51208


Can you try setting N8N_PROXY_HOPS to 1 and see if that works.

Renewing Facebook Graph API token automatically?

 

Mã truy cập dài hạn

https://developers.facebook.com/docs/facebook-login/guides/access-tokens/get-long-lived/

https://community.n8n.io/t/renewing-facebook-graph-api-token-automatically/12867/2

Hi @tomato_planet, I am not aware of a way to automate the renewal of your personal token I am afraid.

However, in many cases this shouldn’t be required. Are you using your token to post on a FB page by any chance? If so, you can first send a request to me/accounts like so:

💡 Double-click a node to see its settings, or paste  into n8n to import it

This returns a page-specific token for each page I have access to for me:

This page-specific token does not expire as per Facebook’s token debugger:

Using this new token you should then be able to interact with your page for an extended period of time via the API.

How to use _embed when using _fields?

 https://wordpress.stackexchange.com/questions/363868/how-to-use-embed-when-using-fields

It is not clear in the documentation, but you need to include the "_links" and "_embedded" as fields to be returned. In addition, I include the _embed parameter, as it does not require a value. As of WordPress 5.4, the resources to embed can be limited by passing a list of link relation names to the _embed parameter, though I have not had success with that when using _fields

Example:

domain.com/wp-json/wp/v2/posts?_fields=link,title,featured_media,_links,_embedded&_embed

SO SÁNH 5 “ĐỨA CON AI” HOT NHẤT 2025

 https://www.facebook.com/AInews2023/posts/pfbid031usNyqqvstcDbFaRptkJmG3ReiTUUmGxGE5fp5PqPKqaseVRqVsoypKNS5CBRzNJl?__cft__[0]=AZUVx56Rvbt3n...