-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathllm_interface.py
More file actions
108 lines (99 loc) · 3.87 KB
/
Copy pathllm_interface.py
File metadata and controls
108 lines (99 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
from __future__ import annotations
import os
import re
from typing import Optional, Tuple
from .inference import InferenceResult
import json
try:
from openai import OpenAI # new SDK
except Exception:
OpenAI = None # type: ignore
def parse_natural_query(text: str) -> Optional[Tuple[str, str, str]]:
# Very naive patterns for demo purposes
m = re.search(r"Is\s+(\w+)\s+(\w+)\s+of\s+(\w+)[?]?$", text, re.I)
if m:
subj, rel, obj = m.group(1), m.group(2), m.group(3)
# Capitalize relation first letter to match KG labels by default
return (subj, rel[0].upper() + rel[1:].lower(), obj)
# Try explicit triple format: John Grandparent Alice
parts = text.strip().split()
if len(parts) == 3:
return parts[0], parts[1], parts[2]
return None
def narrate_result(res: InferenceResult) -> str:
h, r, t = res.triple
lines = [f"Query: ({h}, {r}, {t})"]
lines.append(f"Probability: {res.probability:.2f}")
if res.supporting_rules:
lines.append("Supported by rules:")
for s in res.supporting_rules[:5]:
lines.append(f" - {s}")
else:
lines.append("No supporting rules fired; probability from priors.")
return "\n".join(lines)
def build_llm_context(
question: str,
res: InferenceResult,
context_weights: list[tuple[int, float]] | None = None,
rule_witnesses: list[str] | None = None,
) -> str:
h, r, t = res.triple
ctx = []
ctx.append("Task: Answer the KG question with calibrated probability and a brief rationale.")
ctx.append("")
ctx.append(f"Question: {question}")
ctx.append(f"KG Query: ({h}, {r}, {t})")
ctx.append(f"Estimated Probability: {res.probability:.3f}")
ctx.append("")
if context_weights:
ctx.append("Context Weights (learned reliabilities):")
for cid, th in sorted(context_weights, key=lambda x: -x[1])[:5]:
ctx.append(f" - context {cid}: theta={th:.3f}")
ctx.append("")
if res.supporting_rules:
ctx.append("Supporting Rules Fired:")
for s in res.supporting_rules[:8]:
ctx.append(f" - {s}")
ctx.append("")
if rule_witnesses:
ctx.append("Example Witnesses (bindings supporting the rules):")
for w in rule_witnesses[:8]:
ctx.append(f" - {w}")
ctx.append("")
ctx.append("Guidelines:")
ctx.append("- Be concise (2-4 sentences).")
ctx.append("- Mention the probability and key rule(s) involved.")
ctx.append("- If rules are weak or absent, note low confidence.")
return "\n".join(ctx)
def llm_wrap_explanation(prompt: str, res: InferenceResult) -> str:
explanation = narrate_result(res)
api_key = os.environ.get("OPENAI_API_KEY")
if api_key and OpenAI is not None:
try:
client = OpenAI(api_key=api_key)
system = (
"You are an assistant explaining knowledge-graph probabilistic reasoning."
)
user = (
f"Question: {prompt}\n\n"
f"Evidence:\n{explanation}\n\n"
f"Explain the probability and key rules in simple terms."
)
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": user},
],
temperature=0.2,
)
return resp.choices[0].message.content or explanation
except Exception:
# Fall back to templated explanation
pass
return (
f"You asked: {prompt}\n\n"
f"Here is an explainable KG answer using probabilistic contexts:\n\n"
f"{explanation}\n\n"
f"Interpretation: Based on mined rules and learned context reliabilities, the system combines evidence with a Noisy-OR model to estimate the probability."
)