Nhảy đến nội dung chính

Giới thiệu về ReAct Architecture

Kiến trúc ReAct là một mô hình rất quan trọng trong việc xây dựng các Agent dựa trên LLM. Tên “ReAct” là viết tắt của Reasoning and Acting – tức là kết hợp giữa lập luậnhành động. Đây là cách mà một Agent thông minh có thể thực hiện nhiều bước để hoàn thành một nhiệm vụ, thay vì chỉ trả lời một lần rồi kết thúc.

Giới thiệu về ReAct Architecture

ReAct cho phép các LLM (Large Language Models) hoạt động theo chu trình:

  1. act (hành động)
    Mô hình quyết định gọi một công cụ (tool) để thực hiện một hành động cụ thể. Ví dụ: tìm kiếm thông tin, tính toán, tra dữ liệu từ API, v.v.

  2. observe (quan sát)
    Công cụ thực hiện hành động và trả về kết quả. Kết quả này sẽ được đưa trở lại LLM như một phần của cuộc hội thoại (hoặc “context”).

  3. reason (lập luận)
    LLM tiếp nhận kết quả, phân tích và quyết định bước tiếp theo: có thể gọi thêm một công cụ khác, tiếp tục hỏi người dùng, hoặc kết thúc bằng một câu trả lời.

Ví dụ thực tế

Giả sử bạn hỏi:
"Hôm nay thời tiết ở TP Hồ Chí Minh như thế nào và tôi có nên mang ô không?"

Agent thực hiện:

  • act: Gọi một công cụ thời tiết để lấy dữ liệu thời tiết tại TP Hồ Chí Minh.

  • observe: Nhận được kết quả: "Trời có khả năng mưa vào chiều tối."

  • reason: LLM suy luận: "Trời có thể mưa → nên mang ô → trả lời người dùng."

Trả lời cuối cùng:
"Hôm nay TP Hồ Chí Minh có khả năng mưa vào chiều tối, bạn nên mang theo ô."

Ứng dụng của ReAct

  • Xây dựng multi-step agents: Giải quyết các bài toán phức tạp cần nhiều hành động trung gian.

  • Cho phép Agent có thể tự khám phá, điều chỉnh kế hoạch dựa trên kết quả trung gian.

  • Hữu ích trong các hệ thống như LangGraph, LangChain, nơi bạn cần điều phối nhiều bước và công cụ.

Ví dụ cơ bản

Tạo một agent hỏi người dùng một phép tính, gọi một công cụ để tính, rồi tiếp tục hỏi đến khi người dùng muốn dừng.

Kiến trúc Agent như sau

START
  ↓
LLM (hỏi phép tính)
  ↓
TOOL (tính kết quả)
  ↓
LLM (xem kết quả, hỏi tiếp hay kết thúc?)
  → Nếu tiếp → quay lại TOOL
  → Nếu kết thúc → END

1. Định nghĩa State

from typing import TypedDict, List, Optional

class CalcState(TypedDict):
    history: List[str]
    next_action: Optional[str]
    question: Optional[str]
    answer: Optional[str]

2. Tạo Tool Node

def calculator_tool(state: CalcState) -> CalcState:
    question = state["question"]
    try:
        answer = str(eval(question))  # WARNING: chỉ dùng với ví dụ đơn giản!
    except:
        answer = "Không thể tính được."

    state["answer"] = answer
    state["history"].append(f"Q: {question}\nA: {answer}")
    return state

3. Tạo LLM Node

def llm_node(state: CalcState) -> CalcState:
    print("🧠 LLM: Tôi đang nghĩ...")
    print(f"Câu hỏi: {state.get('question')}")
    print(f"Kết quả: {state.get('answer')}")
    
    # Quyết định bước tiếp theo
    choice = input("Bạn muốn tiếp tục (yes/no)? ")
    if choice.lower() == "no":
        state["next_action"] = "end"
    else:
        new_q = input("Nhập phép tính mới: ")
        state["question"] = new_q
        state["next_action"] = "calculate"
    return state

4. Router

def calc_router(state: CalcState) -> str:
    return state["next_action"]

5. Kết nối các bước bằng LangGraph

from langgraph.graph import StateGraph

builder = StateGraph(CalcState)

builder.add_node("llm_node", llm_node)
builder.add_node("tool_node", calculator_tool)
builder.add_node("router", calc_router)

builder.set_entry_point("llm_node")
builder.add_edge("llm_node", "router")

builder.add_conditional_edges("router", {
    "calculate": "tool_node",
    "end": "__end__"
})

builder.add_edge("tool_node", "llm_node")
graph = builder.compile()

6. Chạy thử

state = {
    "history": [],
    "next_action": None,
    "question": "2 + 3",
    "answer": None,
}

graph.invoke(state)

Output mẫu

LLM: Tôi đang nghĩ...
Câu hỏi: 2 + 3
Kết quả: None
Nhập phép tính mới: 2 + 3
Q: 2 + 3
A: 5
Bạn muốn tiếp tục (yes/no)? yes
Nhập phép tính mới: 10 * 2
...

Tác giả: Đỗ Ngọc Tú
Công Ty Phần Mềm VHTSoft