Plan-b working

This commit is contained in:
Cyber MacGeddon 2024-11-09 11:10:19 +00:00
parent 4cc029f00c
commit 82235a0758
4 changed files with 986 additions and 79 deletions

View file

@ -9,6 +9,7 @@ import textwrap
import time import time
import dataclasses import dataclasses
import sys import sys
import base64
def wrap(text, width=75): def wrap(text, width=75):
@ -50,6 +51,7 @@ class Action:
thought : str thought : str
name : str name : str
arguments : dict arguments : dict
observation : str
@dataclasses.dataclass @dataclasses.dataclass
class Final: class Final:
@ -173,12 +175,13 @@ Question: {{question}}
Input: Input:
{% for h in history %} {% for h in history %}
{ {
"action": {{h.action}}, "action": "{{h.action}}",
"arguments": [ "arguments": [
{% for k, v in h.arguments.items() %} { {% for k, v in h.arguments.items() %} {
"{{k}}": "{{v}}", "{{k}}": "{{v}}",
{%endfor%} } {%endfor%} }
] ],
"observation": "{{h.observation}}"
} }
{% endfor %}""" {% endfor %}"""
@ -206,7 +209,8 @@ Input:
{ {
"thought": h.thought, "thought": h.thought,
"action": h.name, "action": h.name,
"arguments": h.arguments "arguments": h.arguments,
"observation": h.observation,
} }
for h in self.history for h in self.history
], ],
@ -214,7 +218,6 @@ Input:
print(prompt) print(prompt)
resp = prompt_client.request( resp = prompt_client.request(
"question", "question",
{ {
@ -225,6 +228,11 @@ Input:
resp = resp.replace("```json", "") resp = resp.replace("```json", "")
resp = resp.replace("```", "") resp = resp.replace("```", "")
print("---")
print(resp)
print("---")
print(base64.b64encode(resp.encode("utf-8")).decode("utf-8"))
obj = json.loads(resp) obj = json.loads(resp)
if obj.get("final-answer"): if obj.get("final-answer"):
@ -272,8 +280,32 @@ Input:
else: else:
self.think(act.thought) self.think(act.thought)
print(act.name)
action = None
for tool in self.tools:
if tool.tool.name == act.name:
action = tool
if action is None:
raise RuntimeError(f"No action for {act.name}!")
resp = action.invoke(**act.arguments)
resp = resp.strip()
print(resp)
act.observation = resp
print("act>", act)
self.history.append(act) self.history.append(act)
print(self.history)
raise RuntimeError("Too many iterations") raise RuntimeError("Too many iterations")
@ -284,78 +316,3 @@ am = AgentManager(prompt_client, tools, q)
act = am.invoke() act = am.invoke()
print(act) print(act)
sys.exit(0)
tpl = ibis.Template(template)
history = []
output(wrap(q))
print()
for iter in range(0, 10):
prompt = tpl.render({
"tools": tools,
"question": q,
"tool_names": ",".join([t["function"] for t in tools]),
"history": [json.dumps(h, indent=2) for h in history],
})
print("-" * 76)
print(prompt)
print("-" * 76)
resp = prompt_client.request(
"question",
{
"question": prompt
}
)
print("-" * 76)
print(resp)
print("-" * 76)
resp = resp.replace("```json", "")
resp = resp.replace("```", "")
obj = json.loads(resp)
output(obj["thought"], "? ")
print()
if "final-answer" in obj:
history.append(obj)
break
if "action" in obj:
if obj["action"] == "cats-kb":
ans = graph_rag_query(obj["arguments"]["query"])
obj["observation"] = ans.strip()
elif obj["action"] == "compute":
if "196" in obj["arguments"]["query"]:
obj["observation"] = "196 > 1.319501555"
else:
obj["observation"] = "The answer is 1.319501155"
elif obj["action"] == "shuttle-kb":
ans = graph_rag_query(obj["arguments"]["query"])
obj["observation"] = ans.strip()
else:
raise RuntimeError("Unknown action:", obj["action"])
output(obj["observation"], "! ")
print()
history.append(obj)
print("-" * 76)
print(history)
print("-" * 76)
continue
raise RuntimeError("Iteration output is not action or final-answer")
output(obj["final-answer"], "< ")

312
agent/plan-b-2 Executable file
View file

@ -0,0 +1,312 @@
#!/usr/bin/env python3
from trustgraph.clients.prompt_client import PromptClient
from trustgraph.clients.graph_rag_client import GraphRagClient
import json
import textwrap
import ibis
import textwrap
import time
import dataclasses
import sys
import base64
def wrap(text, width=75):
out = textwrap.wrap(
text, width=width
)
return "\n".join(out)
def output(text, prefix="> ", width=78):
out = textwrap.indent(
text, prefix=prefix
)
print(out)
pulsar_host = "pulsar://localhost:6650"
prompt_client = PromptClient(pulsar_host=pulsar_host)
rag_client = GraphRagClient(pulsar_host=pulsar_host)
def graph_rag_query(q):
resp = rag_client.request(q)
return resp
@dataclasses.dataclass
class Argument:
name : str
type : str
description : str
@dataclasses.dataclass
class Tool:
name : str
description : str
arguments : list[Argument]
@dataclasses.dataclass
class Action:
thought : str
name : str
arguments : dict
observation : str
@dataclasses.dataclass
class Final:
thought : str
final : str
class CatsKb:
tool = Tool(
name = "cats-kb",
description = "Query a knowledge base with information about Mark's cats. The query should be a simple natural language question",
arguments = [
Argument(
name = "query",
type = "string",
description = "The search query string"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(arguments.get("query"))
class ShuttleKb:
tool = Tool(
name = "shuttle-kb",
description = "Query a knowledge base with information about the space shuttle. The query should be a simple natural language question",
arguments = [
Argument(
name = "query",
type = "string",
description = "The search query string"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(arguments.get("query"))
class Compute:
tool = Tool(
name = "compute",
description = "A computation engine which can answer questions about maths and computation",
arguments = [
Argument(
name = "computation",
type = "string",
description = "The computation to solve"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(
"question", { "question": arguments.get("computation") }
)
tools = [
CatsKb(rag_client),
ShuttleKb(rag_client),
Compute(prompt_client),
]
class AgentManager:
template="""Answer the following questions as best you can. You have access to the following tools:
{% for tool in tools %}{
"function": "{{ tool.tool.name }}",
"description": "{{ tool.tool.description }}",
"arguments": [
{% for arg in tool.tool.arguments %} {
"name": "{{ arg.name }}",
"type": "{{ arg.type }}",
"description": "{{ arg.description }}",
}
{% endfor %}
]
}
{% endfor %}
To call a function, respond - immediately with exactly one action - a JSON object of the following format:
{
"action": "function_name",
"arguments": {
"argument1": "argument_value",
"argument2": "argument_value"
}
}
Each step has the following format in your output:
{
"thought": "you should always think about what to do",
"action": "the action to take, should be one of [{{tool_names}}]",
"arguments": {
"argument1": action argument,
"argument2": action argument2
},
"observation": "the result of the action",
}
... (this JSON object can repeat N times)
{
"thought": "I now know the final answer",
"final-answer": "the final answer to the original input question"
}
Respond by describing either one single thought/action/arguments or the final-answer. Pause after providing one action or final answer.
Begin!
Question: {{question}}
Input:
{% for h in history %}
{
"action": "{{h.action}}",
"arguments": [
{% for k, v in h.arguments.items() %} {
"{{k}}": "{{v}}",
{%endfor%} }
],
"observation": "{{h.observation}}"
}
{% endfor %}"""
def __init__(self, client, tools, question):
self.client = client
self.tools = tools
self.history = []
self.question = question
def iterate(self):
tpl = ibis.Template(self.template)
tools = self.tools
tool_names = ",".join([
t.tool.name for t in self.tools
])
prompt = tpl.render({
"tools": tools,
"question": self.question,
"tool_names": tool_names,
"history": [
{
"thought": h.thought,
"action": h.name,
"arguments": h.arguments,
"observation": h.observation,
}
for h in self.history
],
})
print(prompt)
resp = prompt_client.request(
"question",
{
"question": prompt
}
)
resp = resp.replace("```json", "")
resp = resp.replace("```", "")
print("---")
print(resp)
print("---")
print(base64.b64encode(resp.encode("utf-8")).decode("utf-8"))
obj = json.loads(resp)
if obj.get("final-answer"):
a = Final(
thought = obj.get("thought"),
final = obj.get("final-answer"),
)
return a
else:
a = Action(
thought = obj.get("thought"),
name = obj.get("action"),
arguments = obj.get("arguments"),
observation = "FIXME"
)
return a
def think(self, thought):
print(thought)
output(thought, "? ")
print()
def invoke(self):
for i in range(0, 10):
print("-----------------------")
print("Iter", i)
act = self.iterate()
print(act)
if isinstance(act, Final):
self.think(act.thought)
return act.final
else:
self.think(act.thought)
print(act.name)
action = None
for tool in self.tools:
if tool.tool.name == act.name:
action = tool
if action is None:
raise RuntimeError(f"No action for {act.name}!")
resp = action.invoke(**act.arguments)
resp = resp.strip()
print(resp)
act.observation = resp
print("act>", act)
self.history.append(act)
print(self.history)
raise RuntimeError("Too many iterations")
q = "How many cats does Mark have? Calculate that number raised to 0.4 power. Is that number higher than the numeric part of the mission identifier of the Space Shuttle Challenger on its last mission? If so, give me an apple pie recipe, otherwise return a poem about cheese."
am = AgentManager(prompt_client, tools, q)
act = am.invoke()
print(act)

311
agent/plan-b-3 Executable file
View file

@ -0,0 +1,311 @@
#!/usr/bin/env python3
from trustgraph.clients.prompt_client import PromptClient
from trustgraph.clients.graph_rag_client import GraphRagClient
import json
import textwrap
import ibis
import textwrap
import time
import dataclasses
import sys
import base64
def wrap(text, width=75):
out = textwrap.wrap(
text, width=width
)
return "\n".join(out)
def output(text, prefix="> ", width=78):
out = textwrap.indent(
text, prefix=prefix
)
print(out)
pulsar_host = "pulsar://localhost:6650"
prompt_client = PromptClient(pulsar_host=pulsar_host)
rag_client = GraphRagClient(pulsar_host=pulsar_host)
@dataclasses.dataclass
class Argument:
name : str
type : str
description : str
@dataclasses.dataclass
class Tool:
name : str
description : str
arguments : list[Argument]
@dataclasses.dataclass
class Action:
thought : str
name : str
arguments : dict
observation : str
@dataclasses.dataclass
class Final:
thought : str
final : str
class CatsKb:
tool = Tool(
name = "cats-kb",
description = "Query a knowledge base with information about Mark's cats. The query should be a simple natural language question",
arguments = [
Argument(
name = "query",
type = "string",
description = "The search query string"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(arguments.get("query"))
class ShuttleKb:
tool = Tool(
name = "shuttle-kb",
description = "Query a knowledge base with information about the space shuttle. The query should be a simple natural language question",
arguments = [
Argument(
name = "query",
type = "string",
description = "The search query string"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(arguments.get("query"))
class Compute:
tool = Tool(
name = "compute",
description = "A computation engine which can answer questions about maths and computation",
arguments = [
Argument(
name = "computation",
type = "string",
description = "The computation to solve"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(
"question", { "question": arguments.get("computation") }
)
tools = [
CatsKb(rag_client),
ShuttleKb(rag_client),
Compute(prompt_client),
]
class AgentManager:
template="""Answer the following questions as best you can. You have access to the following tools:
{% for tool in tools %}{
"function": "{{ tool.tool.name }}",
"description": "{{ tool.tool.description }}",
"arguments": [
{% for arg in tool.tool.arguments %} {
"name": "{{ arg.name }}",
"type": "{{ arg.type }}",
"description": "{{ arg.description }}",
}
{% endfor %}
]
}
{% endfor %}
To call a function, respond - immediately and only - with a JSON object of the following format:
{
"action": "function_name",
"arguments": {
"argument1": "argument_value",
"argument2": "argument_value"
}
}
Each step has the following format in your output:
{
"thought": "you should always think about what to do",
"action": "the action to take, should be one of [{{tool_names}}]",
"arguments": {
"argument1": action argument,
"argument2": action argument2
},
"observation": "the result of the action",
}
... (this JSON object can repeat N times)
{
"thought": "I now know the final answer",
"final-answer": "the final answer to the original input question"
}
Respond by describing either one single thought/action/arguments or the final-answer. Pause after providing each action.
Begin!
Question: {{question}}
Input:
{% for h in history %}
{
"action": "{{h.action}}",
"arguments": [
{% for k, v in h.arguments.items() %} {
"{{k}}": "{{v}}",
{%endfor%} }
],
"observation": "{{h.observation}}"
}
{% endfor %}"""
def __init__(self, client, tools, question):
self.client = client
self.tools = tools
self.history = []
self.question = question
def iterate(self):
tpl = ibis.Template(self.template)
tools = self.tools
tool_names = ",".join([
t.tool.name for t in self.tools
])
prompt = tpl.render({
"tools": tools,
"question": self.question,
"tool_names": tool_names,
"history": [
{
"thought": h.thought,
"action": h.name,
"arguments": h.arguments,
"observation": h.observation,
}
for h in self.history
],
})
# print(prompt)
resp = prompt_client.request(
"question",
{
"question": prompt
}
)
resp = resp.replace("```json", "")
resp = resp.replace("```", "")
# print("---")
# print(resp)
# print("---")
# print(base64.b64encode(resp.encode("utf-8")).decode("utf-8"))
obj = json.loads(resp)
if obj.get("final-answer"):
a = Final(
thought = obj.get("thought"),
final = obj.get("final-answer"),
)
return a
else:
a = Action(
thought = obj.get("thought"),
name = obj.get("action"),
arguments = obj.get("arguments"),
observation = "FIXME"
)
return a
def think(self, thought):
# print(thought)
output(wrap(thought), "? ")
print()
def invoke(self):
for i in range(0, 10):
# print("-----------------------")
# print("Iter", i)
act = self.iterate()
# print(act)
if isinstance(act, Final):
self.think(act.thought)
return act.final
else:
self.think(act.thought)
# print(act.name)
action = None
for tool in self.tools:
if tool.tool.name == act.name:
action = tool
if action is None:
raise RuntimeError(f"No action for {act.name}!")
resp = action.invoke(**act.arguments)
resp = resp.strip()
# print(resp)
act.observation = resp
# print("act>", act)
self.history.append(act)
# print(self.history)
raise RuntimeError("Too many iterations")
q = "How many cats does Mark have? Calculate that number raised to 0.4 power. Is that number higher than the numeric part of the mission identifier of the Space Shuttle Challenger on its last mission? If so, give me an apple pie recipe, otherwise return a poem about cheese."
output(wrap(q))
print()
am = AgentManager(prompt_client, tools, q)
act = am.invoke()
print(act)

327
agent/plan-b-4 Executable file
View file

@ -0,0 +1,327 @@
#!/usr/bin/env python3
from trustgraph.clients.prompt_client import PromptClient
from trustgraph.clients.graph_rag_client import GraphRagClient
import json
import textwrap
import ibis
import textwrap
import time
import dataclasses
import sys
import base64
def wrap(text, width=75):
if text is None: text = "n/a"
out = textwrap.wrap(
text, width=width
)
return "\n".join(out)
def output(text, prefix="> ", width=78):
out = textwrap.indent(
text, prefix=prefix
)
print(out)
pulsar_host = "pulsar://localhost:6650"
prompt_client = PromptClient(pulsar_host=pulsar_host)
rag_client = GraphRagClient(pulsar_host=pulsar_host)
@dataclasses.dataclass
class Argument:
name : str
type : str
description : str
@dataclasses.dataclass
class Tool:
name : str
description : str
arguments : list[Argument]
@dataclasses.dataclass
class Action:
thought : str
name : str
arguments : dict
observation : str
@dataclasses.dataclass
class Final:
thought : str
final : str
class CatsKb:
tool = Tool(
name = "cats-kb",
description = "Query a knowledge base with information about Mark's cats. The query should be a simple natural language question",
arguments = [
Argument(
name = "query",
type = "string",
description = "The search query string"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(arguments.get("query"))
class ShuttleKb:
tool = Tool(
name = "shuttle-kb",
description = "Query a knowledge base with information about the space shuttle. The query should be a simple natural language question",
arguments = [
Argument(
name = "query",
type = "string",
description = "The search query string"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(arguments.get("query"))
class Compute:
tool = Tool(
name = "compute",
description = "A computation engine which can answer questions about maths and computation",
arguments = [
Argument(
name = "computation",
type = "string",
description = "The computation to solve"
)
]
)
def __init__(self, client):
self.client = client
def invoke(self, **arguments):
return self.client.request(
"question", { "question": arguments.get("computation") }
)
tools = [
CatsKb(rag_client),
ShuttleKb(rag_client),
Compute(prompt_client),
]
class AgentManager:
template="""Answer the following questions as best you can. You have
access to the following functions:
{% for tool in tools %}{
"function": "{{ tool.tool.name }}",
"description": "{{ tool.tool.description }}",
"arguments": [
{% for arg in tool.tool.arguments %} {
"name": "{{ arg.name }}",
"type": "{{ arg.type }}",
"description": "{{ arg.description }}",
}
{% endfor %}
]
}
{% endfor %}
You can either choose to call a function to get more information, or
return a final answer.
To call a function, respond with a JSON object of the following format:
{
"thought": "your thought about what to do",
"action": "the action to take, should be one of [{{tool_names}}]",
"arguments": {
"argument1": "argument_value",
"argument2": "argument_value"
}
}
To provide a final answer, response a JSON object of the following format:
{
"thought": "I now know the final answer",
"final-answer": "the final answer to the original input question"
}
Previous steps are included in the input. Each step has the following
format in your output:
{
"thought": "your thought about what to do",
"action": "the action taken",
"arguments": {
"argument1": action argument,
"argument2": action argument2
},
"observation": "the result of the action",
}
Respond by describing either one single thought/action/arguments or
the final-answer. Pause after providing one action or final-answer.
Begin!
Question: {{question}}
Input:
{% for h in history %}
{
"action": "{{h.action}}",
"arguments": [
{% for k, v in h.arguments.items() %} {
"{{k}}": "{{v}}",
{%endfor%} }
],
"observation": "{{h.observation}}"
}
{% endfor %}"""
def __init__(self, client, tools, question):
self.client = client
self.tools = tools
self.history = []
self.question = question
def iterate(self):
tpl = ibis.Template(self.template)
tools = self.tools
tool_names = ",".join([
t.tool.name for t in self.tools
])
prompt = tpl.render({
"tools": tools,
"question": self.question,
"tool_names": tool_names,
"history": [
{
"thought": h.thought,
"action": h.name,
"arguments": h.arguments,
"observation": h.observation,
}
for h in self.history
],
})
# print(prompt)
resp = prompt_client.request(
"question",
{
"question": prompt
}
)
resp = resp.replace("```json", "")
resp = resp.replace("```", "")
# print("---")
# print(resp)
# print("---")
# print(base64.b64encode(resp.encode("utf-8")).decode("utf-8"))
obj = json.loads(resp)
if obj.get("final-answer"):
a = Final(
thought = obj.get("thought"),
final = obj.get("final-answer"),
)
return a
else:
a = Action(
thought = obj.get("thought"),
name = obj.get("action"),
arguments = obj.get("arguments"),
observation = "FIXME"
)
return a
def think(self, thought):
# print(thought)
output(wrap(thought), "? ")
print()
def invoke(self):
for i in range(0, 10):
# print("-----------------------")
# print("Iter", i)
act = self.iterate()
# print(act)
if isinstance(act, Final):
self.think(act.thought)
return act.final
else:
self.think(act.thought)
# print(act.name)
action = None
for tool in self.tools:
if tool.tool.name == act.name:
action = tool
if action is None:
raise RuntimeError(f"No action for {act.name}!")
resp = action.invoke(**act.arguments)
resp = resp.strip()
# print(resp)
act.observation = resp
# print("act>", act)
self.history.append(act)
# print(self.history)
raise RuntimeError("Too many iterations")
q = "How many cats does Mark have? Calculate that number raised to 0.4 power. Is that number higher than the numeric part of the mission identifier of the Space Shuttle Challenger on its last mission? If so, give me an apple pie recipe, otherwise return a poem about cheese."
output(wrap(q))
print()
am = AgentManager(prompt_client, tools, q)
resp = am.invoke()
output(resp, "< ")
print()