讓 LLM 真的會做研究:拆解 ResearchEVO

📌 本文重點

  • ResearchEVO 讓 LLM 直接在程式碼空間做演化搜尋
  • 論文寫作以 sentence-level RAG 確保可檢索與可驗證
  • 可拆解為可落地的 Auto-Research / Auto-ABTest / Auto-Feature-Engineering 流程

多數所謂「AI 做研究」還停留在幫你寫 code、寫報告;ResearchEVO 解決的痛點是:讓 LLM 直接在程式碼空間裡做演化搜尋、自己排實驗、自己寫論文。從工程角度看,它提供了一個可實作的 blueprint,讓你能在公司內做 Auto-Research / Auto-ABTest / Auto-Feature-Engineering,而不是只多一個聊天機器人。


重點說明

1. 演化階段:LLM 驅動的「程式碼空間搜索」

ResearchEVO 的核心是 LLM + 演化算法 操作「程式碼本身」:

  1. 程式碼空間表示
  2. 個體 = 一份可執行程式碼(例如一個 train.py 或一個 model 定義 + config)。
  3. 用 LLM 實作 變異 / 交配
    • 變異:改損失函數、網路結構、優化器、訓練 schedule。
    • 交配:將兩個高適應度方案的關鍵設計融合。
  4. 不做 AST 級別操作也可以,實務上多數情況直接用 自然語言 prompt + code diff 就夠用。

  5. fitness 評估與搜索控制

  6. fitness 只看 metrics:例如 val_accuracyAUClatency
  7. Search loop:
    1. LLM 生成/修改程式碼。
    2. 提交到 GPU/雲端排程系統跑實驗。
    3. 收集結果 → 更新種群 → 再交給 LLM 反思與生成。
  8. 約束控制 避免亂飛:
    • 硬約束:只允許改特定檔案 / 函數;強制保持 I/O 介面不變。
    • 軟約束:LLM prompt 中加入「只動這幾個維度」「保留下列設計」。

💡 關鍵: 把 fitness 完全交給客觀 metrics(如 val_accuracylatency),可以讓 LLM 的創意探索與實際效能緊密對齊。

  1. 對接現有 GPU / 雲端排程
  2. ResearchEVO 本身不是新的 scheduler,而是:
    • 上游:LLM 生成/修改 code & config。
    • 下游:把 job 提交給你已有的 Kubernetes / Slurm / Airflow / SageMaker / Vertex AI
  3. 你只需要做一層 adapter,把 ExperimentSpec → Job 映射好。

2. 寫作階段:sentence-level RAG + 驗證

演化出最佳演算法後,ResearchEVO 的寫作階段是在做 「可檢索、可驗證」的自動論文生成

  1. 論文結構模板
  2. 先固定一個論文 schema(Title / Abstract / Intro / Method / Exp / Discussion / Related Work)。
  3. 每個 section 再細分成 段落 level 的子任務,讓 LLM 聚焦生成。

  4. 句子級 RAG(sentence-level RAG)

  5. 檢索單位不是 chunk,而是句子
    • 實驗 log、表格、程式碼註解、對照文獻都 embed 成 sentence vector。
    • 每當 LLM 要生成一個句子,就檢索最相關的 3~5 個 evidence。
  6. 這樣可以:
    • 降低 context 噪音。
    • 讓每句話都有「引用依據」。

💡 關鍵: 以「句子」為檢索單位,讓每一句論文敘述能精確對應到 3–5 條證據,大幅降低幻覺與錯引。

  1. 事實核查與防幻覺
  2. 對每一句包含數字、claim 的句子,送到 Verifier agent
    • 檢查是否能在實驗結果 / log / paper corpus 中找到支持證據。
    • 找不到就要求 LLM 重寫或改成不那麼強的 claim。
  3. 論文內引用的實驗表格、圖表,ID 必須能對回到真實跑出的 artifacts(例如 MLflow run id / S3 path)。

3. 如何落地 Auto-Research / Auto-ABTest / Auto-Feature-Engineering

你不一定要重現完整 ResearchEVO。實務上可以拆成:

  • 一個 orchestrator(Airflow / Prefect / Dagster / LangGraph)
  • 幾個 LLM agent(code 生成 / 反思 / 寫作)
  • 一個實驗調度器(K8s / Slurm / 自家平台)
  • 一個結果分析工具(MLflow / Weights & Biases / 自製 dashboard)

核心流程:

  1. 目標定義
  2. LLM 生成候選方案
  3. 實驗排程跑
  4. 收集結果 & 自動分析
  5. LLM 反思改進
  6. 收斂後自動產出報告/論文

💡 關鍵: 把「做研究」拆成可編排的 6 步驟流程後,Auto-Research 就變成一組可插拔模組,而不是神秘黑盒。


實作範例

以下用 Python + Airflow/LangGraph 說明一個簡化版 pipeline。

1. 演化 loop 的 code 表示與變異

假設我們把「演算法個體」抽象成一個簡單的 spec:

from pydantic import BaseModel
from typing import Dict, Any

class AlgoSpec(BaseModel):
    name: str
    base_script: str              # 參考模板路徑
    hyperparams: Dict[str, Any]   # 学习率, layer 数等
    patches: str                  # LLM 產生的程式碼 patch (diff-like)

讓 LLM 做「變異」:

SYSTEM_PROMPT = """你是資深 ML 研究員,幫我在保持 I/O 介面不變的前提下,
只修改 loss function、網路架構與訓練策略。輸出 unified diff 格式的 patch。"""

user_msg = f"""
目前的程式碼:
{current_code}

本輪實驗結果:
val_accuracy = {metrics['val_acc']}
train_loss_curve = {metrics['loss_curve'][:10]}

請根據結果給出改進 patch。"""

resp = llm.chat([
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user", "content": user_msg},
])

patch = extract_patch(resp)  # 解析成純文本 diff
new_spec = AlgoSpec(
    name=f"algo_v{gen_id}",
    base_script="templates/train_base.py",
    hyperparams={"lr": 3e-4, "hidden_dim": 512},
    patches=patch,
)

接著用簡單的 patch engine 把 diff 套進檔案,產生下一版 train.py


2. 串接實驗排程(以 K8s Job 為例)

假設有一個內部的 submit_experiment(spec: AlgoSpec) -> str 會幫你:

  1. 打包 code + config 到 image/volume。
  2. 生成 K8s Job yaml。
  3. 提交到 cluster,回傳 job_id

簡化 pseudo-code:

import kubernetes as k8s

def submit_experiment(spec: AlgoSpec) -> str:
    job = build_k8s_job(spec)  # 填入 image, args, resource 限制
    api = k8s.client.BatchV1Api()
    resp = api.create_namespaced_job(namespace="research", body=job)
    return resp.metadata.name

# fitness 評估:等 job 完成,讀取 metrics.json

def fetch_fitness(job_id: str) -> float:
    # 假設每個 job 在 /results/metrics.json 寫入 val_acc
    metrics = load_from_object_store(f"results/{job_id}/metrics.json")
    return metrics["val_acc"]

你只要確保:

  • 所有實驗都寫出 統一格式的 metrics.json / config.json
  • job name、run id 能對應回實驗記錄系統(MLflow、W&B)。

3. Orchestrator:以 LangGraph 為例構建演化 DAG

LangGraph 可以把 LLM、工具、迭代邏輯包成圖:

from langgraph.graph import StateGraph, END

class EvoState(BaseModel):
    population: list[AlgoSpec]
    history: list[dict]
    generation: int


def propose_candidates(state: EvoState) -> EvoState:
    # 用 LLM 對每個 top-k spec 做變異
    ...


def run_experiments(state: EvoState) -> EvoState:
    # 提交所有 candidates,等待完成,回寫 fitness
    ...


def select_and_check_stop(state: EvoState) -> str:
    if state.generation >= MAX_GEN:
        return END
    return "propose"


graph = StateGraph(EvoState)

graph.add_node("propose", propose_candidates)
graph.add_node("run", run_experiments)

graph.add_edge("propose", "run")

graph.add_conditional_edges("run", select_and_check_stop, {"propose": "propose", END: END})

evo_app = graph.compile()

後面你可以在另一個 graph 裡接上 writing phase:以最優 AlgoSpec + 實驗結果為輸入,調用 sentence-level RAG agent 生成報告或論文。


4. sentence-level RAG 實作簡例

from sentence_transformers import SentenceTransformer
from qdrant_client import QdrantClient

encoder = SentenceTransformer("all-mpnet-base-v2")
qdrant = QdrantClient(host="localhost", port=6333)

# 建 index:把實驗 log、表格、文獻拆成句子

def index_sentences(sentences: list[str], meta: list[dict]):
    vecs = encoder.encode(sentences)
    qdrant.upsert(
        collection_name="research_corpus",
        points=[{"id": i, "vector": v, "payload": meta[i]} for i, v in enumerate(vecs)],
    )


def retrieve_evidence(query_sentence: str, k: int = 5):
    qvec = encoder.encode([query_sentence])[0]
    hits = qdrant.search("research_corpus", query_vector=qvec, limit=k)
    return hits

# LLM 每寫一句話前,先取 evidence

claim = "在 QEC 任務上,我們的演算法平均錯誤率降低了 12.3%。"
evidences = retrieve_evidence(claim)
llm_context = format_evidence(evidences)

resp = llm.chat([
    {"role": "system", "content": "根據下面的實驗證據,生成一個對應的結論句。"},
    {"role": "user", "content": llm_context},
])

再加一個 Verifier:重新檢索一次,看 claim 是否可被證據支持,不行就標記為需重寫。


建議與注意事項

1. 實驗結果格式不一致

  • :每個實驗 script 隨意 print,LLM/agent 很難 parse,fitness 評估混亂。
  • 建議
  • 強制所有實驗輸出 統一 schema 的 JSON,例如:
    • metrics.json{"val_acc": 0.92, "train_time": 360}
    • config.json(完整 hyperparams)。
  • schema 驗證(Pydantic)檢查 artifact;不合法就標記這個個體為低適應度。

2. LLM 收斂到壞思路 / mode collapse

  • :LLM 易過度放大小樣本成功設計,反覆微調同一個局部解,失去探索。
  • 建議
  • 搜索策略上引入 探索度控制:族群裡保留一部分「純隨機變異」個體。
  • 每 N 代重啟一次高多樣性的種群(借鑑 evolutionary algo 的 restart 策略)。
  • LLM prompt 中顯式要求「給出三類不同思路」,避免只改超參數。

3. 成本與資源控制

  • :LLM + GPU 雙重成本,很容易跑成燒錢機器。
  • 建議
  • 在 orchestrator 層面設 hard budget:最大世代數、最大 job 數、最大雲端花費。
  • 用低成本模型做日常迭代,大模型只用在 跨世代總結 / 報告撰寫
  • 優先讓 LLM 做 靜態檢查(例如檢查明顯錯誤設計)再送去跑 GPU。

4. LLM 對數據科學工具的錯用

  • :LLM 可能亂用 API(例如 pandas groupby 用錯、Sklearn split 漏掉 stratify),結果漂亮但不可信。
  • 建議
  • 對關鍵 API(train/test split、metrics 計算、cross-validation)儘量做成 封裝好的 utility 函數,禁止 LLM 自己寫這些低級邏輯。
  • 在 pipeline 裡加入 sanity check step
    • label 分布是否合理?
    • baseline 是否被超過?
    • 結果是否疑似 data leakage?

5. 開始時先做「窄版」

  • 不要一開始就做「全自動研究員」。較務實的起點:
  • Auto-ABTest:讓 LLM 只改部分業務策略 / feature 配置,實驗系統沿用現有 AB 平台。
  • Auto-Feature-Engineering:LLM 只負責產生特徵轉換 pipeline(例如 SQL / PySpark),模型訓練沿用既有框架。
  • 寫作階段先只產出 自動實驗報告(非論文),幫團隊省時間。

從工程的角度看,ResearchEVO 真正帶來的啟發是:

把「做研究」拆成可編排的演化搜尋 + sentence-level RAG 寫作兩個 pipeline,然後用現成的 LLM、orchestrator、GPU 排程系統拼起來。

只要你公司已經有基本的實驗平台,做一個自己的「輕量版 ResearchEVO」其實沒有想像中難,但能快速幫你把實驗速度和研究產出拉一個量級。

🚀 你現在可以做的事

  • 先為現有實驗腳本統一輸出 metrics.json / config.json schema,打好 Auto-Research 地基
  • 選一個任務,用一個 LLM agent + 既有 K8s/Slurm 搭出最小可用的演化搜尋 loop
  • 把歷史實驗 log 拆成句子建一個向量索引,試做 sentence-level RAG 自動實驗報告生成

留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *