把上一份「BP 神經網路基礎」落地到 Odoo(Odoo ERP;白話:可客製的企業管理系統)內的實務情境:銷售(Sales)、CRM、庫存(Inventory)、會計(Accounting) 等。策略是:
read_group
、search_read
),整理成特徵(Features),呼叫外部 ML API。x_lead_score
)、觸發 Server Action(白話:自動動作)或 排程任務(ir.cron
)。/predict
、/train
。為何推論放外部?
Odoo 核心環境精簡,不適合安裝大量科學運算套件;把模型服務外部化,可保部署與升級穩定。
crm.lead
新增 x_lead_score
(Float),x_lead_tier
(Selection:A/B/C)。/predict
→ 回寫分數/等第 → 自動建立 活動(Activity) 指派資深業務追蹤。stock.warehouse.orderpoint
的 最小/最大庫存(Reorder Point),觸發自動補貨。subscription
/sale.subscription
,週期性推論→ 建立 活動 或寄送 Email 模板。ir.attachment
)→ 外部 ML 辨識 → 回寫 account.move
欄位,並在稽核不一致時建立 待辦。sale.order.line
)新增「推薦集」Many2many,UI 上彈出 Side Panel。__manifest__.py
python
{
"name": "ml_bp_integration",
"version": "16.0.1.0.0",
"depends": ["crm", "sale_management", "stock", "queue_job"], # queue_job: OCA 佇列處理
"data": [
"data/ir_cron.xml",
"views/crm_lead_views.xml"
],
"installable": True,
}
模型:在 crm.lead 加欄位與推論方法
from odoo import api, fields, models, _
import requests
class CrmLead(models.Model):
_inherit = "crm.lead"
x_lead_score = fields.Float(string="Lead Score (BP)")
x_lead_tier = fields.Selection(
[("A", "Tier A"), ("B", "Tier B"), ("C", "Tier C")],
string="Lead Tier",
compute="_compute_lead_tier",
store=True,
)
def _build_features(self):
# 專有名詞:Feature Engineering(特徵工程;白話:把原始欄位轉成模型懂的數字)
feats = []
for lead in self:
feats.append({
"country": lead.country_id.code or "NA",
"industry": lead.industry_id.name if hasattr(lead, "industry_id") else "NA",
"company_size": lead.partner_id.employee_count or 0,
"website_pages": lead.website_pages_viewed or 0,
"email_open_rate": lead.email_open_rate or 0.0,
"reply_delay_hours": lead.reply_delay_hours or 999,
"utm_source": lead.source_id.name if lead.source_id else "Direct",
})
return feats
def _call_ml_api(self, payload):
# 專有名詞:Model Serving(模型服務;白話:一個可被呼叫的預測 API)
base = self.env["ir.config_parameter"].sudo().get_param("ml_bp.api_base", "http://ml:8000")
url = f"{base}/predict/lead"
# 可加上 API Key
r = requests.post(url, json=payload, timeout=10)
r.raise_for_status()
return r.json()
@api.model
def cron_score_leads(self, limit=500):
# 專有名詞:Scheduled Action / ir.cron(排程工作;白話:自動每 X 分鐘跑一次)
domain = [("type", "=", "opportunity"), ("create_date", ">=", fields.Date.subtract(fields.Date.today(), days=90))]
leads = self.search(domain, limit=limit)
if not leads:
return
feats = leads._build_features()
resp = leads._call_ml_api({"instances": feats})
scores = resp.get("predictions", [])
for lead, score in zip(leads, scores):
lead.write({"x_lead_score": score})
# 門檻驅動:自動建立活動(Activity)
if score >= 0.8:
lead.activity_schedule(
"mail.mail_activity_data_call",
user_id=lead.user_id.id or self.env.user.id,
summary=_("High-score lead auto follow-up"),
)
@api.depends("x_lead_score")
def _compute_lead_tier(self):
for rec in self:
s = rec.x_lead_score or 0.0
rec.x_lead_tier = "A" if s >= 0.8 else ("B" if s >= 0.5 else "C")
排程(ir_cron)
ML 微服務雛形(FastAPI)
from fastapi import FastAPI
from pydantic import BaseModel
import math
import random
app = FastAPI(title="BP Lead Scoring Service")
class Instances(BaseModel):
instances: list # list of dict features
@app.post("/predict/lead")
def predict(payload: Instances):
preds = []
for feat in payload.instances:
# 範例:簡化版的前向傳遞(Feedforward;白話:把數字一路算到輸出)
x = 0.0
x += 0.3 * (feat.get("email_open_rate", 0))
x += 0.2 * (1.0 / (1 + feat.get("reply_delay_hours", 999)))
x += 0.1 * (feat.get("website_pages", 0) / 10.0)
x += 0.15 if feat.get("utm_source") in ("Referral", "Campaign") else 0.0
x += 0.1 if (feat.get("company_size", 0) >= 100) else 0.0
# Sigmoid(邏輯式/Logistic;白話:把分數壓在 0~1)
score = 1.0 / (1.0 + math.exp(-x))
preds.append(round(score, 4))
return {"predictions": preds}
實務上請:
以 PyTorch/TensorFlow 訓練 BP 網路;
儲存 權重(Weights)/偏置(Bias);
上線時載入模型、實作 /predict;
搭配 Model Registry(例如 MLflow;白話:版本化模型)管理不同版本。
特徵工程(Feature Engineering)設計範例
情境 原始欄位 衍生特徵(衍伸) 說明
CRM 進件 utm_source, email logs 開信率、點擊率、回覆延遲小時 行為強度越高,成交機率通常越高
銷售預測 sale.order.line 移動平均、節慶 dummy、促銷標誌 非線性特徵有助 BP 逼近模式
流失 subscription 使用頻率、近 30 天支援票數 頻率下降+抱怨升高 → 高風險
OCR 校驗 account.move 影像邊緣密度、字元信心度 作為二階分類器,過濾錯讀
專有名詞:One-Hot Encoding(獨熱編碼;白話:把類別變成多個 0/1 燈)、Normalization(標準化;白話:把數值縮放到合理範圍)。
工作流(Workflow)串接與自動化
排程拉數據(ir.cron)→
特徵工程 →
呼叫 ML API →
寫回分數(x_lead_score 等)→
條件觸發 Server Action/Activity(白話:自動派工、寄信、打標籤)→
量化觀測(KPI Dashboard:AUC、精準率、召回率)。
專有名詞:Precision/Recall(精準率/召回率;白話:抓到的有多準/漏掉多少)、AUC(ROC 曲線下面積;白話:分得開的程度)。
模型訓練與治理(MLOps)
資料切分(Train/Validation/Test;白話:練習/調參/期末考)
過擬合控制(Dropout、L2 正則、早停 Early Stopping)
超參數(Hidden Layers/Neurons、Learning Rate、Batch Size)
監控(Data Drift、Concept Drift;白話:資料型態或規則變了)
版本管理(模型/特徵/資料快照),失效就 Rollback。
安全與效能注意事項
重試與熔斷(Retry/Circuit Breaker;白話:ML 服務掛了別把 Odoo 卡死)
佇列(queue_job):把大量推論丟背景工作,避免 HTTP 超時。
權限(API Key/簽章)、稽核軌跡(Log 每次推論輸入/輸出與模型版本)。
隱私(PII/個資)最小化傳遞,能匿名就匿名。
端到端示例:銷售預測→自動補貨
ir.cron 每晚抽近 26 週的 sale.order.line。
生成 SKU × 週期的特徵表(季節、促銷、移動平均、節日 dummy)。
呼叫 /predict/demand,拿到未來 4 週需求量。
更新 stock.warehouse.orderpoint 的最小/最大庫存。
觸發 Odoo 補貨(Reordering Rules;白話:低於線就自動採購/生產)。
KPI 看 缺貨率、呆滯庫存天數、服務水準。
FAQ(常見問題)
為何不用 Odoo 內訓練?
大量科學套件與本機相依會衝突、升級困難;外部微服務更穩定。
BP 與梯度消失?
可改 ReLU、加 BatchNorm,或遷移到 CNN/RNN/Transformer 視需求。
資料不平衡(Imbalanced)?
權重損失(Class Weight)、過採樣/欠採樣、閾值調整。
一頁關鍵詞(附白話)
Backpropagation(反向傳遞):從結果往回修正每條線的強弱。
Activation Function(激活函數):把加總分數壓成 0~1 或其他形狀。
Loss Function(損失函數):預測與真實差多遠。
SGD(隨機梯度下降):靠斜率決定要加還是減。
Overfitting(過擬合):背答案。Underfitting(欠擬合):沒學會。
Feature Engineering(特徵工程):把原始欄位變成模型好懂的數字。
Model Serving(模型服務):把模型包成 API 讓系統呼叫。
MLOps:管資料、模型、部署與監控的一整套方法。
結語
把 BP 神經網路 放進 Odoo,重點不是「多深多炫」,而是:
選好業務節點 → 做對特徵 → 服務化部署 → 迭代監控。
當你把模型輸出與 Odoo 工作流(活動、補貨、票據、推薦)緊密連結,AI 就不再是展示,而是每天實打實替團隊省時增效的引擎。