Skip to main content

LangChain custom chat model

Project description

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.pysingle 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: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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

custom_langchain_model-0.2.0.tar.gz (40.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

custom_langchain_model-0.2.0-py3-none-any.whl (42.8 kB view details)

Uploaded Python 3

File details

Details for the file custom_langchain_model-0.2.0.tar.gz.

File metadata

File hashes

Hashes for custom_langchain_model-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9b53028d5a0ef2ba27b9b45353f30111027ef9f55dc8abe9df75c5f2f4e43d85
MD5 ba813e44d801a693ab8bdf3936e6530f
BLAKE2b-256 50726711a475f8552ebd5c099f8f3f75de7b2de56d48182b7d853613c71256a3

See more details on using hashes here.

File details

Details for the file custom_langchain_model-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for custom_langchain_model-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 11747f71606c8320b9774c05b4f70b65114be4b758cf4b6370505fbdd59b512a
MD5 1f59dcec978837260e7e556f25487dbd
BLAKE2b-256 d9387cbed5deffcf637db73d1a82006c966af1809c9ced9a3a9ce82d4f520a04

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page