NEWS & BLOG

テック

2025.9.12

生成AIで論文を繋ぐ:知識統合が生む「創発」

ブファイマテクノロジーの堀江です。

今回は生成AIを用いた当社の研究内容について、紹介します。
なお今回のメイン研究は当社の佐藤さんが行ってくれています。
テーマはこちらです!

 

「机の上に積まれた論文たちが、もし夜のあいだに内緒でディスカッションを始めて、朝には「ここ、つながってるよ」とメモを残してくれたら——。」

 

これは派手な魔法ではなく、生成AIの技術を用いた「創発(emergence)」です。

 

 

はじめに

近年、科学研究は前例のない速度で進み、論文は爆発的に増え続けています。しかし、知識は分野の壁に閉じこもり、横断的につながらないまま眠っていることが少なくありません。
もし複数の論文を機械的に処理・統合し、論文間の関係性を地図のように浮かび上がらせる仕組みがあったなら——そこから、人間の「気づき」に匹敵する創発(emergence)が生まれる可能性はあるのでしょうか。

 

人間の「気づき」に関する一例を上げます。
私たちが自販機で同じコインが何度も戻ってくると「これは読み取れないコインだ」と自然に悟るように、データの総和を超えた意味の飛躍はたしかに存在します。LLMが単独でこの力を完全に示すのはまだ難しいとしても、膨大な知識を横断的に統合する設計が整えば、創発に等価な力が静かに立ち上がる——本稿はその前提に立ち、複数の論文を対象にした知識統合処理という視点から、「何が課題か」「どう進めるか」「その先に何が起きるか」を整理してご紹介します。

 

1. 背景:論文の増加と知識の断片化

研究の最前線では、特に医学やAI分野を中心に成果が日々更新され、すべてを読み、横断的に理解し続けることは現実的に困難になっています。この状況は、分野ごとに知が積み上がる一方で分野間の接続が見えにくくなるという、いわば「見えない壁」を生みます。例えば、AIの言語モデルと医学の画像診断支援は一見遠い領域に見えますが、学習データの設計や解釈性(Explainability)といった観点では共通する課題と示唆を多く持っています。それでも、論文が個別の山として積み上がるだけでは、隣の山から伸びているはずの橋が見えず、重要なヒントが静かに取りこぼされていきます。

 

2. 共通するアプローチ:知識断片の抽出と再統合

ここからは、具体的にどう手を動かすかをご一緒に見ていきましょう。結論から言うと、やることは「意味の単位でほぐし、意味の単位でつなぐ」です。

  • 抽出: 研究を「背景/課題/方法/結果/考察」に分解し、再利用可能な断片にします。例として「言語モデルの表現安定性」や「医用画像モデルの効率的蒸留」の設計要素を粒度を揃えて取り出します。
  • 正規化: 書誌情報と用語を正規化し、同義語・略語を統合します。断片の粒度とタグ(セクション/対象/評価指標など)を整えます。
  • 表現化: LLMを用いてキーワードではなく文脈に基づく要点抽出を行い、断片に埋め込み(embedding)を付与します。
  • 接続: 近傍探索とクラスタリングで意味的に近い断片を束ね、因果/前提/結果/制約といった関係エッジを付与します。
  • 検証: 反例探索、エビデンス強度のスコアリング、専門家レビューのフックを用意し、過剰一般化を避けます。

 

このプロセスにより、同じテーマがまとまるだけでなく、遠い分野同士の思わぬ橋渡しが生まれます。たとえば小規模LMの表現安定性の示唆と、医用画像の蒸留設計の工夫がつながると、データが限られた環境でも安定して学習できる設計指針が見えてきます。大事なのは、キーワードの一致ではなく、文脈の「息づかい」を捉えることです。

 

3. 創発的効果とは何か?

少し立ち止まって、創発のイメージを共有させてください。創発(emergence)は、個々の断片を足し合わせても出てこない性質が、つなぎ方を工夫した瞬間に現れることです。離れていた領域がふと握手する、名前のなかった仮説が輪郭を帯びる——その源は「関係のつくり方」にあります。量を増やすことより、関係の設計が変わることが、次の一歩の方向を更新します。



4. 技術的な基盤(実装イメージ)

いよいよ実装です。難しく考えすぎず、手順を小さく分けて始めましょう。PDFをテキスト化し、自然なまとまりで分割、セクションの位置づけを明確にします。次に、LLMで意味を抽出し、断片に埋め込み(embedding)を付与して検索・クラスタリング・知識グラフ化につなげます。

加えて、マルチエージェントの「バーチャルディスカッション」で収束点と対立点を洗い出し、引用や根拠のトレースを保ちます。ここでのLLMは「答える装置」ではなく、「関係を生み、人が確かめられる形に整える編集者」として働きます。

科学的研究の自動化における知識統合

 

5. 今後の展望:創発的発見をどう評価するか

AIの活用で評価は大切なところです(そして難しいところです)。なんとなくの手触りの良さだけで判断せず、ひとつの見方に偏らないで、いくつかの視点から確かめます。専門家が文脈の妥当性を確認し、実験・臨床・実装で再現性を検証することに加え、次の点を数値でも見ていきます。

  • 新規リンク比率: 既知関係に対する新規関係の割合
  • 妥当性×新規性: 文献支持の厚みと独自性のバランス
  • 合意率と反証率: 専門家レビューでの一致/不一致の内訳
  • 再現テスト: 異なるコーパス/手順でのリンク再現性
  • 影響度: 意思決定(設計変更・仮説生成)への寄与

 

これらが整ってくるほど、成果はレビュー支援の域を超え、政策づくりや医療プロトコル、環境設計など「説明できて再現できること」が大切な場面にも、自然につながっていきます。

 

まとめ(なぜ、今、知識統合なのか)

最後に「なぜ、今、知識統合なのか」を振り返ります。
先端分野の研究では論文は増え続け、断片のままでは接点が見えません。だからこそ、断片を拾い、意味でつなぎ直し、分野という境界に小さな突破口を作る必要があります。

知識統合とは、単なる要約や効率化ではなく、見えない接点を示唆する試みです。生成AIは、言葉を文言ではなく意味の流れを扱う道具として用いることで、探したいこと、研究したいことを広げていくことができます。

結論

ここまでの話をひとことで言えば ——情報の関係の編集が新しい気づきを呼び込むことができるということです。
複数論文の機械的処理と知識統合は、レビューの迅速化にとどまらず、人の「気づき」に近い創発的な新知を育てます。丁寧な抽出と再統合、そして確かな評価を通じて、研究・開発の現場で、説明できて再現できる判断を後押しできるかもしれません。

 

付録(実装コード例)


import pandas as pd
import streamlit as st
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import FAISS
import openai
import os
import pandas as pd
import streamlit as st
from sklearn.preprocessing import MinMaxScaler
import numpy as np
import datetime
import csv
import codecs
import json
import pytz
from tqdm import tqdm

# 記事を生成
article = []
import os
import boto3
import json
from typing import Dict
from typing import Annotated, List, TypedDict
import operator
#st.write(paper_infos)
SPEAKERS_NAMES = {
    'A子': {"担当論文一覧": "BERT"},
    'B太': {"担当論文一覧": "BERT"}
}

class AppState(TypedDict):
    thema: str
    history: Annotated[List[str], operator.add]
    speak_count: int
    next_speaker: str
    conversation_summary: str
    user_end: bool
    # セッションステートの初期化
    if 'thema' not in st.session_state:
        st.session_state.thema = "与えられた論文をもとにして3つの新しいアイデアを創出してください。"
    if 'history' not in st.session_state:
        st.session_state.history = []
    if 'speak_count' not in st.session_state:
        st.session_state.speak_count = 0
    if 'next_speaker' not in st.session_state:
        st.session_state.next_speaker = None
    if 'conversation_summary' not in st.session_state:
        st.session_state.conversation_summary = ""
    if 'user_end' not in st.session_state:
        st.session_state.user_end = False
    if 'chat_log' not in st.session_state:
        st.session_state.chat_log = []
import random
# Anthropic Model Setup
claude_client = boto3.client(
    "bedrock-runtime", region_name="us-east-1"  # 適切なリージョンを指定
)
def invoke_claude(prompt: str) -> str:
    """
    Claude-3 モデルを呼び出すためのヘルパー関数
    Args:
    prompt (str): モデルへのプロンプト
    Returns:
    str: Claudeからのレスポンス
    """
    bedrock_client = boto3.client(
    "bedrock-runtime",
    region_name="us-east-1"  # 適切なリージョンを指定
)
    # フォーマットに沿ったプロンプトを生成
    prompt = f"""
Human: {prompt}
Assistant:"""
    messages = [
        {"role": "user", "content": [{"text": prompt}]}
    ]
    # Converse APIの呼び出し
    response = bedrock_client.converse(
        modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
        messages=messages,
        inferenceConfig={
            "maxTokens": 1000  # トークンの最大数を設定
        }
    )
    # レスポンスの解析
    assistant_reply = response["output"]["message"]["content"][0]["text"]
    return assistant_reply
def speaker(state: AppState):
    """
    会話の参加者として発言を生成します。
    Args:
    state(AppState): AppState
    Return:
    Dict[str]: 生成した発言
    """
    print("speaker")
    speaker_name = st.session_state.next_speaker
    history = st.session_state.history
    thema = st.session_state.thema
    speak_count = st.session_state.speak_count
    system_message = f"""あなたは次のようなパーソナリティを持った人物です。
    ------------
    {speaker_name}
    ------------
    あなたが担当する論文は以下のとおりです。
    {SPEAKERS_NAMES[speaker_name]["担当論文一覧"]}
    この人物"{speaker_name}"として他の参加者と{thema}について会話をし、全員で結論を出してください。
    """
    human_message_prefix = f"""あなたは今{thema}について他の参加者と会話をし、全員で結論を導くタスクが与えられています。
    これまでの会話の履歴を見て、あなたの{thema}についての意見を自然な短い文体で作成してください。
    ただし、以下の点に留意してください。
    ・各論文の技術的特徴を踏まえてなるべく具体的な意見を述べることも意識してください。
    ・また、情報を捕捉するような会話を心がけてください。
    ・分からないところがあれば、発言の終わりに問いを生み出すようにしてください。
    ・与えられた論文の内容を根拠とした建設的な会話を心がけてください。
    ・良いアイデアが出ている時は実現方法など詳細な議論を深めるようにしてください。
    ・アイデアは一つずつ出して議論を深めてください。
    # 会話の履歴
    """
    print(history)
    human_message = human_message_prefix + "\n".join(history) + f"\n{speaker_name}: "
    response_text = invoke_claude(system_message + "\n" + human_message)
    st.session_state.chat_log.append({"name": speaker_name, "msg": response_text})
    st.session_state.history.append(f"{speaker_name}: {response_text}")
    st.session_state.next_speaker = speaker_name
    st.session_state.speak_count = speak_count + 1
    return {
        "history": [f"{speaker_name}: {response_text}"],
        "speak_count": speak_count + 1
    }
def conversation_manager(state: AppState):
    """
    会話の管理者として次の発言者を決定します。
    Args:
    state(AppState): AppState
    Return:
    Dict[str]: 次の発言者の名前
    """
    print("conversation_manager")
    max_speak_count = 9  # 会話の回数の最大値
    first_speaker_index = 0  # 一番最初の発言者のindex
    speak_count = st.session_state.speak_count
    history = st.session_state.history
    thema = st.session_state.thema
    user_end = st.session_state.user_end
    greeting_msg = f"""司会: 今日は[{thema}]についてのみなさんの活発なご意見を聞かせて下さい!"""
    speakers_names_str = ",".join(SPEAKERS_NAMES .keys())
    if user_end:
        print("no_one")
        st.session_state.next_speaker = "no_one"
        return {"next_speaker": "no_one"}
    # if speak_count == 0:
    #     return {"history": [greeting_msg], "next_speaker": list(SPEAKERS_NAMES[first_speaker_index].keys())[0]}
    system_message = f"""{speakers_names_str}が{thema}についての会話をしています。
    あなたはこの会話を管理する役割を持っています。
    与えられる会話の履歴を読み、次に発言すべき参加者の名前を決定します。"""
    print(speak_count)
    if speak_count%3 != 2:
        human_message = f"""これまでの{thema}についての[{speakers_names_str}]の履歴を見て、
        会話の結論がまとまるまで次に誰が発言すべきかを決めて下さい。
        連続で同じ人に発言させないようにしてください。
        必ず一人2回以上発言させるようにしてください。
        同じような内容の会話が連続しこれ以上会話に変化が見られないと判断した場合は[TERMINATE]と出力してください。
        それ以外は必ず[{speakers_names_str}]のどれかを出力してください。
        # 履歴
        {st.session_state.history}
        次の発言者:
        """
        response_text = invoke_claude(system_message + "\n" + human_message)
        #st.write(response_text)
        generate_text = response_text.split("\n")[0]
        if generate_text in speakers_names_str.split(','):
            st.session_state.next_speaker = generate_text
            return {"next_speaker": generate_text}
        elif "TERMINATE" in generate_text:
            st.session_state.next_speaker ="user"
            return {"next_speaker": "user"}
    else:
        st.session_state.next_speaker ="user"
        return {"next_speaker": "user"}
   
def user_comment(state: AppState):
    print("user")
    speak_count = st.session_state.speak_count
    # チャットログの初期化
    if "chat_log" not in st.session_state:
        st.session_state.chat_log = []
    # 初回の呼び出し時に入力待ちフラグをセット
    if "user_comment_active" not in st.session_state:
        st.session_state.user_comment_active = True
    # ユーザーに質問を表示
    # st.write("ここまでの会話で気になる点はありますか?特になく会話を終わらせる場合は END と入力してください。")
    # 過去のチャットログを表示
    for chat in st.session_state.chat_log:
        with st.chat_message(chat["name"]):
            st.write(chat["msg"])
    # ユーザーに質問を表示
    st.write("ここまでの会話で気になる点はありますか?特になく会話を終わらせる場合は END と入力してください。")
    # ユーザー入力を取得(固定の key を使用)
    comment = st.chat_input("文字を入力してください:", key=f"user_chat_input{speak_count}")
    print(comment)
    # 入力がない場合は `st.stop()` で待機
    if comment is None:
        st.stop()
    # 入力完了後に `user_comment_active` を False にして、入力欄を消す
    st.session_state.user_comment_active = False
    # 入力されたコメントを表示
    USER_NAME = "user"
    with st.chat_message(USER_NAME):
        st.write(comment)
        print(comment)
    # チャットログに追加
    st.session_state.chat_log.append({"name": USER_NAME, "msg": comment})
    # "END" が入力された場合、会話を終了
    if comment == "END":
        st.session_state.user_end = True
        st.session_state.speak_count += 1
        print("end")
        return {"user_end": True, "speak_count": st.session_state.speak_count}
    # セッションの履歴とカウントを更新
    st.session_state.history.append(f"User: {comment}")
    st.session_state.speak_count += 1
    return {"history": [f"User: {comment}"], "speak_count": st.session_state.speak_count}
def conversation_summarizer(state: AppState):
    """
    会話の最後に会話の内容を要約し、インサイトを作成します。
    Args:
    state(AppState)
    Return:
    Dict[str]: 生成した会話から得られるインサイト
    """
    history = st.session_state.history
    thema = st.session_state.thema
    system_message = "あなたは複数人の会話から有益なインサイトを見つけることに長けています。"
    human_message = f"""これまでの"{thema}"についての会話の履歴を見て素人でもわかるように3つの主要なアイデアについてまとめて詳しく説明してください。
    # 履歴
    {st.session_state.history}
    """
    response_text = invoke_claude(system_message + "\n" + human_message)
    #st.write(response_text)
    st.session_state.conversation_summary = response_text
    return {"conversation_summary": response_text}
def next_speaker(state: AppState):
    """
    次の発言者を決めます。
   
    Args:
    state: AppState
    Return:
    str: 次のアクション
    """
    speaker_name = st.session_state.next_speaker
    speakers_names_str = ",".join(SPEAKERS_NAMES .keys())
    print("A")
    print(speaker_name)
    if speaker_name in speakers_names_str.split(','):
        # 次の発言者が指定された場合
        return "continue"
    elif speaker_name == "user":
        return "comment"
    else:
        # 会話が完了した場合
        return "summarize"
## 新しいクエリの作成
new_query = f'''与えられた論文をもとにして3つの新しいアイデアを創出してください。アプリケーションよりも基礎研究よりのアイデアが欲しいです。'''
from langgraph.graph import END, StateGraph
workflow = StateGraph(AppState)
workflow.add_node("conversation_manager", conversation_manager)
workflow.add_node("speaker", speaker)
workflow.add_node("user_comment", user_comment)
workflow.add_node("conversation_summarizer", conversation_summarizer)
workflow.add_conditional_edges(
    "conversation_manager",
    next_speaker,
    {
        "continue": "speaker",
        "comment": "user_comment",
        "summarize": "conversation_summarizer",
    }
)
workflow.add_edge("speaker", "conversation_manager")
workflow.add_edge("user_comment", "conversation_manager")
workflow.add_edge("conversation_summarizer", END)
workflow.set_entry_point("conversation_manager")
group_discussion = workflow.compile()
st.write(group_discussion.get_graph().draw_mermaid())
if "chat_log" not in st.session_state:
    st.session_state.chat_log = []
discussion_history = group_discussion.invoke({
    "thema":f"{new_query}",
    "speak_count": 0,
    "history":[],
    "next_speaker": None,
    "conversation_summary": "",
    "user_end": False
})
print("###history###")
print(discussion_history["history"])
summary = discussion_history["conversation_summary"]
st.write(summary)

 

引用文献

  • Evaluating Generalization and Representation Stability in Small LMs via Prompting, Fine-Tuning and OOD Prompts(arXiv
  • Efficient Knowledge Distillation of SAM for Medical Image Segmentation(arXiv

 

大規模言語モデルは世界中で日々研究が行われており、ファイマテクノロジーでは、お客様のニーズに合わせて業務効率化や生産性向上のソリューション開発を行っています。AIやソフトウェアを活用した業務効率化や生産性向上をご検討中の方は、ぜひファイマテクノロジーにご相談ください。

一覧に戻る一覧に戻る

CONTACT

まずは気軽にご相談ください

問い合わせはこちら

COMPANY

会社名 株式会社Feynma Technology
所在地 〒461-0005
愛知県名古屋市東区東桜1-1-1
アーバンネット名古屋 ネクスタビル内
LIFORK久屋大通
設立 2020年4月1日
代表者 土屋太助
従業員数 8名
事業内容 AI活用のコンサルティングおよび
分析プラットフォームの開発、販売

TOP