### 1. Xử lý LangChain Braces & Dynamic Parameters
Bởi vì LangChain sử dụng cặp ngoặc nhọn `{}` cho biến (variables), nếu trong prompt có `{}` thông thường (như JSON), nó sẽ gây lỗi. Hàm `get_system_prompt_template()` sẽ tự động escape `{}` và chỉ giữ lại biến động `{date_str}`.

```python
def get_system_prompt_template() -> str:
    """Template chưa replace date_str — dùng cho ChatPromptTemplate."""
    raw = _get_system_prompt_raw()
    
    # 1) Re-escape toàn bộ ngoặc nhọn cho LangChain (literal { → {{, } → }})
    escaped = raw.replace("{", "{{").replace("}", "}}")
    
    # 2) Đảo ngược lại chỉ biến {{date_str}} thành {date_str} để LangChain nội suy
    # Sau bước 1, {{date_str}} biến thành {{{{date_str}}}} -> trả về {date_str}
    return escaped.replace("{{{{date_str}}}}", "{date_str}")
```

### 2. MD5 Cache Invalidation ở Graph
Tránh rebuild toàn bộ LangChain nếu prompt không thay đổi.

```python
def _build_chain(self, system_prompt_template: str):
    prompt_hash = hashlib.md5(system_prompt_template.encode()).hexdigest()
    
    # Nếu hash không đổi, dùng lại chain cũ
    if self._cached_chain is not None and self._cached_prompt_hash == prompt_hash:
        return self._cached_chain
        
    logger.info("🔄 Building new chain (prompt hash changed)")
    prompt_template = ChatPromptTemplate.from_messages([
        ("system", system_prompt_template),
        MessagesPlaceholder(variable_name="messages"),
    ])
    
    self._cached_chain = prompt_template | self.llm_with_tools
    self._cached_prompt_hash = prompt_hash
    return self._cached_chain
```