Skip to main content

ChatBaml

Custom LangChain Chat Model tích hợp BAML — bridge giữa LangChain orchestration và BAML structured extraction/function calling.

Demo: React Agent với ChatBaml chạy trên Qwen3-VL-8B-Instruct demo


Mục lục


Cài đặt

git clone https://github.com/thanhhuynhk17/ChatBaml.git
cd ChatBaml

uv venv
source .venv/bin/activate          # Linux/macOS
# source .venv/Scripts/activate    # Windows

uv pip install -e .

# Generate baml_client/ từ baml_src/
uv run baml-cli generate

Cấu hình môi trường

Tạo file .env (xem .env.sample):

# Model config
OPENAI_MODEL_NAME="qwen3-vl"
OPENAI_BASE_URL="http://localhost:8000/v1"
OPENAI_API_KEY="sk-your-key"

# Bắt buộc khi dùng vLLM
DEFAULT_ROLE="user"

# Tắt BAML verbose logging (optional)
BAML_LOG=off

# Bắt buộc cho LangChain content blocks v1
LC_OUTPUT_VERSION="v1"

Kiến trúc

custom_langchain_model/
├── core/
│   ├── registry.py        ← build_client_registry(), get_baml_client()
│   └── logging.py
├── llms/
│   ├── chat_baml.py       ← ChatBaml (BaseChatModel)
│   └── types.py
├── helpers/
│   ├── parse_json_schema.py  ← convert_to_baml_tool()
│   ├── messages.py
│   └── render_agent_wants_to.py
└── extractors/
    └── structured.py      ← extract_structured(), extract_with_pydantic()

baml_src/
├── chat_baml.baml         ← Chat, ChooseTool, ExtractStructure
├── clients.baml
└── generators.baml

react_agent/
├── agent.py
└── tools.py

Nguyên tắc thiết kế:

  • core/registry.py là single source of truth cho BAML authentication — cả ChatBaml lẫn standalone client đều dùng chung.
  • Không cần tạo ChatBaml instance nếu chỉ cần gọi BAML functions trực tiếp.

Sử dụng

1. Standalone BAML Client

Dùng khi muốn gọi BAML functions trực tiếp mà không cần tạo LangChain model instance. Giải quyết vấn đề 401 auth error khi dùng baml_client.b mặc định.

from custom_langchain_model import get_baml_client

# Đọc config từ env vars (OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL_NAME)
b = get_baml_client()

# Override bất kỳ param nào
b = get_baml_client(
    model="gpt-4o",
    api_key="sk-...",
    base_url="http://localhost:8000/v1",
)

# Gọi BAML functions như bình thường
from custom_langchain_model.baml_client.types import BamlState, BaseMessage, ContentBlock

state = BamlState(messages=[
    BaseMessage(role="user", content_block=ContentBlock(text="Hello!"))
])
result = b.Chat(state)
print(result)  # str

2. Pydantic Extraction — extract_with_pydantic()

Trích xuất dữ liệu sử dụng Pydantic Model. Hỗ trợ nested models và truyền description trong Field để điều hướng LLM.

from pydantic import BaseModel, Field
from custom_langchain_model import extract_with_pydantic

class Invoice(BaseModel):
    invoice_number: str = Field(description="Số hóa đơn")
    total_amount: float = Field(description="Tổng tiền")
    customer_name: str = Field(description="Tên khách hàng, hãy viết HOA")

result = extract_with_pydantic(
    input_text="Hóa đơn #INV-2024-001 cho khách Nguyễn Văn A, tổng 5.500.000đ",
    model_class=Invoice,
    client_kwargs={
        "base_url": "http://localhost:8000/v1",
        "api_key": "sk-...",
        "model": "qwen3-vl"
    }
)
print(result.extracted["customer_name"])  # "NGUYỄN VĂN A"

Lưu ý: Sử dụng client_kwargs để override cấu hình client (base_url, api_key, model) thay vì dùng file .env.


3. ChatBaml với LangChain

import os
from dotenv import load_dotenv
from custom_langchain_model import ChatBaml

load_dotenv()

chat = ChatBaml(
    base_url=os.getenv("OPENAI_BASE_URL"),
    api_key=os.getenv("OPENAI_API_KEY"),
    model=os.getenv("OPENAI_MODEL_NAME"),
    temperature=0.7,
    streaming=True,
)

# Basic invoke
from langchain_core.messages import HumanMessage, SystemMessage
response = chat.invoke([
    SystemMessage(content="Bạn là trợ lý hữu ích."),
    HumanMessage(content="2 + 2 bằng mấy?"),
])
print(response.content)

# Streaming
for chunk in chat.stream([HumanMessage(content="Kể tên 3 thủ đô châu Á.")]):
    print(chunk.content, end="", flush=True)

Bind tools

from pydantic import BaseModel, Field
from custom_langchain_model import ChatBaml

class SearchWeb(BaseModel):
    """Tìm kiếm thông tin trên internet."""
    query: str = Field(description="Từ khóa tìm kiếm")

class Calculator(BaseModel):
    """Tính toán biểu thức số học."""
    expression: str = Field(description="Biểu thức cần tính, ví dụ: '2 + 3 * 4'")

chat = ChatBaml(model="qwen3-vl", streaming=True)
chat_with_tools = chat.bind_tools([SearchWeb, Calculator])

response = chat_with_tools.invoke([
    HumanMessage(content="Tìm kiếm về LangChain trên internet")
])

if response.tool_calls:
    tool_call = response.tool_calls[0]
    print(f"Tool: {tool_call['name']}")
    print(f"Args: {tool_call['args']}")

4. React Agent

# Chạy LangGraph dev server
langgraph dev

# Hoặc F5 trong VSCode (cần .vscode/launch.json)
# react_agent/agent.py
from langchain.agents import create_agent
from custom_langchain_model import ChatBaml
from react_agent.tools import add, multiply
from langchain_community.tools import DuckDuckGoSearchRun

chat_baml = ChatBaml(
    base_url=os.getenv("OPENAI_BASE_URL"),
    api_key=os.getenv("OPENAI_API_KEY"),
    model=os.getenv("OPENAI_MODEL_NAME"),
    streaming=True,
    temperature=0.7,
)

agent = create_agent(
    chat_baml,
    tools=[add, multiply, DuckDuckGoSearchRun()],
    system_prompt="You are a helpful assistant with math and search tools.",
)

5. Tool Definition

Pydantic BaseModel (recommended)

from pydantic import BaseModel, Field

class AddTool(BaseModel):
    """Cộng hai số nguyên."""
    a: int = Field(..., description="Số thứ nhất")
    b: int = Field(..., description="Số thứ hai")

class SearchTool(BaseModel):
    """Tìm kiếm thông tin."""
    query: str = Field(..., description="Từ khóa tìm kiếm")
    max_results: int = Field(default=5, description="Số kết quả tối đa")

LangChain @tool (cần parse_docstring=True)

from langchain.tools import tool

@tool(parse_docstring=True)
def get_weather(city: str, unit: str = "celsius") -> str:
    """Lấy thông tin thời tiết hiện tại của một thành phố.

    Args:
        city (str): Tên thành phố.
        unit (str): Đơn vị nhiệt độ, "celsius" hoặc "fahrenheit".

    Returns:
        str: Thông tin thời tiết dạng text.
    """
    return f"Thời tiết tại {city}: 28°C, nhiều mây"

Lưu ý: @tool phải có docstring đầy đủ Args: và Returns: sections. Thiếu sẽ gây lỗi khi convert sang BAML schema.


BAML Functions

Function Input Output Dùng khi
Chat BamlState string Chat thông thường, không có tools
ChooseTool BamlState + TypeBuilder string | DynamicSchema Agent cần chọn và gọi tools
ExtractStructure system_instruction?, prefix?, input DynamicSchema Trích xuất structured data từ text

ExtractStructure chi tiết

function ExtractStructure(
    system_instruction: string?,   // null → dùng default instruction
    prefix: string?,               // null → không có prefix trong output format
    input: string                  // text cần extract (bắt buộc)
) -> DynamicSchema

Cách BAML render prompt:

  • system_instruction | default(...) → fallback về default nếu null
  • {% if prefix %} → chỉ thêm prefix vào ctx.output_format khi có giá trị
  • DynamicSchema được define lúc runtime qua TypeBuilder (truyền vào baml_options={"tb": tb})

API Reference

get_baml_client(*, model, api_key, base_url, **kwargs)

Trả về BAML client đã authenticated. Không cần tạo ChatBaml.

from custom_langchain_model import get_baml_client
b = get_baml_client()

extract_with_pydantic(input_text, model_class, client_kwargs=None, ...)

Extraction với Pydantic model làm schema. Hỗ trợ client_kwargs để cấu hình client.

from custom_langchain_model import extract_with_pydantic
result = extract_with_pydantic("text...", MyModel, client_kwargs={"model": "gpt-4o"})

ChatBaml

LangChain BaseChatModel backed by BAML. Hỗ trợ .invoke(), .stream(), .bind_tools().

from custom_langchain_model import ChatBaml
chat = ChatBaml(model="qwen3-vl", streaming=True)

References

Metadata

Release files for custom-langchain-model 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for custom-langchain-model 0.2.0
File Size Uploaded
custom_langchain_model-0.2.0.tar.gz 40.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for custom-langchain-model 0.2.0
File Interpreter ABI Platform
custom_langchain_model-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 82.8 kB

Release files / custom_langchain_model-0.2.0.tar.gz

Download URL custom_langchain_model-0.2.0.tar.gz
Size 40.0 kB
Tags Source
SHA-256 checksum
How to use checksums
9b53028d5a0ef2ba27b9b45353f30111027ef9f55dc8abe9df75c5f2f4e43d85
BLAKE2b-256 checksum
How to use checksums
50726711a475f8552ebd5c099f8f3f75de7b2de56d48182b7d853613c71256a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.14

Release files / custom_langchain_model-0.2.0-py3-none-any.whl

Download URL custom_langchain_model-0.2.0-py3-none-any.whl
Size 42.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
11747f71606c8320b9774c05b4f70b65114be4b758cf4b6370505fbdd59b512a
BLAKE2b-256 checksum
How to use checksums
d9387cbed5deffcf637db73d1a82006c966af1809c9ced9a3a9ce82d4f520a04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.14

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page