Tracks
Mô hình ngôn ngữ lớn trở nên hữu ích hơn khi chúng ta giao cho chúng vai trò chuyên biệt, công cụ và quyền truy cập dữ liệu trực tiếp. Thay vì dựa vào một mô hình duy nhất, ta có thể xây dựng một nhóm nghiên cứu nhỏ, trong đó mỗi tác nhân tập trung vào một phần khác nhau của quá trình phân tích.
Đó chính xác là những gì chúng ta sẽ làm trong hướng dẫn này: chúng ta sẽ xây dựng một multi-agent phân tích cổ phiếu bằng GLM-5.3-Flash và CrewAI. Ba tác nhân phân tích các yếu tố cơ bản, chỉ báo kỹ thuật và tin tức gần đây, trong khi một nhà quản lý danh mục đầu tư hợp nhất phát hiện của họ thành tín hiệu nghiên cứu cuối cùng: BUY, HOLD hoặc SELL.
Trước tiên, chúng ta sẽ thử nghiệm quy trình trong Jupyter Notebook, sau đó biến nó thành một giao diện dòng lệnh đơn giản có thể phân tích cổ phiếu và trả lời các câu hỏi tiếp theo.
Dự án sử dụng:
- GLM-5.3-Flash cho lập luận
- CrewAI để điều phối tác nhân
- Finnhub cho dữ liệu thị trường và cơ bản
- Yahoo Finance cho giá lịch sử
- Tavily cho tin tức gần đây
- Pandas và NumPy cho chỉ báo kỹ thuật
Mới làm quen với framework? Khóa học Building AI Agents with CrewAI của chúng tôi bao quát agents, crews, và flows từ đầu.
Vì sao dùng GLM-5.3-Flash cho ứng dụng Multi-Agent
GLM-5.3-Flash mang lại cân bằng ấn tượng giữa hiệu năng, hiệu suất và chi phí. Để có cái nhìn tổng quan, hãy đọc hướng dẫn GLM-5.3-Flash của chúng tôi và bài so sánh với Qwen3.8-Flash-Next.
Hiệu năng và hiệu suất cạnh tranh
Trên Artificial Analysis Intelligence Index, mô hình đạt 57, xếp vào nhóm dẫn đầu và cạnh tranh với một số mô hình tuyến đầu đắt hơn nhiều. Ví dụ:
-
GPT-5.6 Sol cũng đạt 57 (với nỗ lực lập luận
high) nhưng chi phí đắt hơn hơn 25 lần cho token đầu vào và 40 lần cho token đầu ra. -
Claude Sonnet 5 thậm chí thấp hơn một chút, 55 ở mức nỗ lực lập luận
max. Mô hình này đắt hơn 20x/30x cho token vào/ra so với GLM-5.3-Flash.
Mô hình có tổng 320B tham số, nhưng chỉ khoảng 18B tham số hoạt động trên mỗi token, cho phép đạt hiệu năng mạnh mẽ mà vẫn khá tiết kiệm tính toán.

Nguồn: AI Model & API Providers Analysis | Artificial Analysis
Mức giá hấp dẫn
Như đã đề cập, hiệu năng này đi kèm mức giá API tương đối thấp. Tại thời điểm viết bài, OpenRouter đang cung cấp GLM-5.3-Flash với mức giảm 50%, ở mức $0,075 cho mỗi triệu token đầu vào và $0,25 cho mỗi triệu token đầu ra.
Ngay cả ở mức giá thông thường $0,15/$0,50, nó vẫn rẻ hơn các mô hình như GPT-5.6 Luna của OpenAI, có giá $0,20/$1,20 (52 trên AA Intelligence Index với lập luận max). Điều này khiến nó hấp dẫn không chỉ cho thử nghiệm mà còn cho các ứng dụng tác nhân quy mô lớn, mức sản xuất.

Nguồn: GLM 5.3 Flash - API Pricing & Benchmarks | OpenRouter
Điều này càng quan trọng khi bạn xây dựng hệ thống multi-agent, vì một yêu cầu người dùng có thể kích hoạt nhiều cuộc gọi LLM ở hậu trường. Một tác nhân LLM đơn lẻ có thể gọi mô hình nhiều lần cho lập luận, chọn công cụ, xử lý đầu ra công cụ và tạo phản hồi cuối cùng. Nếu một tác nhân thực hiện khoảng bảy lần gọi LLM và quy trình của bạn dùng năm tác nhân, một yêu cầu có thể dễ dàng dẫn đến 35 cuộc gọi LLM hoặc hơn.
Con số chính xác phụ thuộc vào thiết kế hệ thống, nhưng điểm mấu chốt là: quy trình tác nhân có thể trở nên tốn kém rất nhanh. Dùng một mô hình đủ mạnh với giá token thấp như GLM-5.3-Flash có thể tạo khác biệt đáng kể khi chuyển từ bản demo nhỏ sang ứng dụng sản xuất thực sự.
1. Thiết lập môi trường cho GLM-5.3-Flash
Trước khi xây dựng quy trình multi-agent, hãy tạo khóa API cho Z.ai, Finnhub và Tavily.
Tạo khóa API
Với Z.ai, hãy chắc chắn dùng API thông thường, không phải GLM Coding Plan. Coding Plan dành cho các công cụ lập trình AI được hỗ trợ và không nên dùng như API mục đích chung cho ứng dụng multi-agent của bạn.
Tạo một khóa API Z.ai thông thường và nạp một khoản nhỏ vào tài khoản. Vì GLM-5.3-Flash rẻ, bạn chỉ cần số dư nhỏ để bắt đầu thử nghiệm.

Nguồn: Z.ai API Platform — Bắt đầu xây dựng với GLM-5.3
Bạn cũng có thể tạo tài khoản miễn phí trên Finnhub và Tavily và tạo khóa API. Mức miễn phí của họ đủ để thử nghiệm dự án này.
Thiết lập tệp dự án
Tiếp theo, tạo tệp .env trong thư mục dự án và thêm các khóa API:
ZAI_API_KEY="your_zai_api_key"
FINNHUB_API_KEY="your_finnhub_api_key"
TAVILY_API_KEY="your_tavily_api_key"
Giờ hãy tạo một Jupyter Notebook mới. Chúng ta sẽ trước hết xây dựng và kiểm thử toàn bộ quy trình multi-agent ở đây, kiểm tra đầu ra của từng tác nhân, và sửa lỗi trước khi biến nó thành ứng dụng hoàn chỉnh.
Cài đặt thư viện cần thiết
Chúng ta sẽ dùng CrewAI để tạo và điều phối tác nhân, Finnhub cho dữ liệu thị trường chứng khoán, và Tavily cho tìm kiếm web thời gian thực. Cài đặt các gói Python cần thiết:
!pip install -q crewai crewai-tools finnhub-python tavily-python pandas numpy requests python-dotenv openai
Import thư viện và khóa API
Tiếp theo, import các thư viện cần thiết và tải khóa API:
import os
import re
import time
import finnhub
import numpy as np
import pandas as pd
import requests
from dotenv import load_dotenv
from openai import OpenAI
from tavily import TavilyClient
from crewai import Agent, Crew, LLM, Process, Task
from crewai.tools import tool
from crewai_tools import TavilySearchTool
# Load environment variables
load_dotenv()
# Disable CrewAI tracing
os.environ.setdefault("CREWAI_TRACING_ENABLED", "false")
os.environ.setdefault("OTEL_SDK_DISABLED", "true")
Cuối cùng, chọn mã cổ phiếu bạn muốn các tác nhân phân tích:
TICKER = "NVDA"
Tôi sẽ dùng NVIDIA (NVDA) xuyên suốt notebook, nhưng bạn có thể thay bằng mã khác bạn quan tâm như AAPL, MSFT, hoặc TSLA.
2. Cấu hình GLM-5.3-Flash và các API dữ liệu
Giờ khi đã có khóa API, ta có thể kết nối các dịch vụ mà các tác nhân sẽ dùng xuyên suốt dự án.
Bắt đầu bằng việc khởi tạo Finnhub cho dữ liệu thị trường và Tavily cho tìm kiếm web:
finnhub_client = finnhub.Client(
api_key=os.environ["FINNHUB_API_KEY"]
)
tavily_client = TavilyClient(
api_key=os.environ["TAVILY_API_KEY"]
)
Nếu bạn muốn xây dựng các tác nhân tài chính và chưa rõ nên dùng nguồn dữ liệu nào, tôi khuyên đọc hướng dẫn của chúng tôi về chọn API dữ liệu thị trường chứng khoán phù hợp.
Tiếp theo, cấu hình GLM-5.3-Flash làm LLM chính cho các tác nhân CrewAI. Z.ai cung cấp API tương thích OpenAI, nên ta có thể kết nối trực tiếp qua lớp LLM của CrewAI:
llm = LLM(
model="openai/glm-5.3-flash",
api_key=os.environ["ZAI_API_KEY"],
base_url="https://api.z.ai/api/paas/v4/",
temperature=0.1,
)
Chúng ta giữ temperature thấp vì ứng dụng này tập trung vào nghiên cứu và phân tích tài chính, nơi ta muốn tác nhân cho phản hồi nhất quán và tập trung hơn.
Với mô hình, dữ liệu thị trường và API tìm kiếm web đã kết nối, giờ ta có thể bắt đầu xây dựng các công cụ mà tác nhân sẽ dùng.
3. Thu thập dữ liệu thị trường lịch sử
Tiếp theo, ta cần dữ liệu giá lịch sử để các tác nhân hiểu được hiệu suất cổ phiếu theo thời gian.
Cho việc này, ta sẽ dùng endpoint biểu đồ công khai của Yahoo Finance để thu thập dữ liệu giá mở, cao, thấp, đóng và khối lượng theo ngày.
Tải lịch sử giá
HTTP = requests.Session()
HTTP.headers.update({"User-Agent": "glm-stock-swarm/1.0"})
def _yahoo_history(ticker: str, days: int) -> pd.DataFrame:
end = int(time.time())
start = end - days * 24 * 60 * 60
response = HTTP.get(
f"https://query1.finance.yahoo.com/v8/finance/chart/{ticker}",
params={
"period1": start,
"period2": end,
"interval": "1d",
"events": "history",
},
timeout=30,
)
response.raise_for_status()
result = response.json()["chart"]["result"][0]
values = result["indicators"]["quote"][0]
frame = pd.DataFrame({
"date": pd.to_datetime(
result["timestamp"], unit="s", utc=True
).tz_localize(None),
"open": values["open"],
"high": values["high"],
"low": values["low"],
"close": values["close"],
"volume": values["volume"],
})
frame = (
frame.dropna(subset=["close"])
.sort_values("date")
.reset_index(drop=True)
)
frame.attrs["source"] = "Yahoo public chart"
return frame
def get_price_history(ticker: str, days: int = 450) -> pd.DataFrame:
return _yahoo_history(ticker.strip().upper(), days)
Chúng ta sẽ thu thập khoảng 450 ngày lịch sử, đủ để tính các chỉ báo dài hạn như trung bình động 200 ngày.
Tính toán chỉ báo kỹ thuật
Tiếp theo, hãy tính một vài chỉ báo thường dùng:
- Đường trung bình động: trung bình trên khung 20, 50 và 200 ngày
- Chỉ số sức mạnh tương đối (RSI): Thang 0–100 dùng để chỉ báo cổ phiếu quá mua (>70) hoặc quá bán (<30)
- MACD: Chênh lệch giữa EMA dài hạn và ngắn hạn
def add_indicators(frame: pd.DataFrame) -> pd.DataFrame:
if frame.empty:
return frame.copy()
result = frame.copy()
result.attrs.update(frame.attrs)
# Moving averages
result["SMA20"] = result["close"].rolling(20).mean()
result["SMA50"] = result["close"].rolling(50).mean()
result["SMA200"] = result["close"].rolling(200).mean()
# RSI
delta = result["close"].diff()
gain = delta.clip(lower=0)
loss = -delta.clip(upper=0)
avg_gain = gain.ewm(
alpha=1 / 14, min_periods=14, adjust=False
).mean()
avg_loss = loss.ewm(
alpha=1 / 14, min_periods=14, adjust=False
).mean()
result["RSI14"] = 100 - (
100 / (1 + avg_gain / avg_loss.replace(0, np.nan))
)
# MACD
result["EMA12"] = result["close"].ewm(
span=12, adjust=False
).mean()
result["EMA26"] = result["close"].ewm(
span=26, adjust=False
).mean()
result["MACD"] = result["EMA12"] - result["EMA26"]
return result
Các chỉ báo này hữu ích vì chúng cho tác nhân phân tích kỹ thuật cái nhìn nhanh về xu hướng và động lượng mà không cần yêu cầu LLM tự tính toán mọi thứ.
Xem lại các giá trị mới nhất
Giờ hãy thu thập dữ liệu, tính chỉ báo và hiển thị các dòng mới nhất:
history = add_indicators(
get_price_history(TICKER)
)
if len(history) < 200:
raise RuntimeError(
f"Need at least 200 daily observations; received {len(history)}."
)
print(
f"Loaded {len(history)} rows "
f"from {history.attrs['source']}."
)
history.tail(3)[
[
"date",
"close",
"SMA20",
"SMA50",
"SMA200",
"RSI14",
"MACD",
]
]

Bạn sẽ thấy giá cổ phiếu mới nhất cùng với các đường trung bình động, RSI và MACD, tương tự như đầu ra ở trên.
Sau này, chúng ta sẽ chuyển dữ liệu này cho tác nhân phân tích kỹ thuật để xác định xu hướng giá, động lượng, và tín hiệu tăng/giảm.
4. Biến nguồn dữ liệu thành công cụ CrewAI
Giờ khi các nguồn dữ liệu của chúng ta đã hoạt động, ta cần biến chúng thành công cụ CrewAI. Điều này cho phép các tác nhân gọi trực tiếp bất cứ khi nào cần thông tin tài chính, kỹ thuật hoặc tin tức.
Tạo công cụ dữ liệu cổ phiếu
Đầu tiên, tạo một hàm phụ trợ nhỏ để giữ giá trị số gọn gàng và nhất quán:
def _number(value, decimals: int = 2) -> str:
if value is None or pd.isna(value):
return "N/A"
return f"{float(value):,.{decimals}f}"
Tiếp theo, tạo công cụ fundamentals. Nó dùng Finnhub để truy xuất giá cổ phiếu mới nhất, định giá, tăng trưởng, lợi nhuận và các yếu tố cơ bản khác của công ty.
@tool("Get Stock Fundamentals")
def get_fundamentals(ticker: str) -> str:
"""Get current price and company fundamentals from Finnhub for one ticker."""
ticker = ticker.strip().upper()
quote = finnhub_client.quote(ticker)
metrics = finnhub_client.company_basic_financials(ticker, "all")
m = metrics.get("metric", {})
return f"""Ticker: {ticker}
Source: Finnhub
Current price: {_number(quote.get('c'))}
Previous close: {_number(quote.get('pc'))}
Daily change %: {_number(quote.get('dp'))}
Day high / low: {_number(quote.get('h'))} / {_number(quote.get('l'))}
Market cap (USD millions): {_number(m.get('marketCapitalization'))}
52-week high / low: {_number(m.get('52WeekHigh'))} / {_number(m.get('52WeekLow'))}
Normalized annual P/E: {_number(m.get('peNormalizedAnnual'))}
Annual P/B: {_number(m.get('pbAnnual'))}
Annual P/S: {_number(m.get('psAnnual'))}
ROE TTM: {_number(m.get('roeTTM'))}
Net margin TTM: {_number(m.get('netProfitMarginTTM'))}
Revenue growth TTM YoY: {_number(m.get('revenueGrowthTTMYoy'))}
EPS growth TTM YoY: {_number(m.get('epsGrowthTTMYoy'))}
Annual debt/equity: {_number(m.get('totalDebt/totalEquityAnnual'))}"""
Chúng ta cũng sẽ tạo một công cụ phân tích kỹ thuật dùng dữ liệu lịch sử và chỉ báo từ phần trước.
@tool("Analyze Stock Technicals")
def get_technicals(ticker: str) -> str:
"""Calculate price trends, returns, moving averages, RSI, and MACD."""
ticker = ticker.strip().upper()
frame = add_indicators(get_price_history(ticker))
if len(frame) < 200:
return (
f"Technical data unavailable for {ticker}: "
"fewer than 200 observations."
)
latest = frame.iloc[-1]
return f"""Ticker: {ticker}
Source: {frame.attrs.get('source', 'unknown')}
Last market date: {latest['date'].date()}
Close: {_number(latest['close'])}
SMA20 / SMA50 / SMA200: {_number(latest['SMA20'])} / {_number(latest['SMA50'])} / {_number(latest['SMA200'])}
RSI14: {_number(latest['RSI14'])}
MACD: {_number(latest['MACD'])}
20-day return: {_number((latest['close'] / frame['close'].iloc[-21] - 1) * 100)}%
50-day return: {_number((latest['close'] / frame['close'].iloc[-51] - 1) * 100)}%
Price vs SMA20: {_number((latest['close'] / latest['SMA20'] - 1) * 100)}%
Price vs SMA50: {_number((latest['close'] / latest['SMA50'] - 1) * 100)}%
Price vs SMA200: {_number((latest['close'] / latest['SMA200'] - 1) * 100)}%"""
Phần quan trọng ở đây là decorator @tool. Nó biến một hàm Python bình thường thành công cụ mà tác nhân CrewAI có thể quyết định gọi trong khi thực hiện nhiệm vụ.
Thêm công cụ tìm kiếm web
Đối với tin tức công ty và diễn biến gần đây, chúng ta sẽ dùng công cụ tìm kiếm Tavily của CrewAI:
web_search = TavilySearchTool(
api_key=os.environ["TAVILY_API_KEY"],
topic="news",
search_depth="advanced",
days=30,
max_results=5,
)
Chúng ta giới hạn tìm kiếm trong 30 ngày qua và trả về tối đa năm kết quả, đủ để các tác nhân nghiên cứu có thông tin cập nhật mà không bị quá tải nội dung không cần thiết.
Kiểm thử các công cụ cổ phiếu
Trước khi tạo tác nhân, hãy chạy trực tiếp hai công cụ tùy chỉnh:
print(get_fundamentals.run(ticker=TICKER))
print()
print(get_technicals.run(ticker=TICKER))

Giờ bạn sẽ thấy các chỉ số cơ bản mới nhất tiếp theo là các chỉ báo kỹ thuật cho cổ phiếu đã chọn.
5. Xây dựng đội nghiên cứu Multi-Agent
Giờ khi công cụ đã sẵn sàng, ta có thể tạo đội nghiên cứu multi-agent.
Chúng ta sẽ dùng ba tác nhân chuyên biệt, lần lượt cho phân tích cơ bản, phân tích kỹ thuật và tin tức gần đây, cùng một nhà quản lý danh mục đầu tư để hợp nhất kết quả thành đánh giá cuối cùng.
Tạo các tác nhân chuyên trách
Trước tiên, tạo nhà phân tích cơ bản:
fundamental_agent = Agent(
role="Fundamental Analyst",
goal=(
"Evaluate financial health, growth, profitability, "
"valuation, and balance-sheet risk."
),
backstory=(
"You are a careful long-term equity analyst. "
"Use the fundamentals tool and never invent a figure. "
"Treat N/A as missing, not as zero."
),
tools=[get_fundamentals],
llm=llm,
allow_delegation=False,
max_iter=4,
verbose=False,
)
Tiếp theo, tạo nhà phân tích kỹ thuật:
technical_agent = Agent(
role="Technical Analyst",
goal=(
"Determine whether the current price setup is "
"bullish, bearish, or neutral."
),
backstory=(
"You interpret indicators calculated by Python. "
"Never guess market prices or indicator values."
),
tools=[get_technicals],
llm=llm,
allow_delegation=False,
max_iter=4,
verbose=False,
)
Sau đó tạo nhà phân tích tin tức tài chính:
news_agent = Agent(
role="Financial News Analyst",
goal=(
"Find material recent developments and distinguish "
"confirmed reporting from speculation."
),
backstory=(
"You are a skeptical financial-news researcher. "
"Prioritize primary and reputable sources, dates, and links."
),
tools=[web_search],
llm=llm,
allow_delegation=False,
max_iter=5,
verbose=False,
)
Mỗi chuyên gia chỉ nhận công cụ mình cần. Điều này giữ cho quy trình tập trung và ngăn tác nhân gọi các công cụ không liên quan.
Tạo nhà quản lý danh mục
Cuối cùng, tạo tác nhân quản lý sẽ xem xét cả ba báo cáo chuyên gia:
manager_agent = Agent(
role="Portfolio Manager",
goal=(
"Combine the specialist reports into a balanced, "
"evidence-based research signal."
),
backstory=(
"You lead an equity research team. "
"Weigh bullish and bearish evidence, use HOLD when evidence "
"is mixed, and never add unsupported facts."
),
llm=llm,
allow_delegation=False,
max_iter=4,
verbose=False,
)
Nhà quản lý danh mục không cần truy cập trực tiếp công cụ dữ liệu. Thay vào đó, họ sẽ làm việc với các báo cáo do ba tác nhân chuyên môn tạo ra.
Thiết lập allow_delegation=False cũng giúp quy trình có thể dự đoán, trong khi max_iter giới hạn số chu kỳ lập luận và sử dụng công cụ mà mỗi tác nhân có thể thực hiện.
6. Giao nhiệm vụ nghiên cứu chuyên biệt
Tạo tác nhân xác định họ là ai. Giờ chúng ta cần nói rõ cho từng tác nhân họ phải làm gì và đầu ra cuối cùng cần chứa gì.
Định nghĩa các nhiệm vụ nghiên cứu
Bắt đầu với nhiệm vụ phân tích cơ bản:
fundamental_task = Task(
description=(
f"Analyze {TICKER}'s growth, profitability, valuation, "
"balance sheet, and business quality. "
"Use Get Stock Fundamentals. "
"Return a Fundamental Score from 0-100, strongest positive, "
"biggest risk, and note all material missing data."
),
expected_output=(
"A concise fundamental assessment with a 0-100 score, "
"evidence, strongest positive, biggest risk, "
"and missing-data note."
),
agent=fundamental_agent,
)
Tiếp theo, định nghĩa nhiệm vụ phân tích kỹ thuật:
technical_task = Task(
description=(
f"Analyze {TICKER}'s technical setup. "
"Use Analyze Stock Technicals. "
"Consider SMA20/50/200, RSI14, MACD, recent returns, and trend. "
"Return Technical Score 0-100, Bullish/Neutral/Bearish signal, "
"trend, momentum, and main technical risk."
),
expected_output=(
"A concise technical assessment with score, signal, trend, "
"momentum, data source, and main risk."
),
agent=technical_agent,
)
Với diễn biến gần đây, tạo nhiệm vụ nghiên cứu tin tức:
news_task = Task(
description=(
f"Research the most important recent news for {TICKER}, "
"focusing on the last 30 days: earnings, guidance, analyst "
"revisions, products, partnerships, M&A, regulation, lawsuits, "
"management, and industry developments. "
"Use Tavily Search. "
"Return News Score 0-100, sentiment, positive and negative "
"catalysts, publication dates, and source URLs. "
"Ignore low-quality speculation."
),
expected_output=(
"A sourced recent-news assessment with score, sentiment, "
"catalysts, dates, and clickable URLs."
),
agent=news_agent,
)
Việc giao cho mỗi tác nhân một nhiệm vụ và định dạng đầu ra rõ ràng rất quan trọng. Nó giúp báo cáo của họ dễ so sánh hơn với nhau thay vì nhận những phản hồi hoàn toàn khác nhau.
Tạo nhiệm vụ quyết định cuối cùng
Nhiệm vụ cuối cùng tập hợp cả ba báo cáo lại:
decision_task = Task(
description=(
f"Review all three specialist reports and make the final "
f"educational research assessment for {TICKER}. "
"Return exactly one signal: BUY, HOLD, or SELL. "
"Use HOLD when evidence is mixed or confidence is insufficient. "
"Base every claim only on the supplied reports."
),
expected_output=(
"Ticker; Signal; Overall Score /100; Confidence %; "
"Fundamental, Technical, and News scores; Bull Case; "
"Bear Case; Main Catalyst; Main Risk; Final Explanation; "
"Sources; and an educational-not-financial-advice disclaimer."
),
agent=manager_agent,
context=[
fundamental_task,
technical_task,
news_task,
],
)
Phần then chốt là context. Nó cung cấp cho nhà quản lý danh mục quyền truy cập đầu ra từ cả ba nhiệm vụ chuyên môn, cho phép so sánh tín hiệu cơ bản, kỹ thuật và tin tức trước khi đưa ra đánh giá BUY, HOLD hoặc SELL cuối cùng.
Đến đây, các tác nhân, công cụ và nhiệm vụ đều đã sẵn sàng. Tiếp theo, ta có thể kết nối mọi thứ vào quy trình CrewAI và chạy toàn bộ đội nghiên cứu.
7. Chạy đội nghiên cứu Multi-Agent
Giờ chúng ta có thể ghép mọi thứ lại và chạy quy trình nghiên cứu cổ phiếu hoàn chỉnh.
Tạo crew
Tạo một crew CrewAI gồm ba tác nhân chuyên môn và nhà quản lý danh mục:
crew = Crew(
agents=[
fundamental_agent,
technical_agent,
news_agent,
manager_agent,
],
tasks=[
fundamental_task,
technical_task,
news_task,
decision_task,
],
process=Process.sequential,
verbose=False,
tracing=False,
)
Chúng ta dùng Process.sequential, vì vậy các nhiệm vụ nghiên cứu chạy theo thứ tự. Các tác nhân cơ bản, kỹ thuật và tin tức hoàn thành phân tích trước, rồi nhà quản lý danh mục nhận các báo cáo đó để đưa ra đánh giá cuối cùng.
Chạy đội nghiên cứu
Khởi chạy quy trình bất đồng bộ:
result = await crew.kickoff_async()
Bước này có thể mất thời gian vì các tác nhân thực hiện nhiều cuộc gọi LLM và công cụ. Trong thử nghiệm của tôi, quy trình nghiên cứu hoàn chỉnh mất khoảng 4 đến 5 phút để kết thúc.
Khi hoàn tất, hiển thị báo cáo cuối cùng của nhà quản lý danh mục:
print(result.raw)

Bạn sẽ nhận một báo cáo chi tiết tương tự đầu ra trên, bao gồm:
- Tín hiệu BUY, HOLD hoặc SELL
- Điểm tổng thể
- Mức độ tin cậy
- Điểm của từng chuyên gia
- Lập luận chiều tăng (bull case)
- Lập luận chiều giảm (bear case)
- Yếu tố xúc tác
- Rủi ro
- Nguồn tham chiếu hỗ trợ
Trong ví dụ này, các tác nhân phân tích NVIDIA độc lập rồi hợp nhất phát hiện của họ thành một báo cáo nghiên cứu dựa trên bằng chứng duy nhất. Đây là lúc chúng ta thấy lợi ích của cách tiếp cận multi-agent: thay vì yêu cầu một mô hình làm mọi thứ cùng lúc, mỗi tác nhân tập trung vào lĩnh vực của mình rồi nhà quản lý danh mục tổng hợp tất cả nghiên cứu.
Nếu bạn gặp vấn đề khi chạy mã trên, tôi cũng đã đính kèm Jupyter Notebook hoàn chỉnh với toàn bộ mã và đầu ra để bạn xem hoặc tự chạy: glm-stock-swarm/stock_analyst_crew.ipynb
8. Xây dựng và chạy giao diện Terminal
Sau khi thử nghiệm mọi thứ trong Jupyter Notebook, tôi đã chuyển toàn bộ quy trình thành giao diện người dùng terminal (TUI). Thay vì chạy thủ công từng ô notebook, giờ bạn có thể khởi chạy toàn bộ bộ phân tích cổ phiếu multi-agent với một lệnh duy nhất.
Toàn bộ dự án, bao gồm mã và hướng dẫn thiết lập, có trên GitHub: kho GitHub glm-stock-swarm.
Cài đặt và chạy ứng dụng
Bắt đầu bằng cách clone kho:
git clone https://github.com/kingabzpro/glm-stock-swarm.git
cd glm-stock-swarm
Thêm khóa API Z.ai, Finnhub và Tavily của bạn vào tệp .env, rồi cài đặt tất cả phụ thuộc bằng uv:
uv sync
Cuối cùng, khởi chạy TUI:
uv run glm-stock-swarm
Phân tích một cổ phiếu
Giao diện cung cấp một ô nhập đơn giản nơi bạn có thể nhập bất kỳ mã cổ phiếu được hỗ trợ nào để bắt đầu phân tích.

Khi bạn gửi mã, bạn có thể theo dõi từng tác nhân làm việc. Nhà phân tích cơ bản bắt đầu trước, sau đó là nhà phân tích kỹ thuật, nhà phân tích tin tức và cuối cùng là nhà quản lý danh mục, người hợp nhất mọi thứ thành quyết định cuối cùng.

Cuối cùng, TUI tạo một báo cáo hoàn chỉnh ngay trong terminal, bao gồm điểm cơ bản, điểm kỹ thuật, điểm tin tức, điểm tổng thể, độ tin cậy, bull case, bear case, rủi ro, yếu tố xúc tác và tín hiệu BUY, HOLD hoặc SELL cuối cùng.
Đặt câu hỏi tiếp theo
Tôi cũng thêm phần chat theo sau để bạn không phải chạy lại toàn bộ pipeline multi-agent mỗi khi có câu hỏi mới.

Ví dụ, sau khi nhận khuyến nghị SELL, tôi hỏi liệu tôi nên bán toàn bộ vị thế hay chỉ một phần.

Thay vì khởi chạy lại cả bốn tác nhân, ứng dụng sử dụng ngữ cảnh từ báo cáo nghiên cứu đã tạo và gửi phản hồi tiếp theo nhanh hơn nhiều.
Điều này khiến ứng dụng thực tiễn hơn vì quá trình nghiên cứu multi-agent tốn kém chỉ chạy một lần, còn câu hỏi tiếp theo có thể tái sử dụng phân tích sẵn có.
Kết luận
Điểm đáng nói từ các lần thử của tôi là độ tin cậy khi gọi công cụ. Cả ba chuyên gia đều chọn đúng công cụ, tuân thủ quy ước N/A thay vì coi dữ liệu thiếu là 0, và trả lại định dạng điểm-số-và-bằng-chứng mà nhà quản lý danh mục cần. Đó thường là nơi các mô hình giá rẻ thất bại.
Tốc độ là đánh đổi. Artificial Analysis đo GLM-5.3-Flash khoảng 45 token đầu ra mỗi giây trên API của Z.ai, thuộc mức thấp đối với các mô hình open-weight kích cỡ này, và bạn sẽ cảm nhận ở thời gian 4–5 phút cho một lượt chạy đầy đủ. Nó cũng đạt 57 trên chỉ số trí tuệ của họ so với 60 của GLM-5.3, nên bạn hy sinh đôi chút chất lượng lập luận, nhưng đó là đánh đổi hợp lý khi bạn chỉ trả khoảng một phần mười chi phí.
Không có gì ràng buộc bạn. Chuyển sang OpenRouter, Hugging Face Inference, hoặc mô hình cục bộ qua Ollama thường chỉ cần đổi ba thứ: khóa API, tên mô hình và base URL. Công cụ cũng vậy, nơi yfinance có thể đảm nhiệm phần việc mà Finnhub và Yahoo chia sẻ ở đây.
Bước tiếp theo tôi sẽ làm là nối ứng dụng với API giao dịch mô phỏng và lên lịch chạy buổi sáng. Tuy nhiên, hãy giữ ở tài khoản demo. Ứng dụng này được xây để dạy thiết kế tác nhân, không phải để giao dịch.
Nếu bạn muốn học mọi thứ về AI tác nhân từ gốc, tôi khuyến nghị lộ trình kỹ năng AI Agent Fundamentals của chúng tôi như điểm khởi đầu tuyệt vời.
Là một nhà khoa học dữ liệu được chứng nhận, tôi đam mê tận dụng công nghệ tiên tiến để tạo ra các ứng dụng học máy đổi mới. Với nền tảng vững chắc về nhận dạng giọng nói, phân tích và báo cáo dữ liệu, MLOps, AI hội thoại và NLP, tôi đã rèn giũa kỹ năng phát triển các hệ thống thông minh có thể tạo ra tác động thực sự. Bên cạnh chuyên môn kỹ thuật, tôi cũng là một người truyền đạt tốt, có khả năng chắt lọc các khái niệm phức tạp thành ngôn ngữ rõ ràng, súc tích. Nhờ đó, tôi trở thành một blogger được nhiều người quan tâm trong lĩnh vực khoa học dữ liệu, chia sẻ góc nhìn và kinh nghiệm với cộng đồng các chuyên gia dữ liệu ngày càng lớn. Hiện tại, tôi tập trung vào sáng tạo và biên tập nội dung, làm việc với các mô hình ngôn ngữ lớn để phát triển nội dung mạnh mẽ và hấp dẫn, giúp doanh nghiệp và cá nhân tận dụng tối đa dữ liệu của mình.
