Repository navigation
Expand file tree
/
Copy pathlearning.py
More file actions
113 lines (92 loc) · 4.82 KB
/
Copy pathlearning.py
File metadata and controls
113 lines (92 loc) · 4.82 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
109
110
111
112
113
"""An observable, narrated execution of the support copilot."""
import argparse
from pathlib import Path
from mellea import start_session
from support_copilot.facts import extract_order_ids
from support_copilot.mellea_program import ReplyValidationError, analyze_ticket, draft_reply
from support_copilot.models import SupportTicket
from support_copilot.policy import decide_route
def pause(enabled: bool) -> None:
if enabled:
input("\nPress Enter to run this stage...")
def heading(number: int, title: str) -> None:
print(f"\n{'=' * 72}\nSTAGE {number}: {title}\n{'=' * 72}")
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Learn Mellea by observing each pipeline stage")
parser.add_argument("ticket", type=Path)
parser.add_argument("--backend", default="ollama")
parser.add_argument("--model", default=None)
parser.add_argument("--no-pause", action="store_true")
return parser
def main() -> None:
args = build_parser().parse_args()
should_pause = not args.no_pause
ticket = SupportTicket.model_validate_json(args.ticket.read_text())
heading(0, "THE PROGRAMMING BOUNDARY")
print(
"A normal Python program is deterministic; an LLM call is not.\n"
"This workshop crosses that boundary twice and contains it each time.\n\n"
f"Deterministic input object ({type(ticket).__name__}):\n{ticket.model_dump_json(indent=2)}\n\n"
f"Order IDs extracted directly from source text: {list(extract_order_ids(ticket.as_text()).values())}\n"
"Identifiers have rigid syntax, so Python—not the LLM—is their source of truth."
)
session_args = {"backend_name": args.backend}
if args.model:
session_args["model_id"] = args.model
with start_session(**session_args) as session:
heading(1, "TYPED GENERATIVE FUNCTION")
print(
"analyze_ticket() has no Python implementation—its body is `...`.\n"
"Mellea builds an instruction from its name, parameter, docstring, and return type.\n"
"The model may vary its raw tokens, but Mellea must return a TicketAnalysis."
)
pause(should_pause)
analysis = analyze_ticket(session, ticket_text=ticket.as_text())
print(f"\nReturned Python type: {type(analysis).__name__}")
print(analysis.model_dump_json(indent=2))
print("\nTAKEAWAY: types constrain shape. They do not guarantee factual correctness.")
heading(2, "DETERMINISTIC BUSINESS POLICY")
print(
"The LLM interpreted the ticket. It must not approve money, choose hidden policy,\n"
"or silently decide whether a human is required. Plain Python now does that."
)
pause(should_pause)
decision = decide_route(analysis)
print(f"\nNo model was called. decide_route() returned:\n{decision.model_dump_json(indent=2)}")
print("\nTAKEAWAY: use generation for interpretation; use code for auditable rules.")
heading(3, "INSTRUCT → VALIDATE → REPAIR (IVR)")
print(
"The second model call drafts natural language. Deterministic requirements\n"
"check every attempt. On failure, Mellea feeds the reason back and tries again,\n"
"up to the configured sampling budget. Watch the checks below."
)
pause(should_pause)
validation_number = 0
def show_validation(name: str, passed: bool, reason: str) -> None:
nonlocal validation_number
validation_number += 1
marker = "PASS" if passed else "FAIL → repair feedback"
print(f" check {validation_number:02}: [{marker}] {name}: {reason}")
try:
reply = draft_reply(session, ticket, analysis, decision, observer=show_validation)
except ReplyValidationError as error:
print("\nREJECTED: the retry budget was exhausted. Nothing was approved.")
print(f"Attempts: {error.attempts}")
print("Remaining failures:")
for reason in error.reasons:
print(f" - {reason}")
print(f"\nQuarantined candidate (for debugging only):\n\n{error.candidate}")
else:
print(f"\nVALIDATED reply:\n\n{reply}")
heading(4, "WHAT MELLEA CONTRIBUTED")
print(
"1. A model-backed function with a normal typed Python interface.\n"
"2. Structured parsing into TicketAnalysis.\n"
"3. Requirements that are prompt guidance AND executable checks.\n"
"4. A bounded repair strategy—and an explicit failure when its budget is exhausted.\n"
"5. An explicit Session that owns the model backend and context.\n\n"
"Next: open LEARNING_PATH.md and do Lab 1. The labs make you change the code,\n"
"predict the result, and verify the prediction."
)
if __name__ == "__main__":
main()