[ blog · use-case ]9 min read

สร้าง Agent ตรวจสอบสถานะ (Due Diligence) บนเอกสารยื่น SEC (10-K, 10-Q, 8-K, ผลประกอบการ)

Sarah Choyเผยแพร่ 3 พฤษภาคม 2569อ่าน 9 นาที
สร้าง Agent ตรวจสอบสถานะ (Due Diligence) บนเอกสารยื่น SEC (10-K, 10-Q, 8-K, ผลประกอบการ)

การอ่าน 10-K ส่วนใหญ่ก็คือกด Ctrl+F ทำแบบนี้กับห้าสิบบริษัทก็กลายเป็นงานเต็มเวลา แทนที่ 80% ที่น่าเบื่อด้วย agent ค้นหา-และ-สกัดข้อความบน SEC EDGAR แล้วเก็บ 20% ที่สำคัญไว้ให้นักวิเคราะห์ที่เป็นมนุษย์

สรุปสั้น

  • สถาปัตยกรรม: ค้นหา ticker → SEC Filings Search (เอกสารยื่น + ผลประกอบการ + สถิติหุ้น) → URL Extract สำหรับช่วงข้อความยาว → คำตอบจาก LLM พร้อมการอ้างอิงระดับหัวข้อ
  • เพดานต้นทุน: SEC Filings Search คิด 120 เครดิตต่อการเรียกหนึ่งครั้ง (≈$0.12); การรีวิวบริษัทแบบ 3 คำถามตามปกติมีต้นทุนราว ~$0.40 เป็นเครดิต + ~$0.05 เป็น token ของ LLM
  • สิ่งที่ agent ทำได้ดี: การค้นหาข้อเท็จจริง (รายได้แยกตามเซกเมนต์ แนวโน้ม capex ธรรมาภิบาล การเปลี่ยนแปลงปัจจัยเสี่ยงเทียบปีต่อปี) สรุปค่าตอบแทนผู้บริหาร เหตุการณ์ 8-K ล่าสุด
  • สิ่งที่ยังต้องใช้มนุษย์: การใช้วิจารณญาณเรื่องคุณภาพของฝ่ายบริหาร การวางตำแหน่งในตลาด ประเด็นเฉพาะของดีล และสิ่งใดก็ตามที่อยู่นอกเหนือถ้อยคำในเอกสารยื่น

ทำไมเรื่องนี้จึงคุ้มค่าที่จะทำให้เป็นอัตโนมัติ

การอ่านตรวจสอบสถานะรอบแรกของบริษัทมหาชนส่วนใหญ่เป็นงานเชิงกลไก: ดึง 10-K ล่าสุดออกมา สแกนดูปัจจัยเสี่ยงและ MD&A ตรวจ 8-K ล่าสุด ชำเลืองดู earnings call ครั้งล่าสุด นักวิเคราะห์ระดับ associate ใช้เวลา 2–4 ชั่วโมงต่อบริษัทกับงานนี้ ผลลัพธ์แทบไม่เคยเป็นข้อค้นพบเชิงลึก — แต่เป็นชุดข้อเท็จจริงที่มีโครงสร้างซึ่งอีกคนที่อาวุโสกว่าจะนำไปคิดวิเคราะห์ต่อ

ขั้นตอน "ชุดข้อเท็จจริง" นั้นเองคือสิ่งที่ agent ขนาดเล็กสามารถรับช่วงต่อได้ ค้นหาใน SEC สกัดช่วงข้อความที่เกี่ยวข้อง สรุปพร้อมการอ้างอิง คนที่อาวุโสกว่ายังคงเป็นผู้คิดวิเคราะห์ — แต่เริ่มต้นจากการอ่าน 5 นาทีแทนที่จะเป็น 4 ชั่วโมง

สามสิ่งที่ทำให้เรื่องนี้เป็นไปได้จริงในตอนนี้:

  • การค้นหาเชิงความหมายบนเอกสารยื่น หมายความว่าคุณถามได้ว่า 'รายได้ตามเซกเมนต์เปลี่ยนแปลงอย่างไร' แล้วได้ย่อหน้าที่ถูกต้องจากแบบฟอร์มที่ถูกต้องกลับมา แทนที่จะต้องอ่าน 200 หน้า
  • LLM แบบ context ยาว สามารถเก็บ 10-K ทั้งฉบับบวกกับ 8-K อีกสองสามฉบับไว้ในหน่วยความจำใช้งานและตอบคำถามที่ข้ามเอกสารได้
  • วินัยในการอ้างอิง ใน prompt ทำให้ผลลัพธ์ตรวจสอบได้ภายในไม่กี่วินาที — ตรงกับสิ่งที่เวิร์กโฟลว์ด้าน compliance และการทบทวนต้องการพอดี

สถาปัตยกรรม

question + ticker
       ├─ /api/company/facts (2 credits)
       │  ↳ confirm ticker, get CIK and sector
       ├─ /api/search/sec (120 credits)
       │  ↳ semantic search across 10-K/10-Q/8-K/earnings/equity stats
       ├─ /api/extract (2 credits per URL)
       │  ↳ pull full text of the top 3-5 most relevant filings
       └─ Claude / GPT-4 with citation-required prompt
          ↳ "answer + [Form, Fiscal Period, Section]"

ต้นทุนต่อคำถามเดียว: ~130 เครดิต (~$0.13) สำหรับ API + ~$0.03 สำหรับ LLM การรีวิวบริษัทแบบสามคำถาม (แนวโน้มการเงิน diff ของปัจจัยเสี่ยง เหตุการณ์สำคัญล่าสุด) ตกอยู่ที่ราว ~$0.45–$0.60 เมื่อเทียบกับค่าจ้างนักวิเคราะห์หนึ่งชั่วโมงที่อัตราค่าบริการใด ๆ ที่สมเหตุสมผล การคำนวณก็ชัดเจนอยู่แล้ว

System prompt ที่คุ้มค่าจ้าง

ปัจจัยที่กำหนดคุณภาพของผลลัพธ์ใน RAG ทางการเงินมากที่สุดอย่างเทียบไม่ติดคือ system prompt อันที่เราใช้:

You are a financial research assistant for an investment team. You answer
questions about US public companies using SEC filings, earnings call
transcripts, and equity statistics retrieved by your tools.

Rules — non-negotiable:

1. Cite every numeric claim with: [Form, Fiscal Period, Section]. Example:
   "Operating income rose 12% YoY to $4.1B [10-K FY2025, Item 7 MD&A]."

2. Quote numbers verbatim. Do not round, paraphrase, or convert. If a
   filing says "$4,127M", do not say "$4.1B" unless the filing itself does.

3. If the answer requires content you have not extracted, say so:
   "I could not retrieve the FY2024 10-K for the segment-level breakdown.
   Please re-run with that filing in scope."

4. Do not infer from training-data knowledge. If your tools didn't return
   it, you don't know it.

5. Default to the most recent fiscal period available. State the period
   you used.

6. Format multi-figure answers as a small markdown table with one column
   per fiscal period. Always end with a one-line "How I read this" summary.

Tone: precise, terse, no marketing language.

กฎข้อ 1, 2 และ 4 รวมกันขจัดปัญหาการกุข้อมูลได้ราว ~90% ตามที่เราวัดได้ กฎข้อ 3 (การพูดว่า 'ไม่ทราบ' อย่างงดงาม) คือสิ่งที่แยกสิ่งนี้ออกจากแชตบอตที่กุตัวเลขขึ้นมาอย่างมั่นอกมั่นใจ

ตัวอย่างคำถามที่ agent จัดการได้อย่างสะอาดหมดจด

  • 'เปรียบเทียบแนวโน้มรายได้จากบริการของ Apple ในช่วง 5 รอบบัญชีที่ผ่านมา' → ดึงจาก 10-K ที่เกี่ยวข้อง คืนตารางพร้อมการอ้างอิงไปยัง MD&A
  • 'ปัจจัยเสี่ยงของ NVIDIA เปลี่ยนแปลงอะไรบ้างระหว่าง FY2023 กับ FY2025?' → diff ข้ามเอกสาร โดยอ้างอิง Item 1A ในแต่ละแบบฟอร์ม
  • 'สรุป 8-K สี่ฉบับล่าสุดของ $TICKER' → การค้นหาเชิงความหมายที่กรองเฉพาะ 8-K เรียงตามวันที่ยื่น
  • 'CFO ของ Microsoft พูดว่าอะไรเกี่ยวกับ capex ด้าน AI ใน earnings call ครั้งล่าสุด?' → ค้นในบันทึกการประชุม สกัดช่วง Q&A ที่เกี่ยวข้อง อ้างคำต่อคำ

จุดที่มันทำได้ไม่ดี — และการส่งต่อให้มนุษย์อย่างถูกต้อง

agent สะดุดในสามจุดที่คาดเดาได้:

  • การใช้วิจารณญาณเรื่องคุณภาพของฝ่ายบริหาร เอกสารยื่นบอกคุณว่าพวกเขาทำอะไร ไม่ได้บอกว่าพวกเขามีความสามารถหรือไม่ อย่าถาม agent
  • การเทียบเคียงในอุตสาหกรรมที่อยู่นอกเอกสารยื่น หากคำถามคือ 'อัตรากำไรขั้นต้นนี้เทียบกับคู่แข่งเป็นอย่างไร' agent รู้เพียงสิ่งที่อยู่ในเอกสารยื่นที่ค้นมาเท่านั้น สำหรับการเทียบกับคู่แข่ง คุณต้องมีชุดข้อมูลแยกต่างหาก หรือรัน agent หนึ่งครั้งต่อบริษัทแล้วนำมารวมกัน
  • ความคิดเห็นเชิงมองไปข้างหน้า เอกสารยื่นมี forward-looking statements แต่โมเดลจะถือเอาตามตัวอักษรเว้นแต่จะสั่งเป็นอย่างอื่น ให้เพิ่มลงใน prompt: 'ทำเครื่องหมาย forward-looking statements อย่างชัดเจน อย่านำเสนอ guidance เป็นข้อเท็จจริง'

การสร้างเวอร์ชันขั้นต่ำที่ใช้งานได้

รูปแบบ tool-use loop ของ Claude แบบเดียวกันจาก คู่มือแบบละเอียดของ research agent ใช้ได้ที่นี่ — เปลี่ยนเฉพาะเครื่องมือและ system prompt เท่านั้น:

from anthropic import Anthropic
import requests

KEY = "pk_yourkey"
client = Anthropic()

def fetch_tool(path: str) -> dict:
    return requests.get(f"https://www.apipick.com{path}/tool-schema").json()["claude"]

TOOLS = [
    fetch_tool("/api/search/sec"),
    fetch_tool("/api/extract"),
    fetch_tool("/api/company/facts"),
]

def call_tool(block):
    name_to_path = {
        "sec_search": "/api/search/sec",
        "extract_urls": "/api/extract",
        "company_facts": "/api/company/facts",
    }
    path = name_to_path[block.name]
    method = "GET" if block.name == "company_facts" else "POST"
    if method == "GET":
        resp = requests.get(
            f"https://www.apipick.com{path}",
            params=block.input,
            headers={"x-api-key": KEY},
            timeout=30,
        )
    else:
        resp = requests.post(
            f"https://www.apipick.com{path}",
            json=block.input,
            headers={"x-api-key": KEY},
            timeout=30,
        )
    return {
        "type": "tool_result",
        "tool_use_id": block.id,
        "content": resp.text,
        "is_error": resp.status_code != 200,
    }

def due_dil(question: str) -> str:
    messages = [{"role": "user", "content": question}]
    while True:
        r = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=2048,
            system=SYSTEM_PROMPT,  # the one above
            tools=TOOLS,
            messages=messages,
        )
        messages.append({"role": "assistant", "content": r.content})
        if r.stop_reason == "end_turn":
            return "\n".join(b.text for b in r.content if b.type == "text")
        if r.stop_reason == "tool_use":
            results = [call_tool(b) for b in r.content if b.type == "tool_use"]
            messages.append({"role": "user", "content": results})

print(due_dil("Compare Snowflake's product revenue YoY for the last 4 quarters."))

จะต่อยอดไปทางไหนต่อ

  • เทมเพลตสำหรับการรีวิวที่ทำซ้ำได้ ห่อ agent ไว้ใน CLI ขนาดเล็กที่รับ ticker แล้วส่งออกบรีฟ markdown รูปแบบตายตัว: 'เหตุการณ์ 8-K ล่าสุด' 'แนวโน้มรายได้ตามเซกเมนต์' 'ส่วนต่างของปัจจัยเสี่ยง' agent ตัวเดียวกัน prompt ที่สคริปต์ไว้
  • โหมด watchlist รัน agent กับ ticker หนึ่งทุกเช้าแล้ว diff คำตอบของวันนี้กับเมื่อวาน แสดงเฉพาะส่วนต่างขึ้นมา เข้ากันได้ดีกับ รูปแบบ morning-briefing
  • ผสานกับสิทธิบัตรและตลาดพยากรณ์ สำหรับชื่อในกลุ่ม tech / biotech ให้เพิ่ม Patent Search สำหรับการเปลี่ยนแปลงด้าน IP และ Prediction Markets สำหรับผลลัพธ์ที่ฝูงชนบ่งชี้โดยนัย (เช่น ความน่าจะเป็นในการอนุมัติยา)

รูปแบบนี้นำไปใช้ทั่วไปได้ SEC เป็น corpus ที่หนาแน่นที่สุดและเป็นมิตรกับสคีมามากที่สุดที่เราให้บริการ — แต่ loop ('การค้นหาเชิงความหมาย → การสกัด URL → คำตอบพร้อมการอ้างอิง') ใช้ได้กับ corpus ของเอกสารที่มีโครงสร้างใด ๆ ที่คุณสนใจ: เอกสารทางกฎหมาย บทคัดย่อทางวิทยาศาสตร์ ข้อถือสิทธิของสิทธิบัตร สร้าง agent ตรวจสอบสถานะขึ้นมาก่อน แล้วค่อยย้ายสถาปัตยกรรมไปด้านข้าง

คำถามที่พบบ่อย

ดัชนีของ SEC สดใหม่แค่ไหน?

เอกสารยื่นจะถูกจัดทำดัชนีภายในไม่กี่ชั่วโมงหลังจาก EDGAR รับเอกสาร สำหรับ 8-K (ประเภทที่ไวต่อเวลา — เหตุการณ์สำคัญ การเปลี่ยนแปลงผู้นำ การเข้าซื้อกิจการ) โดยทั่วไปมักเร็วพอสำหรับเวิร์กโฟลว์แบบสิ้นวัน หากคุณต้องการการแจ้งเตือน 8-K ใหม่ภายในเวลาไม่ถึงหนึ่งชั่วโมง ให้จับคู่การค้นหากับ SEC RSS feed แยกต่างหาก และใช้ agent เฉพาะสำหรับการวิเคราะห์เนื้อหา ไม่ใช่การตรวจจับ

ครอบคลุมบันทึกการประชุมแจ้งผลประกอบการหรือไม่?

ครอบคลุม — ดัชนีของ SEC Filings Search รวมบันทึก earnings call ของสหรัฐฯ และสถิติหุ้น (ราคา/ปริมาณ ประวัติมูลค่าตลาด) ควบคู่ไปกับตัวเอกสารยื่นเอง query เชิงความหมายเพียงครั้งเดียวสามารถดึงจากแหล่งใดก็ได้เหล่านี้

มีคันโยกด้านต้นทุนอะไรบ้างถ้าผมทำสิ่งนี้ในสเกลใหญ่?

มีสามข้อ (1) กรองล่วงหน้าด้วย Company Facts (2 เครดิต) เพื่อยืนยันว่า ticker เป็นบริษัทมหาชนจริงก่อนจะจ่าย 120 เครดิตให้กับการค้นหา SEC (2) แคชผลการค้นหาตาม (ticker, ไตรมาส) — เอกสารยื่นจะอัปเดตตามกำหนดการเท่านั้น (3) ใช้การค้นหาแบบกว้างหนึ่งครั้งต่อคำถามแทนการค้นหาแคบ ๆ หลายครั้ง เพราะ agent เก่งในการสังเคราะห์ข้ามผลลัพธ์

agent รับมือกับเอกสารยื่นที่ไม่ใช่ของสหรัฐฯ ได้ไหม?

SEC Filings Search ครอบคลุมบริษัทที่จดทะเบียนในสหรัฐฯ (10-K, 10-Q, 8-K) สำหรับบริษัทในสหราชอาณาจักร ให้จับคู่ UK Legal Search กับ Web Search สำหรับเขตอำนาจศาลอื่น ให้หันไปใช้ Web Search + URL Extract บนเว็บไซต์ของหน่วยงานกำกับดูแลระดับชาติที่เกี่ยวข้อง (Companies House, SEDAR ฯลฯ)

จะหลีกเลี่ยงตัวเลขที่ถูกกุขึ้น (hallucinate) ได้อย่างไร?

กฎสามข้อใน system prompt สร้างความแตกต่างได้มากที่สุด (1) 'อ้างตัวเลขคำต่อคำจากข้อความที่สกัดมา — อย่าถอดความหรือปัดเศษ' (2) 'ระบุแบบฟอร์มเอกสารยื่น รอบบัญชี และการอ้างอิงหัวข้อเสมอ' (3) 'หากยังไม่ได้สกัดเอกสารยื่นที่เกี่ยวข้อง ให้บอกอย่างชัดเจน — อย่าอนุมานจากข้อมูลที่ใช้เทรน' สามข้อนี้รวมกันขจัดการกุข้อมูลได้เกือบหมด

API ที่ใช้ในบทความนี้

Sarah Choy
เขียนโดย
Sarah Choy
CEO, API Pick

Sarah Choy เป็น CEO ของ API Pick เธอเขียนเกี่ยวกับการสร้าง API พร้อมใช้งานจริงสำหรับ AI agent และเวิร์กโฟลว์ LLM