SKILL.md · Free
ตรวจ Facebook Ads
ตรวจค่าโฆษณา คลิก และยอดซื้อจากไฟล์รายงาน แยกข้อมูลที่ขาดก่อนสรุปสิ่งที่ควรตรวจต่อ
ดาวน์โหลด Skillต้องเตรียมอะไร
- รายงานระดับโฆษณาในช่วงเดียวกัน
- เป้าหมายและเงื่อนไขการนับยอด
- ยอดรวมจาก export สำหรับเทียบ
Skill ทำอะไรให้
- ตรวจขอบเขตและคอลัมน์
- คำนวณจากยอดรวม
- แยกข้อค้นพบจากข้อสันนิษฐาน
- ส่งรายการตรวจต่อ
ได้อะไรกลับมา
- ตารางตัวเลขรวมและรายโฆษณา
- รายการข้อมูลที่ขาด
- งานตรวจต่อพร้อมเหตุผล
ตัวอย่างข้อมูลและผลทดลอง
ทดลองกับข้อมูลสมมติของ KlangPrompt ไม่ใช่ผลงานลูกค้า
โจทย์ที่ใช้ทดลอง
โฆษณา A/B/C ใช้เงินรวม 2,000 บาท มี link click 400 ครั้ง แถว C ขาดยอดซื้อและมูลค่า ต้องตรวจโดยไม่เปลี่ยนแคมเปญ
ผลที่ได้จากการทำตามขั้นตอน
Link CTR รวม 0.8% / CPC 5 บาท / CPM 40 บาท ยังสรุป CPA และ ROAS รวมไม่ได้ เพราะ C ขาดข้อมูล B มี landing 30 จาก 150 คลิก ควรตรวจวิธีนับและหน้าเว็บก่อนสรุปสาเหตุ
ดูไฟล์ในชุดนี้
facebook-ads-quick-audit/ examples/brief.txt examples/export.csv references/export.md scripts/audit_export.py SKILL.md LICENSE.txt CHANGELOG.md examples/result.md
examples/brief.txt
ข้อมูลสมมติสำหรับทดสอบ ไม่ใช่ผลแคมเปญลูกค้า ตรวจ A/B/C ใน export.csv ช่วง1–7กันยายน2569 THB เป้าหมายยอดขาย attributionเป็นค่าตัวอย่างที่เจ้าของระบุเหมือนกัน Control totals: spend2000 impressions50000 linkclicks400 ยังไม่ส่งเป้าหมายCPA ไม่มีหลักฐานเหตุconversionตก แถวCขาดlanding/purchase/revenue ห้ามเติมศูนย์ ขอรายงานรวมและสิ่งที่ต้องตรวจต่อ ไม่แก้แคมเปญ
examples/export.csv
ad_id,start,end,currency,objective,attribution,spend,impressions,link_clicks,landing_views,purchases,revenue A,2026-09-01,2026-09-07,THB,sales,owner-export-window,1000,10000,200,120,4,2400 B,2026-09-01,2026-09-07,THB,sales,owner-export-window,600,30000,150,30,0,0 C,2026-09-01,2026-09-07,THB,sales,owner-export-window,400,10000,50,,,
references/export.md
# CSV ที่ตัวคำนวณอ่าน หนึ่งแถวต่อ ad_id ต่อช่วงรายงาน ไม่มี breakdownซ้อน ไม่มี total row ลำดับคอลัมน์ต้องตรง: `ad_id,start,end,currency,objective,attribution,spend,impressions,link_clicks,landing_views,purchases,revenue` วันที่ YYYY-MM-DD ทั้งไฟล์ต้องใช้ช่วงเดียวกัน; currency/objective/attributionต้องเหมือนกัน ไม่ได้กำหนดattributionตายตัว ให้คัดค่าจากexportจริงและบอกconversioneventที่ใช้ในรายงาน spend/revenueเป็นจำนวนไม่ติดลบ, impressions/link_clicksเป็นจำนวนเต็มไม่ติดลบ; landing_views/purchases/revenueเว้นว่างได้เมื่อไม่มีข้อมูล ห้ามเติม0แทนช่องว่าง purchaseอนุญาตทศนิยมตามตัวเลขreported ไม่ถือว่าเป็นจำนวนคนที่ไม่ซ้ำกัน link_clicksคือlinkclickไม่ใช่allclick; landing_viewsต้องตรงนิยามที่exportใช้ หากไม่มีก็เว้นว่าง ราคาทั้งหมดตามสกุลเดียวกัน ไม่รวมหลายสกุลหรือรวมreachรายแถวเพื่ออ้างunique reach Scriptไม่อ่าน Excelตรง ไม่ตรวจว่าแพลตฟอร์มยิงeventถูกจริง และไม่พิสูจน์ว่าโฆษณาเป็นสาเหตุของการซื้อ ต้องตรวจข้อมูลต้นทางเพิ่มเมื่อโจทย์ต้องการ
scripts/audit_export.py
"""Read-only ad-export math; Python 3.9+, no external dependency/network."""
import argparse
import csv
import datetime
import json
import sys
from decimal import Decimal, InvalidOperation
SCHEMAS = {
'facebook': 'ad_id,start,end,currency,objective,attribution,spend,impressions,link_clicks,landing_views,purchases,revenue'.split(','),
'google': 'row_id,start,end,currency,conversion_scope,ad_group,search_term,spend,impressions,clicks,conversions,conversion_value'.split(',')
}
def divide(numerator, denominator, factor=1):
if numerator is None or denominator in (None, Decimal(0)):
return None
return float((numerator / denominator * factor).quantize(Decimal('0.000001')))
def audit(path, mode):
schema = SCHEMAS[mode]
metrics = schema[6:] if mode == 'facebook' else schema[7:]
optional = {'landing_views','purchases','revenue'} if mode == 'facebook' else {'conversions','conversion_value'}
identity = ('start','end','currency','objective','attribution') if mode == 'facebook' else ('start','end','currency','conversion_scope')
rows, seen, groups, missing = [], set(), set(), []
with open(path, encoding='utf-8-sig', newline='') as stream:
reader = csv.DictReader(stream)
if reader.fieldnames != schema:
raise ValueError('columns must match documented schema')
for line, row in enumerate(reader, 2):
if None in row or any(v is None for v in row.values()):
raise ValueError(f'line {line}: malformed row')
row = {k:v.strip() for k,v in row.items()}
if any(not row[k] for k in schema if k not in optional):
raise ValueError(f'line {line}: required value missing')
key = row[schema[0]]
if key in seen:
raise ValueError(f'line {line}: duplicate ID; resolve overlapping breakdowns')
seen.add(key)
if datetime.date.fromisoformat(row['start']) > datetime.date.fromisoformat(row['end']):
raise ValueError('reversed period')
groups.add(tuple(row[k] for k in identity))
if len(groups) > 1:
raise ValueError('mixed period/currency/objective/measurement; split export')
values = {}
for key in metrics:
if row[key] == '' and key in optional:
values[key] = None
missing.append({'line':line,'id':row[schema[0]],'metric':key})
continue
value = Decimal(row[key])
if not value.is_finite() or value < 0 or value > Decimal('1e18'):
raise ValueError(f'line {line}: invalid number {key}')
if key in ('impressions','link_clicks','clicks','landing_views') and value != value.to_integral_value():
raise ValueError(f'line {line}: count must be integer {key}')
values[key] = value
rows.append({'source':row,'values':values})
if not rows:
raise ValueError('no data rows')
totals = {k:None if any(r['values'][k] is None for r in rows) else sum((r['values'][k] for r in rows),Decimal(0)) for k in metrics}
def summarize(v):
clicks = v['link_clicks' if mode == 'facebook' else 'clicks']
conversions = v['purchases' if mode == 'facebook' else 'conversions']
revenue = v['revenue' if mode == 'facebook' else 'conversion_value']
out = {k:None if n is None else str(n) for k,n in v.items()}
out.update(ctr_pct=divide(clicks,v['impressions'],100),cpc=divide(v['spend'],clicks),cpa=divide(v['spend'],conversions),roas=divide(revenue,v['spend']))
if mode == 'facebook':
out.update(cpm=divide(v['spend'],v['impressions'],1000),landing_per_link_click_pct=divide(v['landing_views'],clicks,100))
else:
out.update(conversion_rate_pct=divide(conversions,clicks,100))
return out
return {'mode':mode,'scope':dict(zip(identity,next(iter(groups)))), 'totals':summarize(totals),
'rows':[{'id':r['source'][schema[0]],'source_line':i+2,**({'ad_group':r['source']['ad_group'],'search_term':r['source']['search_term']} if mode=='google' else {}),'metrics':summarize(r['values'])} for i,r in enumerate(rows)],
'missing':missing,'limits':['Reported attribution, not causal proof','Null is missing or division by zero; never substitute zero']}
def main():
if hasattr(sys.stdout, 'reconfigure'):
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('mode',choices=SCHEMAS)
parser.add_argument('csv_file')
args=parser.parse_args()
try:
result=audit(args.csv_file,args.mode)
except (OSError,ValueError,InvalidOperation) as exc:
print(json.dumps({'error':str(exc)},ensure_ascii=False),file=sys.stderr)
return 2
print(json.dumps(result,ensure_ascii=False,indent=2))
return 0
if __name__ == '__main__':
sys.exit(main())
SKILL.md
--- name: facebook-ads-quick-audit description: ตรวจรายงาน Facebook Ads หนึ่งช่วงเวลา แยกปัญหาคลิก หน้าเว็บ และยอดซื้อ คำนวณจากยอดรวมและจัดลำดับสิ่งที่ต้องตรวจต่อ ไม่แก้แคมเปญหรือสรุปสาเหตุจาก CTR อย่างเดียว license: KlangPrompt Skills License 1.0 --- # ตรวจ Facebook Ads ส่งรายงานสั้นที่เจ้าของโฆษณาตัดสินใจได้ว่าควรตรวจอะไรต่อ ไม่ตัดสินแพ้ชนะด้วยค่าเฉลี่ยวงการที่ไม่มีหลักฐาน ## ตั้งขอบเขต รับ export ระดับโฆษณาหนึ่งช่วงเวลา สกุลเงิน เป้าหมาย และนิยาม attribution ที่ใช้ รับ CPA/ROAS เป้าหมายเฉพาะเมื่อผู้ใช้มีจริง หากไม่มีให้รายงานค่า ไม่สร้างเกณฑ์เอง ห้ามนำชื่อ/อีเมลของลูกค้ามาใช้ในรายงานนี้ อ่าน [references/export.md](references/export.md) แล้วบันทึก mapping ของคอลัมน์เดิมเป็น CSV สำเนา ไม่แก้ต้นทาง ไม่รวมแถว total กับแถวย่อย หรือ breakdown ที่ทับซ้อน ถ้าไฟล์มีหลายช่วงเวลา/วัตถุประสงค์/attribution ให้แยกก่อน ไม่เฉลี่ยรวมโดยอัตโนมัติ ## ตรวจและคำนวณ 1. รัน `python scripts/audit_export.py facebook FILE.csv` ตัวคำนวณไม่เชื่อมบัญชีโฆษณาและไม่เปลี่ยนงบ 2. ตรวจ warnings ก่อนอ่านผล ช่อง purchases/revenue ว่างคือไม่มีข้อมูล ไม่ใช่ศูนย์ ถ้ามีแถวขาดข้อมูล ยอดรวม metricนั้นเป็น null เพื่อไม่ให้รายงานยอดรวมบางส่วนเป็นทั้งหมด 3. อ่าน link CTR, CPC, CPM, อัตราจาก link click ถึง landing page view และ CPA/ROAS จากยอดรวม ไม่ใช้ค่าเฉลี่ยเปอร์เซ็นต์แต่ละแถวเป็นยอดรวม 4. เทียบแถวภายในกลุ่มเดียวกัน ระบุฐาน impressions/clicks/purchases เสมอ ศูนย์ conversion ทำให้ CPA คำนวณไม่ได้ ไม่ใช่ CPA0 หรืออนันต์ที่นำไปจัดอันดับได้ 5. แยกสิ่งที่รู้กับข้อเสนอให้ตรวจ: click→landingต่างกันมากให้ตรวจความเร็วหน้า/วิธีนับ/redirect ยังไม่ฟันธงว่าสาเหตุคือหน้าเว็บ; ซื้อไม่เกิดให้ตรวจ measurement/ช่วงรอattribution/ข้อเสนอ อย่าเหมาว่า hookไม่ดี ## ส่งงาน ส่งตารางรวมและรายโฆษณา พร้อมช่วงเวลา/attribution/นิยาม linkclick; รายการขาดข้อมูล; งานตรวจต่อที่ผูกกับแถวต้นทาง สำหรับแต่ละงานระบุ “พบอะไร / ยังไม่รู้ / จะตรวจอย่างไร / ใครทำ” ถ้าไม่มีเจ้าของงานให้เว้นว่าไม่ระบุ ไม่ตั้งชื่อคนเอง ถ้าผู้ใช้ถามเรื่องนโยบายหรือการปฏิเสธโฆษณา ให้อ่านเหตุปฏิเสธและเอกสาร Meta ล่าสุดก่อน ไม่ใช้ไฟล์นี้เป็นรายการคำต้องห้าม ไม่ทำนายยอดขายหรือสั่งปิดโฆษณาอัตโนมัติ ## ตรวจผล เทียบยอด spend/impressions/linkclick กับ control total ใน export หากต่างให้หยุดข้อเสนอปรับงบ ตรวจการหารศูนย์และ missing; ทุกข้อสรุปต้องชี้แถว/metric ไม่ใช้ตัวอย่างสมมติเป็น benchmark ความสำเร็จ คงข้อจำกัด attribution และรายงานเฉพาะสิ่งที่ตรวจจริง
LICENSE.txt
KlangPrompt Skills License 1.0 — 2026-09-22 KlangPrompt เป็นผู้จัดทำไฟล์ในชุดนี้ ไม่มีไฟล์ Skill ของผู้อื่นนำมาขายต่อ ผู้ดาวน์โหลดรายการฟรีหรือผู้ซื้อที่ได้รับสิทธิ์ ใช้และปรับไฟล์กับงานของตนและงานลูกค้าได้ เก็บสำเนาสำรองได้ ผลงานที่ทำด้วย Skill นำไปใช้เชิงพาณิชย์ได้ตามสิทธิ์ของข้อมูลและสื่อที่นำมาใช้ ห้ามเผยแพร่ต่อหรือขายต่อไฟล์ Skill หรือสำเนาที่แก้ไขเป็นสินค้าแยก การแบ่งปันภายในทีมต้องมีสิทธิ์จาก KlangPrompt ก่อน ข้อจำกัดนี้ไม่ใช้กับผลลัพธ์งานของผู้ใช้ ไฟล์ไม่รวมค่าใช้บริการ AI หรือเครื่องมือภายนอก และไม่รับรองว่า Agent จะทำงานถูกทุกครั้ง ผู้ใช้ต้องตรวจข้อเท็จจริง สิทธิ์ของเนื้อหา และผลลัพธ์ก่อนใช้จริง สิทธิตามกฎหมายที่ไม่อาจจำกัดได้ยังคงอยู่
CHANGELOG.md
# 1.0.0 — 2026-09-22 รุ่นแรก แยกขั้นตอน ขอบเขตงาน และการตรวจผล พร้อมข้อมูลสมมติสำหรับทดลอง
examples/result.md
# ผลทดลองตรวจ Facebook Ads รันตัวคำนวณจริงใน Codex กับ exportสมมติของKlangPrompt ช่วง1–7กันยายน2569 THB ไม่ใช่ผลลูกค้า ไม่ทดสอบติดตั้งAgentอัตโนมัติ spend2,000 / impressions50,000 / linkclick400 ตรงcontroltotalsทั้งหมด LinkCTR0.8%, CPC5บาท, CPM40บาท ค่าCTRไม่ใช่ค่าเฉลี่ย2%/0.5%/0.5% | โฆษณา | Link CTR | CPC | landing/click | CPA | ROAS | |---|---:|---:|---:|---:|---:| | A | 2% | 5 | 60% | 250 | 2.4 | | B | 0.5% | 4 | 20% | คำนวณไม่ได้ | 0 | | C | 0.5% | 8 | ไม่มีข้อมูล | ไม่มีข้อมูล | ไม่มีข้อมูล | ยอดซื้อ/มูลค่ารวมและCPA/ROASรวมไม่รายงาน เพราะCขาด3ช่อง ไม่เอายอดA+Bไปอ้างทั้งไฟล์ ไม่เรียกCPAของBว่า0บาท งานตรวจต่อ: 1. ขอlanding/purchases/revenueของCหรือยืนยันว่าไม่ได้เก็บ ก่อนสรุปยอดรวม (sourceแถว4) 2. Bมีlanding30จากlinkclick150 ต่ำกว่าAในไฟล์นี้ ตรวจหน้าโหลด วิธีนับ และredirect โดยยังไม่ฟันธงสาเหตุ ยังไม่มีหลักฐานว่าhookทำให้ซื้อไม่ได้ (แถว3) 3. ก่อนสั่งเพิ่ม/ลดงบ ต้องมีเป้าหมายCPAของร้านและสถานะtracking/attributionlag ไม่สรุปว่าAกำไรจากROAS2.4เมื่อไม่มีmargin ไม่มีผู้รับผิดชอบระบุ จึงไม่แต่งชื่อเจ้าของงาน ไม่มีการเปลี่ยนแคมเปญหรือเรียกAPIบัญชี
