0Pricing
AI Agents · บทเรียน

การออกแบบวงจรการวิจัยหลายขั้นตอน

วางแผน → ค้นหา → อ่าน → สกัด → สังเคราะห์ → ทำซ้ำจนได้ความลึกเพียงพอ

การออกแบบวงจรการวิจัยหลายขั้นตอน เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

ลูปการวิจัยคืออะไร

ลูปการวิจัยเป็นรูปแบบการทำงานของเอเจนต์ที่ LLM วางแผน ค้นหา อ่าน แยกข้อมูล ระบุช่องว่าง และทำซ้ำ จนกว่าจะบรรลุเป้าหมายการวิจัย

ลูปนี้แตกต่างจากการค้นหาเพียงครั้งเดียว เพราะจะปรับตัวตามสิ่งที่ค้นพบ โดยติดตามเบาะแสที่ไม่คาดคิดและตัดเส้นทางที่ไม่เกิดประโยชน์ทิ้ง

ระยะที่ 1: การแยกย่อยคำถาม

ขั้นตอนแรกคือการแบ่งคำถามวิจัยออกเป็นคำถามย่อย วิธีนี้จะสร้างแผนการค้นหาแบบมีทิศทาง และป้องกันไม่ให้เอเจนต์เรียกดูข้อมูลไปเรื่อย ๆ อย่างไร้จุดหมาย

import openai, json

client = openai.OpenAI(api_key='YOUR_OPENAI_KEY')

def decompose_question(question: str) -> list[str]:
    prompt = (
        f'Break this research question into 3-5 focused sub-questions.\n'
        f'Each sub-question should be independently searchable.\n'
        f'Question: "{question}"\n'
        f'Return JSON: {{"sub_questions": ["..."]}}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content)['sub_questions']

questions = decompose_question('What are the main causes of inflation in 2024?')
print(questions)

ระยะที่ 2: การค้นหาเว็บ

ดำเนินการค้นหาเว็บสำหรับคำถามย่อยแต่ละข้อ ใช้ส่วนเชื่อมต่อการค้นหา เช่น เซอร์เปอร์ เบรฟ หรือบิง เพื่อรับรายการที่อยู่เว็บและข้อความสรุป อย่าอ่านทุกหน้า ให้จัดลำดับความสำคัญกับแหล่งข้อมูลคุณภาพสูงก่อน

import requests

SERPER_KEY = 'YOUR_SERPER_API_KEY'

def search_web(query: str, num_results: int = 5) -> list[dict]:
    resp = requests.post(
        'https://google.serper.dev/search',
        headers={'X-API-KEY': SERPER_KEY, 'Content-Type': 'application/json'},
        json={'q': query, 'num': num_results}
    )
    resp.raise_for_status()
    results = resp.json().get('organic', [])
    return [
        {'title': r['title'], 'url': r['link'], 'snippet': r.get('snippet', '')}
        for r in results
    ]

ระยะที่ 3: การอ่านและแยกข้อเท็จจริง

ดึงข้อมูลจากที่อยู่เว็บแต่ละแห่งและแยกข้อเท็จจริงสำคัญที่เกี่ยวข้องกับคำถามย่อย ใช้ LLM อ่านบทความและสร้างรายการข้อเท็จจริงพร้อมที่อยู่เว็บของแหล่งข้อมูล

import httpx
from bs4 import BeautifulSoup

def fetch_text(url: str, max_chars: int = 4000) -> str:
    try:
        resp = httpx.get(url, timeout=10, follow_redirects=True,
                         headers={'User-Agent': 'ResearchAgent/1.0'})
        soup = BeautifulSoup(resp.text, 'html.parser')
        for tag in soup(['script', 'style', 'nav', 'footer']):
            tag.decompose()
        return soup.get_text(separator=' ', strip=True)[:max_chars]
    except Exception:
        return ''

def extract_facts(text: str, question: str, url: str) -> list[dict]:
    prompt = (
        f'Extract key facts from the text that answer: "{question}"\n'
        f'Return JSON: {{"facts": ["fact1", ...]}}\n\n'
        f'TEXT:\n{text[:3000]}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    facts = json.loads(resp.choices[0].message.content).get('facts', [])
    return [{'fact': f, 'source': url} for f in facts]

ระยะที่ 4: การระบุช่องว่างทางความรู้

หลังจากอ่านแล้ว ให้ LLM ทบทวนข้อเท็จจริงที่สะสมไว้และระบุว่ายังมีสิ่งใดที่ไม่ทราบ ช่องว่างเหล่านี้จะกลายเป็นคำค้นหาสำหรับการค้นหารอบถัดไป

def identify_gaps(original_question: str, facts: list[dict]) -> list[str]:
    fact_text = '\n'.join(f'- {f["fact"]}' for f in facts[:20])
    prompt = (
        f'Original question: "{original_question}"\n'
        f'Facts gathered so far:\n{fact_text}\n\n'
        f'What key aspects are still unanswered? '
        f'Return 0-3 follow-up search queries (0 if research is complete).\n'
        f'JSON: {{"gaps": ["search query 1", ...]}}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content).get('gaps', [])

เงื่อนไขการยุติการทำงาน

ลูปต้องมีเงื่อนไขหยุดที่ชัดเจนเพื่อป้องกันไม่ให้ทำงานต่อไปตลอด ให้หยุดเมื่อ:

  • ไม่พบช่องว่างใหม่
  • ไม่มีการเพิ่มข้อเท็จจริงใหม่ในการทำซ้ำครั้งล่าสุด
  • ทำซ้ำครบจำนวนสูงสุดแล้ว (ขีดจำกัดด้านความปลอดภัย)
  • จำนวนข้อเท็จจริงทั้งหมดเกินเกณฑ์ที่กำหนด (มีข้อมูลลึกเพียงพอ)
def should_continue(gaps: list[str], new_facts_this_round: int,
                    iteration: int, total_facts: int) -> bool:
    if iteration >= 5:
        return False          # Hard cap: 5 iterations
    if new_facts_this_round == 0:
        return False          # No new information found
    if not gaps:
        return False          # LLM says research is complete
    if total_facts >= 50:
        return False          # Sufficient depth reached
    return True

if __name__ == '__main__':
    print('Continue (has gaps, new facts)?', should_continue(['gap1'], 4, iteration=1, total_facts=10))
    print('Continue (no new facts)?', should_continue(['gap1'], 0, iteration=1, total_facts=10))

การกำจัดข้อเท็จจริงซ้ำ

แหล่งข้อมูลหลายแห่งมักรายงานข้อเท็จจริงเดียวกัน ให้กำจัดข้อมูลซ้ำโดยขอให้ LLM รวมข้อเท็จจริงที่มีความหมายเทียบเท่ากัน และเก็บเวอร์ชันที่มีแหล่งที่มาดีที่สุดไว้

def deduplicate_facts(facts: list[dict]) -> list[dict]:
    if len(facts) <= 3:
        return facts
    fact_text = '\n'.join(
        f'{i}: {f["fact"]} (source: {f["source"]})' for i, f in enumerate(facts)
    )
    prompt = (
        f'Remove duplicate or near-duplicate facts. Keep the most informative version.\n'
        f'Return JSON: {{"keep_indices": [0, 1, ...]}}\n\n'
        f'FACTS:\n{fact_text}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    indices = json.loads(resp.choices[0].message.content).get('keep_indices', [])
    return [facts[i] for i in indices if i < len(facts)]

ลูปการวิจัยแบบสมบูรณ์

รวมทุกระยะไว้ในฟังก์ชัน research() เดียว ซึ่งควบคุมลูปจนกว่าจะถึงเงื่อนไขการยุติการทำงาน

def research(question: str) -> dict:
    all_facts = []
    iteration = 0

    # Phase 1: Decompose into sub-questions
    queries = decompose_question(question)

    while True:
        new_facts_this_round = 0

        for query in queries:
            results = search_web(query, num_results=3)
            for result in results:
                text = fetch_text(result['url'])
                if not text:
                    continue
                facts = extract_facts(text, query, result['url'])
                all_facts.extend(facts)
                new_facts_this_round += len(facts)

        all_facts = deduplicate_facts(all_facts)
        gaps = identify_gaps(question, all_facts)
        iteration += 1

        if not should_continue(gaps, new_facts_this_round, iteration, len(all_facts)):
            break

        queries = gaps  # next iteration searches for the gaps

    return {'facts': all_facts, 'iterations': iteration}

การติดตามที่มาของข้อมูล

ข้อเท็จจริงทุกข้อจะต้องมีที่อยู่เว็บของแหล่งข้อมูลกำกับไว้ เพื่อให้รายงานฉบับสุดท้ายใส่รายการอ้างอิงได้ ห้ามลบข้อมูลเมตาของแหล่งที่มาระหว่างการประมวลผล เพราะจำเป็นต่อชั้นการอ้างอิง

def add_fact(fact_list: list, fact_text: str, source_url: str, iteration: int):
    fact_list.append({
        'fact':      fact_text,
        'source':    source_url,
        'iteration': iteration,
        'verified':  False   # set to True after cross-referencing
    })

# Example:
facts_store = []
add_fact(facts_store, 'Global inflation peaked at 9.1% in June 2022',
         'https://bls.gov/news.release/cpi.htm', iteration=1)

print(f'Logged {len(facts_store)} fact(s):')
for f in facts_store:
    print(f"  - {f['fact']} (source: {f['source']})")

การค้นหาแบบขนานเพื่อเพิ่มความเร็ว

การค้นหาตามลำดับนั้นช้า — คำค้นหา 5 รายการ × ที่อยู่เว็บ 3 แห่ง × การดึงข้อมูลแห่งละ 1 ครั้ง = การเรียกเว็บตามลำดับ 15 ครั้ง ใช้ concurrent.futures เพื่อทำให้การดึงข้อมูลภายในการทำซ้ำแต่ละครั้งทำงานแบบขนาน

from concurrent.futures import ThreadPoolExecutor, as_completed

def parallel_research_round(queries: list[str]) -> list[dict]:
    collected = []

    def process_query(query):
        results = search_web(query, num_results=3)
        facts = []
        for r in results:
            text = fetch_text(r['url'])
            if text:
                facts.extend(extract_facts(text, query, r['url']))
        return facts

    with ThreadPoolExecutor(max_workers=4) as ex:
        futures = {ex.submit(process_query, q): q for q in queries}
        for future in as_completed(futures):
            collected.extend(future.result())

    return collected

การติดตามความคืบหน้าของลูป

บันทึกข้อมูลการทำซ้ำแต่ละครั้งเพื่อให้คุณตรวจสอบได้ว่าเหตุใดลูปจึงหยุดหรือทำงานนานกว่าที่คาดไว้ ให้ระบุจำนวนคำค้นหา จำนวนข้อเท็จจริงที่เพิ่มขึ้น และช่องว่างที่ตรวจพบ

import logging

log = logging.getLogger('research_loop')
import sys
logging.basicConfig(level=logging.INFO, stream=sys.stdout)

def log_iteration(iteration: int, queries: list[str],
                  new_facts: int, total_facts: int, gaps: list[str]):
    log.info(
        'Iteration %d | Queries: %d | New facts: %d | Total: %d | Gaps: %d',
        iteration, len(queries), new_facts, total_facts, len(gaps)
    )
    if gaps:
        for g in gaps:
            log.debug('  Gap query: %s', g)

if __name__ == '__main__':
    log_iteration(iteration=2, queries=['who are our top competitors?'], new_facts=4, total_facts=12, gaps=['pricing data'])

อะไรทำให้ลูปการวิจัยยุติลงเมื่อไม่พบข้อมูลใหม่

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

สรุปการออกแบบลูปการวิจัย

ลูปการวิจัยหลายขั้นตอนทำงานตามลำดับ: แยกย่อย → ค้นหา → อ่าน → แยกข้อมูล → ระบุช่องว่าง → ทำซ้ำ ให้หยุดเมื่อไม่มีช่องว่างเหลือ ไม่พบข้อเท็จจริงใหม่ หรือถึงขีดจำกัดจำนวนการทำซ้ำที่กำหนดไว้

ติดตามที่อยู่เว็บของแหล่งข้อมูลไปพร้อมกับข้อเท็จจริงทุกข้อเสมอ ทำให้การค้นหาเป็นแบบขนานเพื่อเพิ่มความเร็ว และกำจัดข้อเท็จจริงซ้ำก่อนการสังเคราะห์

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

บทเรียน “การออกแบบวงจรการวิจัยหลายขั้นตอน” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การออกแบบวงจรการวิจัยหลายขั้นตอน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การออกแบบวงจรการวิจัยหลายขั้นตอน”

วางแผน → ค้นหา → อ่าน → สกัด → สังเคราะห์ → ทำซ้ำจนได้ความลึกเพียงพอ คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การออกแบบวงจรการวิจัยหลายขั้นตอน” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม

ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การออกแบบวงจรการวิจัยหลายขั้นตอน
  2. การตรวจสอบแหล่งที่มาและการอ้างอิง
  3. การสร้างรายงานแบบมีโครงสร้าง
  4. การตรวจสอบข้อเท็จจริงและการป้องกันการหลอน
← กลับไปที่ AI Agents