信頼度推定、自己評価、自動ウェブ調査を備えた不確実性認識LLMシステムの構築実装
MarkTechPostは、信頼性スコアの自己評価と自動ウェブ検索を組み込んだ不確実性認識型大規模言語モデルシステムの実装チュートリアルを公開し、AIシステムの信頼性と透明性向上の実践的フレームワークを提案している。
キーポイント
三段階推論パイプラインの実装
回答生成、自己報告型信頼度スコアと正当化の提供、自己評価による回答の批判と精緻化を行う三段階の推論プロセスを実装している。
信頼度に基づく自動ウェブ研究のトリガー
モデルが自身の信頼度が低いと判断した場合、ライブソースから関連情報を取得し、より信頼性の高い回答を合成する自動ウェブ研究フェーズを起動する。
信頼性と透明性向上の実践的フレームワーク
信頼度推定、自己内省、自動化された研究を組み合わせることで、不確実性を認識し積極的に優れた情報を求めることができる、より信頼性が高く透明性のあるAIシステム構築の実用的枠組みを提供している。
具体的なコード実装と環境設定
OpenAI APIキーの安全な取得、LLMResponseデータ構造の定義、信頼度閾値の設定など、実際に動作するシステムの実装コードと環境設定を詳細に示している。
自己評価機能の実装
LLMの回答に対して論理的一貫性や信頼度の適切性を評価するself_evaluate関数を定義し、批判的レビューを通じて信頼度や回答内容を改善する仕組みを実装している。
構造化された出力フォーマット
システムがJSON形式でのみ応答するよう強制し、回答、信頼度、推論理由を含む標準化された出力を確保している。
自己評価による信頼度調整
LLMが自身の回答を批判的にレビューし、論理的一貫性や事実誤りをチェックして、必要に応じて信頼度と回答を修正する機能を実装している。
影響分析・編集コメントを表示
影響分析
この記事は、単なる理論的な提案ではなく実際に動作するコード実装を提供しており、LLMの信頼性問題に対する実践的な解決策を示している点で重要である。不確実性を認識し自己修正するAIシステムの構築手法は、医療、金融、法律など高信頼性が要求される分野へのLLM応用を促進する可能性がある。
編集コメント
理論だけでなく実際のコード実装まで詳細に解説している点が実践的で価値が高い。信頼度スコアの閾値設定(CONFIDENCE_LOW=0.55など)といった具体的な実装上の工夫も参考になる。
このチュートリアルでは、回答を生成するだけでなく、その回答に対する信頼度を推定する不確実性認識大規模言語モデルシステムを構築します。3段階の推論パイプラインを実装します。まずモデルが回答と自己申告による信頼度スコア、およびその根拠を生成します。次に、モデルが自身の回答を批判し改良することを可能にする自己評価ステップを導入し、メタ認知的チェックをシミュレートします。モデルが自身の信頼度が低いと判断した場合、ライブソースから関連情報を取得し、より信頼性の高い回答を統合するウェブ検索フェーズを自動的にトリガーします。信頼度推定、自己内省、自動化された調査を組み合わせることで、不確実性を認識し、積極的に優れた情報を求めることができる、より信頼性が高く透明性のあるAIシステムを構築するための実用的なフレームワークを作成します。
必要なすべてのライブラリをインポートし、不確実性認識LLMパイプラインのランタイム環境を設定します。環境変数、Colabシークレット、または非表示のターミナルプロンプトを使用してOpenAI APIキーを安全に取得します。また、システム全体で使用される質問、回答、信頼度スコア、推論、および調査メタデータを格納するLLMResponseデータ構造を定義します。
モデルに較正された信頼度と推論とともに回答を報告するように指示するシステムプロンプトを定義します。次に、パイプラインの第1段階を実行するquery_llm_with_confidence関数を実装します。この段階では、回答、信頼度スコア、説明を含む構造化JSONを出力することを強制しながら、モデルの回答を生成します。
モデルが自身の回答を批判し、必要に応じて信頼度を修正する自己評価段階を実装します。また、DuckDuckGoを使用してライブ情報を取得するウェブ検索機能を導入します。モデルの信頼度が低い場合、検索結果を暫定回答と統合し、外部エビデンスに基づいた改良された応答を生成します。
def web_search(query: str, max_results: int = 5) -> list[dict]:
results = DDGS().text(query, max_results=max_results)
return list(results) if results else []
def research_and_synthesize(response: LLMResponse) -> LLMResponse:
console.print(f" [yellow]
image 信頼度 {response.confidence:.0%} が低いため、自動調査を開始します...[/yellow]")
snippets = web_search(response.question)
if not snippets:
console.print(" [red]検索結果が見つかりませんでした。[/red]")
return response
formatted = "\n\n".join(
f"[{i+1}] {s.get('title','')}\n{s.get('body','')}\nURL: {s.get('href','')}"
for i, s in enumerate(snippets)
)
synthesis_prompt = f"""
質問: {response.question}
暫定回答(低信頼度): {response.answer}
ウェブ検索スニペット:
{formatted}
上記のエビデンスを使用して改善された回答を統合してください。
""".strip()
completion = client.chat.completions.create(
model=MODEL,
temperature=0.2,
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": SYSTEM_SYNTHESIS},
{"role": "user", "content": synthesis_prompt},
],
)
syn = json.loads(completion.choices[0].message.content)
response.answer = syn.get("answer", response.answer)
response.confidence = float(syn.get("confidence", response.confidence))
response.reasoning += f"\n\n[調査後]: {syn.get('reasoning', '')}"
response.sources = [s.get("href", "") for s in snippets if s.get("href")]
response.researched = True
return response
回答生成、自己評価、オプションの調査を調整する主要な推論パイプラインを構築します。視覚的な信頼度インジケーターを計算し、信頼度レベルをラベル付けするヘルパー関数を実装します。また、最終的な回答、推論、信頼度メーター、ソースをクリーンなコンソールインターフェースで表示するフォーマットされた表示システムも構築しました。
Copy CodeCopiedUse a different Browser
DEMO_QUESTIONS = [
"真空中の光の速度は何ですか?",
"2008年の世界的金融危機の主な原因は何でしたか?",
"2025年にリリースされたPythonの最新バージョンは何ですか?",
"2025年現在の東京の人口は何人ですか?",
]
def run_comparison_table(questions: list[str]) -> None:
console.rule("[bold cyan]不確実性認識LLM — バッチ実行[/bold cyan]")
results = []
for i, q in enumerate(questions, 1):
console.print(f"\n[bold]質問 {i}/{len(questions)}:[/bold] {q}")
r = uncertainty_aware_query(q)
display_response(r)
results.append(r)
console.rule("[bold cyan]サマリーテーブル[/bold cyan]")
tbl = Table(box=box.ROUNDED, show_lines=True, highlight=True)
tbl.add_column("#", style="dim", width=3)
tbl.add_column("質問", max_width=40)
tbl.add_column("信頼度", justify="center", width=12)
tbl.add_column("レベル", justify="center", width=10)
tbl.add_column("調査済み", justify="center", width=10)
for i, r in enumerate(results, 1):
emoji, label = confidence_label(r.confidence)
col = "green" if r.confidence >= 0.75 else "yellow" if r.confidence >= 0.55 else "red"
tbl.add_row(
str(i),
textwrap.shorten(r.question, 55),
f"[{col}]{r.confidence:.0%}[/{col}]",
f"{emoji} {label}",
"
image はい" if r.researched else "—",
)
console.print(tbl)
def interactive_mode() -> None:
console.rule("[bold cyan]インタラクティブモード[/bold cyan]")
console.print(" 任意の質問を入力してください。[bold]quit[/bold]と入力すると終了します。\n")
while True:
q = console.input("[bold cyan]あなた
image[/bold cyan] ").strip()
if q.lower() in ("quit", "exit", "q"):
console.print("さようなら!")
break
if not q:
continue
resp = uncertainty_aware_query(q)
display_response(resp)
if __name__ == "__main__":
console.print(Panel(
"[bold white]不確実性認識LLMチュートリアル[/bold white]\n"
"[dim]信頼度推定 · 自己評価 · 自動調査[/dim]",
border_style="cyan",
expand=False,
))
run_comparison_table(DEMO_QUESTIONS)
console.print("\n")
interactive_mode()
デモンストレーション質問を定義し、複数のクエリにわたって不確実性認識システムを評価するバッチパイプラインを実装します。信頼度レベルと調査がトリガーされたかどうかを比較するサマリーテーブルを生成します。最後に、ユーザーの質問を継続的に受け付け、完全な不確実性認識推論ワークフローを実行するインタラクティブモードを実装します。
結論として、PythonとOpenAI APIを使用して、大規模言語モデル向けの完全な不確実性認識推論パイプラインを設計および実装しました。モデルが信頼度を言語化し、内部的な自己評価を実行し、不確実性が検出されたときに自動的に調査を実施する方法を実証しました。このアプローチは、システムが知識のギャップを認識し、必要に応じて外部のエビデンスで回答を補強できるようにすることで、信頼性を向上させます。これらのコンポーネントを統一されたワークフローに統合することにより、開発者が知的で、較正され、透明性があり、適応性のあるAIシステムを構築する方法を示しました。これにより、実世界の意思決定支援アプリケーションにはるかに適したものになります。
完全なノートブックはこちらでご覧ください。また、Twitterでフォローすることをお勧めします。120k以上のML SubRedditに参加し、ニュースレターを購読することをお忘れなく。待ってください!Telegramをご利用ですか?今すぐTelegramでも参加できます。
この投稿「信頼度推定、自己評価、自動ウェブ検索を備えた不確実性認識LLMシステムの構築」は、MarkTechPostで最初に公開されました。
原文を表示
In this tutorial, we build an uncertainty-aware large language model system that not only generates answers but also estimates the confidence in those answers. We implement a three-stage reasoning pipeline in which the model first produces an answer along with a self-reported confidence score and a justification. We then introduce a self-evaluation step that allows the model to critique and refine its own response, simulating a meta-cognitive check. If the model determines that its confidence is low, we automatically trigger a web research phase that retrieves relevant information from live sources and synthesizes a more reliable answer. By combining confidence estimation, self-reflection, and automated research, we create a practical framework for building more trustworthy and transparent AI systems that can recognize uncertainty and actively seek better information.
Copy CodeCopiedUse a different Browser
import os, json, re, textwrap, getpass, sys, warnings
from dataclasses import dataclass, field
from typing import Optional
from openai import OpenAI
from ddgs import DDGS
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich import box
warnings.filterwarnings("ignore", category=DeprecationWarning)
def _get_api_key() -> str:
key = os.environ.get("OPENAI_API_KEY", "").strip()
if key:
return key
try:
from google.colab import userdata
key = userdata.get("OPENAI_API_KEY") or ""
if key.strip():
return key.strip()
except Exception:
pass
console = Console()
console.print(
"\n[bold cyan]OpenAI API Key required[/bold cyan]\n"
"[dim]Your key will not be echoed and is never stored to disk.\n"
"To skip this prompt in future runs, set the environment variable:\n"
" export OPENAI_API_KEY=sk-...[/dim]\n"
)
key = getpass.getpass(" Enter your OpenAI API key: ").strip()
if not key:
Console().print("[bold red]No API key provided — exiting.[/bold red]")
sys.exit(1)
return key
OPENAI_API_KEY = _get_api_key()
MODEL = "gpt-4o-mini"
CONFIDENCE_LOW = 0.55
CONFIDENCE_MED = 0.80
client = OpenAI(api_key=OPENAI_API_KEY)
console = Console()
@dataclass
class LLMResponse:
question: str
answer: str
confidence: float
reasoning: str
sources: list[str] = field(default_factory=list)
researched: bool = False
raw_json: dict = field(default_factory=dict)
We import all required libraries and configure the runtime environment for the uncertainty-aware LLM pipeline. We securely retrieve the OpenAI API key using environment variables, Colab secrets, or a hidden terminal prompt. We also define the LLMResponse data structure that stores the question, answer, confidence score, reasoning, and research metadata used throughout the system.
Copy CodeCopiedUse a different Browser
SYSTEM_UNCERTAINTY = """
You are an expert AI assistant that is HONEST about what it knows and doesn't know.
For every question you MUST respond with valid JSON only (no markdown, no prose outside JSON):
{
"answer": "<your best answer — thorough, factual>",
"confidence": <float 0.0-1.0>,
"reasoning": "<explain WHY you are or aren't confident; mention specific knowledge gaps>"
}
Confidence scale:
0.90-1.00 → very high: well-established fact, you are certain
0.75-0.89 → high: strong knowledge, minor uncertainty
0.55-0.74 → medium: plausible but you may be wrong, could be outdated
0.30-0.54 → low: significant uncertainty, answer is a best guess
0.00-0.29 → very low: mostly guessing, minimal reliable knowledge
Be CALIBRATED — do not always give high confidence. Genuinely reflect uncertainty
about recent events (after your knowledge cutoff), niche topics, numerical claims,
and anything that changes over time.
""".strip()
SYSTEM_SYNTHESIS = """
You are a research synthesizer. Given a question, a preliminary answer,
and web-search snippets, produce an improved final answer grounded in the evidence.
Respond in JSON only:
{
"answer": "<improved, evidence-grounded answer>",
"confidence": <float 0.0-1.0>,
"reasoning": "<explain how the search evidence changed or confirmed the answer>"
}
""".strip()
def query_llm_with_confidence(question: str) -> LLMResponse:
completion = client.chat.completions.create(
model=MODEL,
temperature=0.2,
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": SYSTEM_UNCERTAINTY},
{"role": "user", "content": question},
],
)
raw = json.loads(completion.choices[0].message.content)
return LLMResponse(
question=question,
answer=raw.get("answer", ""),
confidence=float(raw.get("confidence", 0.5)),
reasoning=raw.get("reasoning", ""),
raw_json=raw,
)
We define the system prompts that instruct the model to report answers along with calibrated confidence and reasoning. We then implement the query_llm_with_confidence function that performs the first stage of the pipeline. This stage generates the model’s answer while forcing the output to be structured JSON containing the answer, confidence score, and explanation.
Copy CodeCopiedUse a different Browser
def self_evaluate(response: LLMResponse) -> LLMResponse:
critique_prompt = f"""
Review this answer and its stated confidence. Check for:
- Logical consistency
- Whether the confidence matches the actual quality of the answer
- Any factual errors you can spot
Question: {response.question}
Proposed answer: {response.answer}
Stated confidence: {response.confidence}
Stated reasoning: {response.reasoning}
Respond in JSON:
{{
"revised_confidence": <float — adjust if the self-check changes your view>,
"critique": "<brief critique of the answer quality>",
"revised_answer": "<improved answer, or repeat original if fine>"
}}
""".strip()
completion = client.chat.completions.create(
model=MODEL,
temperature=0.1,
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": "You are a rigorous self-critic. Respond in JSON only."},
{"role": "user", "content": critique_prompt},
],
)
ev = json.loads(completion.choices[0].message.content)
response.confidence = float(ev.get("revised_confidence", response.confidence))
response.answer = ev.get("revised_answer", response.answer)
response.reasoning += f"\n\n[Self-Eval Critique]: {ev.get('critique', '')}"
return response
def web_search(query: str, max_results: int = 5) -> list[dict]:
results = DDGS().text(query, max_results=max_results)
return list(results) if results else []
def research_and_synthesize(response: LLMResponse) -> LLMResponse:
console.print(f" [yellow]
image Confidence {response.confidence:.0%} is low — triggering auto-research...[/yellow]")
snippets = web_search(response.question)
if not snippets:
console.print(" [red]No search results found.[/red]")
return response
formatted = "\n\n".join(
f"[{i+1}] {s.get('title','')}\n{s.get('body','')}\nURL: {s.get('href','')}"
for i, s in enumerate(snippets)
)
synthesis_prompt = f"""
Question: {response.question}
Preliminary answer (low confidence): {response.answer}
Web search snippets:
{formatted}
Synthesize an improved answer using the evidence above.
""".strip()
completion = client.chat.completions.create(
model=MODEL,
temperature=0.2,
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": SYSTEM_SYNTHESIS},
{"role": "user", "content": synthesis_prompt},
],
)
syn = json.loads(completion.choices[0].message.content)
response.answer = syn.get("answer", response.answer)
response.confidence = float(syn.get("confidence", response.confidence))
response.reasoning += f"\n\n[Post-Research]: {syn.get('reasoning', '')}"
response.sources = [s.get("href", "") for s in snippets if s.get("href")]
response.researched = True
return response
We implement a self-evaluation stage in which the model critiques its own answer and revises its confidence as needed. We also introduce the web search capability that retrieves live information using DuckDuckGo. If the model’s confidence is low, we synthesize the search results with the preliminary answer to produce an improved response grounded in external evidence.
Copy CodeCopiedUse a different Browser
def self_evaluate(response: LLMResponse) -> LLMResponse:
critique_prompt = f"""
Review this answer and its stated confidence. Check for:
- Logical consistency
- Whether the confidence matches the actual quality of the answer
- Any factual errors you can spot
Question: {response.question}
Proposed answer: {response.answer}
Stated confidence: {response.confidence}
Stated reasoning: {response.reasoning}
Respond in JSON:
{{
"revised_confidence": <float — adjust if the self-check changes your view>,
"critique": "<brief critique of the answer quality>",
"revised_answer": "<improved answer, or repeat original if fine>"
}}
""".strip()
completion = client.chat.completions.create(
model=MODEL,
temperature=0.1,
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": "You are a rigorous self-critic. Respond in JSON only."},
{"role": "user", "content": critique_prompt},
],
)
ev = json.loads(completion.choices[0].message.content)
response.confidence = float(ev.get("revised_confidence", response.confidence))
response.answer = ev.get("revised_answer", response.answer)
response.reasoning += f"\n\n[Self-Eval Critique]: {ev.get('critique', '')}"
return response
def web_search(query: str, max_results: int = 5) -> list[dict]:
results = DDGS().text(query, max_results=max_results)
return list(results) if results else []
def research_and_synthesize(response: LLMResponse) -> LLMResponse:
console.print(f" [yellow]
image Confidence {response.confidence:.0%} is low — triggering auto-research...[/yellow]")
snippets = web_search(response.question)
if not snippets:
console.print(" [red]No search results found.[/red]")
return response
formatted = "\n\n".join(
f"[{i+1}] {s.get('title','')}\n{s.get('body','')}\nURL: {s.get('href','')}"
for i, s in enumerate(snippets)
)
synthesis_prompt = f"""
Question: {response.question}
Preliminary answer (low confidence): {response.answer}
Web search snippets:
{formatted}
Synthesize an improved answer using the evidence above.
""".strip()
completion = client.chat.completions.create(
model=MODEL,
temperature=0.2,
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": SYSTEM_SYNTHESIS},
{"role": "user", "content": synthesis_prompt},
],
)
syn = json.loads(completion.choices[0].message.content)
response.answer = syn.get("answer", response.answer)
response.confidence = float(syn.get("confidence", response.confidence))
response.reasoning += f"\n\n[Post-Research]: {syn.get('reasoning', '')}"
response.sources = [s.get("href", "") for s in snippets if s.get("href")]
response.researched = True
return response
We construct the main reasoning pipeline that orchestrates answer generation, self-evaluation, and optional research. We compute visual confidence indicators and implement helper functions to label their confidence levels. We also built a formatted display system that presents the final answer, reasoning, confidence meter, and sources in a clean console interface.
Copy CodeCopiedUse a different Browser
DEMO_QUESTIONS = [
"What is the speed of light in a vacuum?",
"What were the main causes of the 2008 global financial crisis?",
"What is the latest version of Python released in 2025?",
"What is the current population of Tokyo as of 2025?",
]
def run_comparison_table(questions: list[str]) -> None:
console.rule("[bold cyan]UNCERTAINTY-AWARE LLM — BATCH RUN[/bold cyan]")
results = []
for i, q in enumerate(questions, 1):
console.print(f"\n[bold]Question {i}/{len(questions)}:[/bold] {q}")
r = uncertainty_aware_query(q)
display_response(r)
results.append(r)
console.rule("[bold cyan]SUMMARY TABLE[/bold cyan]")
tbl = Table(box=box.ROUNDED, show_lines=True, highlight=True)
tbl.add_column("#", style="dim", width=3)
tbl.add_column("Question", max_width=40)
tbl.add_column("Confidence", justify="center", width=12)
tbl.add_column("Level", justify="center", width=10)
tbl.add_column("Researched", justify="center", width=10)
for i, r in enumerate(results, 1):
emoji, label = confidence_label(r.confidence)
col = "green" if r.confidence >= 0.75 else "yellow" if r.confidence >= 0.55 else "red"
tbl.add_row(
str(i),
textwrap.shorten(r.question, 55),
f"[{col}]{r.confidence:.0%}[/{col}]",
f"{emoji} {label}",
"
image Yes" if r.researched else "—",
)
console.print(tbl)
def interactive_mode() -> None:
console.rule("[bold cyan]INTERACTIVE MODE[/bold cyan]")
console.print(" Type any question. Type [bold]quit[/bold] to exit.\n")
while True:
q = console.input("[bold cyan]You
image[/bold cyan] ").strip()
if q.lower() in ("quit", "exit", "q"):
console.print("Goodbye!")
break
if not q:
continue
resp = uncertainty_aware_query(q)
display_response(resp)
if __name__ == "__main__":
console.print(Panel(
"[bold white]Uncertainty-Aware LLM Tutorial[/bold white]\n"
"[dim]Confidence Estimation · Self-Evaluation · Auto-Research[/dim]",
border_style="cyan",
expand=False,
))
run_comparison_table(DEMO_QUESTIONS)
console.print("\n")
interactive_mode()
We define demonstration questions and implement a batch pipeline that evaluates the uncertainty-aware system across multiple queries. We generate a summary table that compares confidence levels and whether research was triggered. Finally, we implement an interactive mode that continuously accepts user questions and runs the full uncertainty-aware reasoning workflow.
In conclusion, we designed and implemented a complete uncertainty-aware reasoning pipeline for large language models using Python and the OpenAI API. We demonstrated how models can verbalize confidence, perform internal self-evaluation, and automatically conduct research when uncertainty is detected. This approach improves reliability by enabling the system to acknowledge knowledge gaps and augment its answers with external evidence when needed. By integrating these components into a unified workflow, we showed how developers can build AI systems that are intelligent, calibrated, transparent, and adaptive, making them far more suitable for real-world decision-support applications.
Check out the FULL Notebook Here. Also, feel free to follow us on Twitter and don’t forget to join our 120k+ ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.
The post A Coding Implementation to Build an Uncertainty-Aware LLM System with Confidence Estimation, Self-Evaluation, and Automatic Web Research appeared first on MarkTechPost.
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み