会話の検索で「Friday」が見つかっても、それだけで納期を確定扱いにはできません。条件の付いた発言を、次のAgentへどう渡すか。自分の英語の記事で書いた例を、Pythonで動く小さな確認処理にしてみました。
私はMemoketの共同創業者兼CTOです。この記事のコードは説明用の架空データを扱う独立した例で、Memoketの製品APIや実装済みメモリスキーマではありません。標準ライブラリだけで実行でき、録音、MCP、LLMへのアクセスは行いません。
何を取り違えたくないか
月曜日に、次のような発言があったとします。
We can deliver on Friday, if the client approves the revised scope.
残したいのはFridayという文字列だけではなく、対象の顧客、提案の版、承認という条件、元の記録です。さらに、スコープの承認と、納期を確約した記録も分けます。承認が見つからないことを、承認されていない証拠として扱わない点も大切です。
図は説明用です。アプリ画面や自動抽出の実測ではありません。
入力を決めて、確認を段階に分ける
この例では、会話から必要な項目を正しく構造化できた後を扱います。確認するのは次の順番です。
- 依頼対象の顧客が特定され、候補の顧客と一致するか。
- 候補の発言に出典が付いているか。
- 同じ顧客・提案・スコープ版を対象とする承認記録があるか。
- その承認と区別できる納期確認の記録があり、日付も候補と一致するか。
sourceは架空の参照文字列です。文字列があるだけで引用内容の正しさを保証できるわけではなく、実システムでは元の記録を開いて確認する工程が別に必要です。
実行例
以下をconditional_handoff.pyに保存し、python3 conditional_handoff.pyで実行できます。入力例と出力は英語にしています。
"""Fictional, manually structured records; no model, MCP or product API calls."""
import json
proposal = {
"client_id": "maple",
"proposal_id": "delivery-1",
"scope_revision": "v2",
"candidate_date": "Friday",
"source": "fictional:monday-conversation",
}
def matches(record, candidate, expected_kind):
keys = ("client_id", "proposal_id", "scope_revision")
return bool(record and record.get("source") and
record.get("kind") == expected_kind and
all(record.get(k) == candidate[k] for k in keys))
def review(client_id, candidate, approval=None, commitment=None):
if not client_id or client_id != candidate["client_id"]:
return "client_unresolved"
if not candidate.get("source"):
return "proposal_source_missing"
if not matches(approval, candidate, "scope_approval"):
return "approval_evidence_unverified"
if (not matches(commitment, candidate, "delivery_confirmation") or
commitment.get("date") != candidate["candidate_date"]):
return "approval_recorded_commitment_unverified"
return "matching_approval_and_commitment_records_found"
approval = {**proposal, "kind": "scope_approval",
"source": "fictional:approval-message"}
commitment = {**proposal, "kind": "delivery_confirmation", "date": "Friday",
"source": "fictional:delivery-confirmation"}
cases = [
("unknown client", None, proposal, None, None),
("no approval record", "maple", proposal, None, None),
("approval for old scope", "maple", proposal,
{**approval, "scope_revision": "v1"}, None),
("approval only", "maple", proposal, approval, None),
("approval reused as commitment", "maple", proposal, approval, approval),
("different delivery date", "maple", proposal, approval,
{**commitment, "date": "Next Monday"}),
("both records", "maple", proposal, approval, commitment),
]
for name, client, candidate, approved, committed in cases:
print(json.dumps({"case": name,
"state": review(client, candidate, approved, committed)}))
実行した出力です。
{"case": "unknown client", "state": "client_unresolved"}
{"case": "no approval record", "state": "approval_evidence_unverified"}
{"case": "approval for old scope", "state": "approval_evidence_unverified"}
{"case": "approval only", "state": "approval_recorded_commitment_unverified"}
{"case": "approval reused as commitment", "state": "approval_recorded_commitment_unverified"}
{"case": "different delivery date", "state": "approval_recorded_commitment_unverified"}
{"case": "both records", "state": "matching_approval_and_commitment_records_found"}
承認だけがある場合はapproval_recorded_commitment_unverifiedです。同じ承認レコードを納期確認の代わりに渡しても、kindが違うので通りません。納期確認の記録が別の日付を指している場合も、確認済みの扱いに進めません。
最後のmatching_approval_and_commitment_records_foundは、与えた項目が一致する2種類の記録を見つけた、という意味です。現実の納期が確定していると証明したわけではありません。
このコードで確認していないこと
自然言語からの抽出が正しいか、顧客IDの対応付けが正しいか、記録にアクセスする権限があるか、後から取消や変更があったかは扱っていません。入力を作る処理の評価や、後続の記録との照合は別です。
小さな例ですが、「取り出せた文章」と「いま判断に使える前提」の間に、どの確認が残っているかを明示できます。MCPの接続ができた後も、その境界を残しておきたいと思っています。
英語版のChatGPT例では、複数会議から懸念の候補は拾えましたが、どの顧客かは一意に特定できていませんでした。したがって、この例の最初の確認も省略できません。ここで新たにChatGPTやMemoketの実アカウントを使った検証はしていません。
背景となる原文:You Have Become Your AI Assistant’s Memory
コードの作成、確認、文章の編集にはAIアシスタントを使用しています。
