-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode.py
More file actions
73 lines (59 loc) · 2.51 KB
/
Copy pathcode.py
File metadata and controls
73 lines (59 loc) · 2.51 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
"""Planning — decide the whole sequence of steps before executing any of them.
Different from prompt chaining: there the steps are hardcoded by you, here the
model designs the step list at runtime based on the goal. That is the tradeoff
- flexibility for unpredictability.
The plan is data (a JSON list), which is what makes it inspectable, editable,
and replayable before you spend tokens executing it.
"""
from langchain_core.prompts import ChatPromptTemplate
from resources.agent import llm
from resources.helper import parse_json, show_response
GOAL = (
"Migrate a small Flask app from SQLite to PostgreSQL without downtime "
"for its ~500 daily users."
)
plan_prompt = ChatPromptTemplate.from_template(
"Break this goal into 4-6 ordered, concrete steps.\n"
'Reply with a JSON array of objects: [{{"step": 1, "action": "...", '
'"why": "..."}}]\n'
"JSON only, no markdown fences.\n\nGoal: {goal}"
)
execute_prompt = ChatPromptTemplate.from_template(
"You are executing one step of a larger plan.\n\n"
"Overall goal: {goal}\n"
"Steps already done: {done}\n\n"
"Now do step {number}: {action}\n"
"Give the concrete output for this step in under 120 words."
)
def make_plan(goal):
"""Ask for a plan and parse it into real data we can inspect."""
reply = llm.invoke(plan_prompt.format(goal=goal))
show_response(reply)
# Models wrap JSON in fences and add preambles even when told not to, so
# parse defensively rather than trusting the instruction - this is the
# boundary where a plan stops being prose and becomes data.
return parse_json(reply.content)
if __name__ == "__main__":
print(f"GOAL: {GOAL}")
plan = make_plan(GOAL)
# The plan exists as data before anything runs, so it can be reviewed,
# reordered, or rejected without burning a single execution call.
print(f"\n{'=' * 60}\nPLAN ({len(plan)} steps)\n{'=' * 60}")
for item in plan:
print(f" {item['step']}. {item['action']}")
print(f" why: {item['why']}")
# Execute in order, passing completed steps forward so each step knows
# what has already happened.
done = []
for item in plan:
print(f"\n{'=' * 60}\nEXECUTING STEP {item['step']}\n{'=' * 60}")
result = llm.invoke(
execute_prompt.format(
goal=GOAL,
done="; ".join(done) or "none",
number=item["step"],
action=item["action"],
)
)
show_response(result)
done.append(item["action"])