智能推薦、銷售預測、多模組資料流、自動對帳、履歷解析、商機評分
在當今數位轉型的浪潮中,Odoo 作為企業資源規劃 (ERP) 系統,正積極引入 人工智慧 (AI) 來強化各模組的功能。
想像一下,繁瑣的手動作業——例如逐張輸入發票、篩選上百份履歷或憑直覺預測銷售——現在都能透過 AI 自動完成或提供決策建議。
今天將以輕鬆但深入技術的方式,探索 Odoo 在會計、人資與 CRM 三大模組中引入 AI 的應用場景與實作方式。
想像公司的財務人員每天都要處理大量發票與收據:報銷單據、人事費用單、供應商發票等等,手動輸入這些票據資訊不僅耗時,還容易出錯。
如果我們能引入 AI,自動讀取票據,將大幅減少人工輸入與比對的負擔。例如,員工提交了一疊報銷收據影本,AI OCR 引擎可即時擷取每張收據上的金額、日期、商家等關鍵資訊,自動填入費用申請單中。
接著,當公司的銀行交易記錄上線後,AI 模型會將銀行對帳單的每筆款項和系統中的應收應付項自動比對,如同替財務人員找出「對帳拼圖」的配對,快速完成對帳並標記可能的差異。透過 AI 的協助,傳統上需要人工作業的會計流程變得更高效且準確。
AI 在會計票據處理與對帳中的具體運作流程:
在上述流程中,當發票影像上傳至 Odoo 時,系統會觸發OCR (Optical Character Recognition, 光學字元辨識) 引擎讀取影像中的文字。
讀取成功後,AI 模型將擷取到的發票號碼、日期、金額、供應商等資訊自動填入 Odoo 中對應的會計憑證欄位。如果有些欄位信心度不高或模糊不清,系統會標記提醒人工確認,確保資料正確無誤。接著,AI 還會根據歷史記錄學習每個供應商常用的費用科目或發票類型,主動建議適當的會計科目,把發票自動分類到正確的帳簿中。
在對帳階段,AI 模型會將處理過的銀行對帳單逐筆交易與系統內發票、收據進行比對:當找到金額、日期相符的一對交易時,自動將它們勾稽並標記為已核對;若有無法匹配的交易,則輸出例外清單供會計人員後續人工檢視處理。整個流程大大減少了人工輸入與核對的工作量,且AI會隨著處理更多資料逐步提升準確率。
技術設計與資料流:
TransientModel
的 Wizard,包含上傳發票影像的欄位。使用者透過此 Wizard 選擇影像並點擊「匯入發票」按鈕啟動流程。account.move
),自動填入供應商、日期及發票行等欄位資料。這裡遵循 Odoo ORM 慣例使用 env['account.move'].create()
新建記錄,同時將發票影像以附件形式關聯到該記錄以供日後查閱。act_window
) 開啟新建立的發票表單,方便使用者檢視與確認。from odoo import models, fields, api
from odoo.exceptions import UserError
import base64, requests
class AccountInvoiceOCRWizard(models.TransientModel):
_name = 'account.invoice.ocr.wizard'
_description = 'Invoice OCR Import Wizard'
invoice_image = fields.Binary(string="Invoice Image", attachment=True, required=True)
filename = fields.Char(string="Filename")
def action_import_invoice(self):
# 確認已上傳發票圖片
if not self.invoice_image:
raise UserError("請先上傳發票影像檔。")
# 呼叫外部 OCR API 辨識發票內容
try:
files = {'file': (self.filename or 'invoice.jpg', base64.b64decode(self.invoice_image))}
response = requests.post('http://my-ocr-service/parse_invoice', files=files)
if response.status_code != 200:
raise Exception(f"OCR service returned status {response.status_code}")
data = response.json()
except Exception as e:
raise UserError(f"OCR 辨識失敗: {e}")
# 根據辨識結果組裝發票資料
partner_name = data.get('vendor_name')
# 嘗試匹配或新建供應商
partner = self.env['res.partner'].search([('name', 'ilike', partner_name)], limit=1)
if not partner and partner_name:
partner = self.env['res.partner'].create({'name': partner_name, 'supplier_rank': 1})
move_vals = {
'move_type': 'in_invoice', # 供應商帳單類型的發票
'partner_id': partner.id if partner else None,
'invoice_date': data.get('invoice_date'),
'invoice_line_ids': []
}
# 處理發票明細行
for line in data.get('lines', []):
desc = line.get('description', '')
qty = line.get('quantity', 1)
price = line.get('price', 0.0)
# 嘗試依名稱找到產品,不存在則使用描述建立臨時產品
product = self.env['product.product'].search([('name', 'ilike', desc)], limit=1)
if not product:
product = self.env['product.product'].create({'name': desc, 'list_price': price})
move_vals['invoice_line_ids'].append((0, 0, {
'product_id': product.id,
'quantity': qty,
'price_unit': price,
'name': desc or "OCR Item"
}))
# 建立發票 (account.move) 紀錄
move = self.env['account.move'].create(move_vals)
# 將原始影像附件到發票
if move and self.filename:
self.env['ir.attachment'].create({
'name': self.filename,
'res_model': 'account.move',
'res_id': move.id,
'type': 'binary',
'datas': self.invoice_image,
})
# 返回動作以開啟新發票表單,讓使用者確認
return {
'name': "Invoice",
'type': 'ir.actions.act_window',
'res_model': 'account.move',
'view_mode': 'form',
'res_id': move.id,
'target': 'current',
}
上述程式碼中,我們建立了一個 account.invoice.ocr.wizard
繼承 TransientModel
的模型,用於上傳發票影像並執行 OCR。
action_import_invoice
方法先將 Binary 欄位中的影像轉換後,透過 requests.post
呼叫外部 OCR API,取得回傳的 JSON 資料。接著按照辨識的欄位填入 move_vals
字典:包含發票類型 (in_invoice
代表供應商發票)、供應商 (partner_id
),發票日期、以及發票行項目等資訊。我們透過 Odoo ORM 在 account.move
模型中建立新紀錄並填入欄位。
為了遵循原生慣例,發票行的建立使用 one2many 欄位的 tuple 格式 (0, 0, values)
來新增多筆 invoice_line_ids
。最後我們將原始發票影像存為附件關聯到新發票,並返回一個動作字典以開啟該發票的表單視圖。
<odoo>
<!-- 發票 OCR 匯入 Wizard 的表單視圖 -->
<record id="view_invoice_ocr_wizard_form" model="ir.ui.view">
<field name="name">account.invoice.ocr.wizard.form</field>
<field name="model">account.invoice.ocr.wizard</field>
<field name="arch" type="xml">
<form string="Import Invoice via OCR">
<group>
<field name="invoice_image" filename="filename"
widget="image" class="oe_enterprise_hide" />
<field name="filename" invisible="1"/>
</group>
<footer>
<button name="action_import_invoice" type="object" string="匯入發票" class="btn-primary"/>
<button string="取消" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- 操作動作:開啟 Wizard -->
<record id="action_invoice_ocr_wizard" model="ir.actions.act_window">
<field name="name">發票影像匯入</field>
<field name="res_model">account.invoice.ocr.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- 導覽功能表:將 Wizard 動作放入會計模組選單 -->
<menuitem id="menu_action_invoice_ocr" name="發票影像匯入" parent="account.menu_finance" action="action_invoice_ocr_wizard" sequence="90"/>
</odoo>
以上 XML 定義了一個 Wizard 表單視圖,包含影像上傳欄位及「匯入發票」按鈕。ir.actions.act_window
設定使我們可以從選單或其他地方開啟這個 Wizard。最後透過 <menuitem>
將此動作掛載到會計模組的選單中 (在此以財務總管 account.menu_finance
父選單下新增一項)。當使用者點選「發票影像匯入」時,會彈出 Wizard 表單,讓使用者上傳發票掃描檔並執行 OCR 導入。
這個擴充遵循 Odoo 的標準開發模式:使用 TransientModel 實現 Wizard 流程,不修改核心模型結構。同時,我們將外部服務解耦出Odoo,由 FastAPI 提供 OCR 功能,透過 HTTP API 交換資料,保持系統模組化。
辨識完成後自動建立的發票記錄,讓會計人員只需簡單校對即可過帳,大幅減少人工輸入時間與錯誤風險**。由於OCR 辨識可能有誤差**,我們保留讓使用者在發票表單中編輯修正的彈性,並將原始影像作為附件保存以供日後稽核。
另外整合時要注意資料安全與隱私:發票與帳務資料較敏感,如果使用外部雲端 OCR 服務,要確保符合公司政策(可對影像做脫敏處理或簽訂保密協議)。
由於會計資料牽涉合規,我們在導入 AI 時,流程上通常仍保留人工覆核環節,以確保關鍵財務數字無誤。
現代的人力資源 (HR) 部門經常面臨兩大挑戰:招聘與培訓。在招聘方面,一個熱門職缺往往會湧入上百份履歷,人工逐一篩選不僅耗費人力,也可能因主觀疲勞而疏漏人才。
而在員工發展方面,HR 需要為在職員工規劃培訓課程,以縮小技能差距,但找出每位員工適合的進修方向並非易事。
讓我們想像這樣的情境:HR 招募團隊每天開啟滿滿的收件匣,裡面是求職者們寄來的 PDF/Word 履歷;同時培訓專員要盤點公司未來的技能需求,安排現有人才進修。如果引入 AI,這些任務將大為簡化——智能履歷審查工具會自動讀取每份履歷,提取關鍵資訊如學歷、技能、工作經驗,甚至根據職缺要求進行候選人評分;而針對在職員工,AI 可以分析其績效和職涯目標,提供個人化訓練課程推薦,打造量身定制的成長計劃。
具體而言,當人資招募收到大量應徵履歷時,AI 會像一位資深獵才顧問,快速掃描每份 CV 的內容——擷取出求職者的學歷背景、技能清單與過往經驗年數,與該職位需求進行匹配,產出一個適配度分數或排名。HR 人員據此可以優先聯繫高分候選人,加速招募流程。同時,對公司現有員工,AI 模型會比對他們的現有技能與公司未來發展所需技能,找出技能缺口,並從內部/外部的課程資料庫中推薦合適的培訓課程。
下面以流程圖呈現履歷解析與員工訓練推薦兩部分的 AI 流程:
在招聘流程中,當新的電子履歷上傳或郵件收到時,AI 會首先對文件進行解析。如果履歷是 PDF 或圖片掃描件,會先經過文字識別 ;接著模型讀取履歷文字,提取出結構化資訊。
例如從段落中抓取學歷(如「碩士,資訊管理」)、技能(如「Python編程、專案管理」)、工作年資和關鍵成果等欄位。若遇到無法解析的特殊格式,系統會標示需要人工補充。當候選人的關鍵資料都結構化後,AI 會將其與職缺需求進行比對:比如該職位要求「5年以上經驗、熟悉數據分析」,則模型會根據履歷中的經驗年數和技能關鍵字計算匹配度分數。最終,AI 給出每位候選人一個分數或評級,HR 系統將候選人列表依此排序,方便招募人員優先篩選。得分特別高的,可能自動標記為「強烈建議面試」;反之,低分的則列為備選或淘汰。這樣一來,人資可以將精力集中在最有潛力的幾位候選人上,大幅提高招聘效率。
接下來看在職培訓部分。這裡 AI 扮演著員工的「訓練顧問」。它首先彙整每名員工的技能檔案與績效評估資料。例如,員工張小明的檔案顯示他精通 Java 和 SQL,近期績效評估中提到希望他加強雲端部署技能。AI 模型會將公司的未來戰略需求(例如更多雲端專才)和員工現有技能做比對,得出每個員工的技能差距報告。
接著,AI 連結到企業內建或外部的課程資料庫(如線上課程列表、研討會資訊),利用演算法尋找能彌補該員工技能差距的課程。例如辨識出張小明缺少 AWS 雲端經驗,就從資料庫中找出「AWS雲服務入門」課程推薦給他。AI 可以根據員工職位、學習偏好甚至同事的培訓成功案例,給出一份個人化的課程清單。
之後,系統可能將推薦結果發送給員工本人或其直屬經理以供審核,經討論確認後,HR 將選定的課程納入該員工的培訓計畫並安排後續的報名和跟進。如此,每位員工都獲得專屬的學習發展路線,有助於提升整體技能水準並留住人才,因為員工也會感受到公司在積極投資他的成長。
技術設計與資料流:
_inherit = 'hr.applicant'
在應徵者模型中新增兩個欄位:resume_data
(Text) 用於儲存解析後的履歷重點或結構化資料摘要,ai_score
(Float) 用於儲存 AI 給予候選人的評分。此外,我們也新增一個 resume_file
二進位欄位讓使用者上傳履歷 PDF 檔(或從附件取得),以及對應的檔名欄位。hr.applicant
表單上加入「解析履歷」按鈕,呼叫後端方法 action_parse_resume
。該方法會將履歷 PDF 傳送給外部 FastAPI 服務的 API(例如 POST /parse_resume
),由 AI 模型提取出求職者的關鍵資訊(如姓名、經驗、技能)並進行評分,回傳 JSON 結構資料。resume_data
,將建議分數寫入 ai_score
。這些欄位在表單中為唯讀顯示,供 HR 人員檢視。HR 可根據 AI 提供的摘要與分數快速瞭解該候選人的概況和推薦程度,輔助決策。hr.applicant
模型擴充與履歷解析方法範例from odoo import models, fields, api
from odoo.exceptions import UserError
import base64, json, requests
class Applicant(models.Model):
_inherit = 'hr.applicant'
resume_file = fields.Binary(string="Resume PDF")
resume_filename = fields.Char(string="Resume Filename")
resume_data = fields.Text(string="Parsed Resume Data", readonly=True)
ai_score = fields.Float(string="AI 評分", readonly=True)
def action_parse_resume(self):
# 確認已上傳履歷檔案
if not self.resume_file:
raise UserError("請先上傳候選人的履歷檔案。")
# 呼叫外部 FastAPI 履歷解析服務
try:
file_content = base64.b64decode(self.resume_file)
files = {'file': (self.resume_filename or 'resume.pdf', file_content, 'application/pdf')}
response = requests.post('http://my-ai-service/parse_resume', files=files)
if response.status_code != 200:
raise Exception(f"Service returned status {response.status_code}")
result = response.json()
except Exception as e:
raise UserError(f"履歷解析失敗: {e}")
# 取得解析結果中的結構資料與分數
structured_data = result.get('structured_data')
score = result.get('score')
# 將結構化資料轉存為 JSON 字串或摘要文字,存入 resume_data 欄位
if structured_data:
self.resume_data = json.dumps(structured_data, ensure_ascii=False, indent=2)
elif result.get('summary'):
# 若有提供摘要欄位,則存入摘要
self.resume_data = result['summary']
else:
self.resume_data = "(No data parsed)"
# 存入 AI 評分
self.ai_score = score if score is not None else 0.0
return True
上述程式碼透過 _inherit
擴充現有的 hr.applicant
模型,在 ORM 層級新增了我們需要的欄位和方法。action_parse_resume
方法的邏輯如下:
resume_file
) 解碼成原始 PDF 檔案內容,並使用 Python requests
套件發出 HTTP 請求到 FastAPI 服務。這裡假設 FastAPI 提供的服務接受一個名為 "file" 的檔案上傳欄位,URL 例如 http://my-ai-service/parse_resume
。UserError
呈現,通知使用者解析失敗。structured_data
(例如字典含姓名、電話、技能等欄位)以及整體評分 score
。我們將結構化資料轉為易讀的 JSON 字串儲存到 resume_data
(方便 HR 在前端直接查看重點資訊),將分數存入 ai_score
。欄位定義中已標記 readonly=True
,確保這些 AI 產出值不被手動修改。structured_data
中的關鍵欄位(如技能、年資)對應到 Odoo 模型的相應欄位做自動填寫,但這需要確保資料欄位匹配且格式正確,此處不贅述。<odoo>
<!-- 繼承 Odoo Recruitment 模組的 Applicant 表單視圖來添加新欄位和按鈕 -->
<record id="view_applicant_form_inherit_ai" model="ir.ui.view">
<field name="name">hr.applicant.form.inherit.ai</field>
<field name="model">hr.applicant</field>
<field name="inherit_id" ref="hr_recruitment.view_applicant_form"/>
<field name="arch" type="xml">
<!-- 在應徵者表單頁面添加一個分組,放置履歷上傳欄位、解析按鈕、以及結果欄位 -->
<group string="履歷解析">
<field name="resume_file" filename="resume_filename" widget="binary"/>
<button name="action_parse_resume" type="object" string="解析履歷" class="btn-primary"/>
</group>
<group string="AI 解析結果">
<field name="ai_score" />
<field name="resume_data" widget="text" colspan="2" />
</group>
</field>
</record>
</odoo>
上述 XML 使用視圖繼承 (inherit_id
) 的方式,將我們的新欄位與按鈕插入到現有的應徵者表單畫面上。在第一個 <group>
中,我們放置了履歷檔案上傳欄位及「解析履歷」按鈕;在第二個 <group>
中放置AI 評分和解析後資料欄位,方便 HR 查看結果。widget="text"
使得 resume_data
以純文字區塊呈現,可顯示JSON或段落文字格式的內容。
當 HR 人員打開某個應徵者記錄並上傳候選人的履歷 PDF 後,只需點擊「解析履歷」按鈕,系統即會將檔案傳至 AI 服務並迅速得到分析結果。
幾秒內,表單上的「AI 評分」會顯示如 85/100 這樣的分數,而「解析結果」欄位則呈現關鍵資訊摘要,例如:「經歷:5年軟體開發經驗;技能:Python、Docker、管理經驗...」。
藉由這種自動解析與評分,HR 可以快速篩選出高潛力的候選人而將精力投入到深入面試中。值得注意的是,AI 分析只是輔助,HR 仍應最終判斷候選人適配度;我們設計上保留了人工覆核的空間(例如可以對解析出的內容再做調整)。
整體流程遵循 Odoo ORM 方式擴充模型與視圖,不影響既有招聘模組的資料表結構與功能,符合模組化原則。
💡 Gary’s Pro Tip|避免招聘偏見
在讓 AI 幫助履歷篩選時,要小心模型可能學到了數據中不良的偏見。例如過去公司偏好特定學校畢業的人才,導致模型自動降低非該校申請者分數。為避免這種情況,建議在設計候選人評分標準時,避開種族、性別、年齡等敏感資訊,主要關注技能和經驗相關欄位。此外,可定期審查AI的推薦結果,如發現不合理的排除/選擇,需調整演算法或加入人工複核機制。
進入 CRM (Customer Relationship Management) 領域,我們關注的是銷售預測與商機評分 (Lead Scoring)。
銷售團隊常常要回答兩個問題:「下季度業績會如何?」以及「目前這些潛在客戶中,哪些最有可能成交?」。傳統上,銷售預測可能依賴經理人在 Excel 中根據往年數據做粗略估計,而商機評分則靠業務員的直覺經驗去判斷誰是「大條魚」。
AI 的加入,讓這一切有了科學的依據:利用歷史銷售資料訓練的預測模型,可以對未來幾個月的營收做出相對精確的預測;而基於客戶和交易數據的機器學習模型則能為每筆銷售線索打分,指出哪些 leads 最值得優先跟進。
以下流程圖將展示銷售預測與商機評分這兩項 AI 功能在 CRM 模組中的運作:
在銷售預測部分,首先需要有大量歷史銷售資料作為基礎,包含每期(每月、每季)的銷售額、訂單數量,以及可能的影響因素(產品類別、季節性、促銷活動等)。
將這些數據送入預測模型訓練階段,可以使用各種時間序列模型或機器學習算法,例如 ARIMA、Prophet、XGBoost 等。模型訓練完成後,就得到了一個能夠輸入時間序列特徵並預測未來銷售額的 AI 模型。
接著,我們將當前的銷售管線數據(例如本季度已簽單金額、正在談判的商機金額等)輸入模型,讓它預測下一季度的銷售額或訂單數。模型的預測結果會匯總成報告,可能以圖表形式顯示未來幾個月的銷售曲線、相對的信心區間等等。
有了這份報告,管理層就能以更科學的依據來制定營業目標、調整庫存和資源配置,避免純粹憑經驗拍腦袋。同時,若預測顯示某月可能業績下滑,團隊可以提前啟動行銷活動或促銷方案作為應對。
在商機評分部分,AI 模型做的是分類/排序的工作。每當新的潛在客戶 (Lead/Opportunity) 進入系統,模型就像一個「顧問」,幫你快速評估它的價值。首先,系統會對商機資料進行特徵提取:例如抽取出「來源=官網註冊」、「產業=製造業」、「公司規模=50人」、「瀏覽官網頁面數=5次」、「與銷售互動=2封Email」等等。接著,這些特徵被餵給預先訓練好的機器學習模型。
該模型可能是一個分類模型(預測該lead最終成交(Won)或流失(Lost)的概率)。模型基於過去成千上萬條類似客戶的結果來預測這一條的結局機率。例如它算出「成交概率 85%」,我們可以將此轉換為一個分數(比如五星中的四星半,或百分比形式顯示)。AI 甚至還可以自動豐富這些潛在客戶資料,例如根據Email網域自動填充公司的行業、規模等資訊,讓評分更準確。
最終,高分的商機會被優先指派給資深業務跟進或立刻聯絡,而低分的則可能交由自動化行銷流程去培養(比如定期發送電子報維繫)。如此一來,銷售團隊能將時間用在刀刃上,提高整體轉換率和營收。
技術設計與流程:
_inherit = 'crm.lead'
為商機模型新增 ai_win_probability
(Float) 欄位,用於記錄預測的成交率百分比,以及 ai_priority_label
(Selection) 欄位,表示 AI 建議的優先級(例如 Low/Medium/High 三檔分類)。action_predict_lead
。當使用者點擊時,後端會收集該 crm.lead
的相關資訊(例如名稱、預計收入、產業、備註描述等),以 JSON 格式傳送給 FastAPI 的 GPT 模型端點 (假設為 POST /score_lead
)。{"win_probability": 0.75, "priority": "high"}
。win_probability
轉換成百分比填入欄位,priority
字串對應到定義的 Selection 選項填入 ai_priority_label
。資料儲存後,使用者界面即刻顯示 AI 評估的數值。開發時也可加入通知 (notification) 來提示評估完成與結果概要。crm.lead
模型擴充與AI評估方法範例from odoo import models, fields, api
from odoo.exceptions import UserError
import requests
class Lead(models.Model):
_inherit = 'crm.lead'
ai_win_probability = fields.Float(string="AI 成交率 (%)", readonly=True)
ai_priority_label = fields.Selection([
('low', 'Low'), ('medium', 'Medium'), ('high', 'High')
], string="AI 建議優先級", readonly=True)
def action_predict_lead(self):
# 準備商機資料發送給 AI 服務
payload = {
'lead_name': self.name,
'lead_value': self.planned_revenue,
'customer_industry': self.partner_id.industry_id.name if self.partner_id.industry_id else '',
'description': self.description or ''
}
try:
response = requests.post("http://my-ai-service/score_lead", json=payload)
if response.status_code != 200:
raise Exception(f"Bad response: {response.status_code}")
result = response.json()
except Exception as e:
raise UserError(f"AI 預測服務調用失敗: {e}")
# 解析回傳結果並寫入欄位
win_prob = result.get('win_probability') # 預測成交率 (0~1 之間的小數)
priority = result.get('priority') # 預測優先級 (low/medium/high)
if win_prob is not None:
# 轉換成百分比存入,例如0.75變75%
self.ai_win_probability = float(win_prob) * 100.0
if priority:
# 如結果在預定義選項內則寫入,否則預設為 medium
self.ai_priority_label = priority if priority in dict(self._fields['ai_priority_label'].selection) else 'medium'
return True
在上述程式中,我們使用 _inherit
為商機模型添加了新的 AI 欄位以及操作方法。action_predict_lead
所做的事情包含:
payload
字典。其中我們選取了可能影響成交率的欄位:商機名稱、預計營收 (planned_revenue
)、客戶的產業、商機描述等。這些欄位只是示例,實際應用中可根據模型需要傳遞更多訊息(如商機階段、客戶規模等)。requests.post
發送 JSON 至 FastAPI 的預測接口。如果 API 回應非成功,我們拋出異常提示。這裡的設計是同步調用,即按鈕按下會等待 AI 結果返回,在一定時間內(幾秒內)完成評估。win_probability
) 乘以100轉換為百分比數字寫入 ai_win_probability
欄位;將優先級 (priority
) 文字寫入 ai_priority_label
。我們用了一個保險處理:確認回傳的 priority 值在我們定義的 low/medium/high 範圍內,否則給個中性值,以避免無效值存入。欄位更新後,Odoo 會自動在畫面上反映最新值。值得一提的是,上述方法返回 True
,Odoo 在處理按鈕類型為 type="object"
的點擊時,不要求特定回傳值;如需在操作完成後給使用者彈出訊息,可使用 self.env.user.notify_info(...)
類的方法,這裡留待需要時實現。
<odoo>
<record id="view_crm_lead_form_inherit_ai" model="ir.ui.view">
<field name="name">crm.lead.form.inherit.ai</field>
<field name="model">crm.lead</field>
<field name="inherit_id" ref="crm.crm_lead_view_form"/>
<field name="arch" type="xml">
<!-- 在商機表單的「內部備註」頁籤後新增一個頁籤來顯示 AI 評估結果 -->
<xpath expr="//page[@name='internal_notes']" position="after">
<page string="AI 評估" name="ai_prediction">
<group>
<button name="action_predict_lead" type="object" string="AI 預測評分" class="btn-primary"/>
<field name="ai_win_probability" />
<field name="ai_priority_label" />
</group>
</page>
</xpath>
</field>
</record>
</odoo>
以上 XML 繼承了 CRM 商機的主要表單視圖 (crm.crm_lead_view_form
),透過 XPath 在「內部備註」頁籤後新增了一個名為 "AI 評估" 的頁籤。其中包含一個按鈕和兩個唯讀欄位:按鈕點擊後將調用先前定義的 action_predict_lead
方法,而 ai_win_probability
與 ai_priority_label
欄位用於顯示預測的成交率百分比和優先級等第。這種分頁設計可以避免擠占原有畫面空間,使用者可按需點擊查看 AI 分析結果。
業務人員在使用本功能時,只需打開商機記錄點擊「AI 預測評分」,幾秒內便能看到例如「AI 成交率:82.5%,建議優先級:High」的結果出現在「AI 評估」頁籤下。
💡 Gary’s Pro Tip|預測結果可解釋性
AI 給出的預測如果無法解釋理由,業務團隊有時會存疑。例如模型突然判定某老客戶的單子不可能成交,而業務員可能認為勝券在握,這時就需要解釋模型判斷的依據(可能因為該客戶過去3次相似需求最後都沒購買)。一種做法是提供解釋性提示,例如附帶一句「因客戶過去一年無追加訂單且競品報價存在,建議降低預期」。這可透過 SHAP 等模型解釋工具取得,但在 Odoo 中實現需要工程投入。權衡下,可以先透過訓練簡單可解釋的模型(如決策樹,以規則呈現)與團隊分享,培養大家對AI決策邏輯的理解,再逐步換用複雜模型並提供解釋摘要。
透過以上三大模組的探索,我們看到 AI 結合 Odoo 的會計、人資、CRM 模組,為管理帶來前所未有的效率提升與智慧洞察。
從繁瑣的票據處理到海量的履歷篩選,從未知的未來業績到茫茫的潛在客戶,AI 都能成為 Odoo ERP 中可靠的助手。
當然,在技術實現的背後,我們也需要關注數據品質、模型偏差和用戶採用度等因素,才能讓AI真正落地生根。