chore: cleanup, identify goal from conversation when evaluting achievement
Signed-off-by: mudler <mudler@localai.io>
This commit is contained in:
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@ IMAGE_NAME?=webui
|
|||||||
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
|
||||||
prepare-tests:
|
prepare-tests:
|
||||||
docker compose up -d
|
docker compose up -d --build
|
||||||
|
|
||||||
cleanup-tests:
|
cleanup-tests:
|
||||||
docker compose down
|
docker compose down
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ import (
|
|||||||
// NewGoal creates a new intention action
|
// NewGoal creates a new intention action
|
||||||
// The inention action is special as it tries to identify
|
// The inention action is special as it tries to identify
|
||||||
// a tool to use and a reasoning over to use it
|
// a tool to use and a reasoning over to use it
|
||||||
func NewGoal(s ...string) *GoalAction {
|
func NewGoal() *GoalAction {
|
||||||
return &GoalAction{tools: s}
|
return &GoalAction{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type GoalAction struct {
|
type GoalAction struct {
|
||||||
tools []string
|
|
||||||
}
|
}
|
||||||
type GoalResponse struct {
|
type GoalResponse struct {
|
||||||
Goal string `json:"goal"`
|
Goal string `json:"goal"`
|
||||||
|
|||||||
@@ -24,7 +24,16 @@ type decisionResult struct {
|
|||||||
func (a *Agent) decision(
|
func (a *Agent) decision(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conversation []openai.ChatCompletionMessage,
|
conversation []openai.ChatCompletionMessage,
|
||||||
tools []openai.Tool, toolchoice any, maxRetries int) (*decisionResult, error) {
|
tools []openai.Tool, toolchoice string, maxRetries int) (*decisionResult, error) {
|
||||||
|
|
||||||
|
var choice *openai.ToolChoice
|
||||||
|
|
||||||
|
if toolchoice != "" {
|
||||||
|
choice = &openai.ToolChoice{
|
||||||
|
Type: openai.ToolTypeFunction,
|
||||||
|
Function: openai.ToolFunction{Name: toolchoice},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var lastErr error
|
var lastErr error
|
||||||
for attempts := 0; attempts < maxRetries; attempts++ {
|
for attempts := 0; attempts < maxRetries; attempts++ {
|
||||||
@@ -32,7 +41,10 @@ func (a *Agent) decision(
|
|||||||
Model: a.options.LLMAPI.Model,
|
Model: a.options.LLMAPI.Model,
|
||||||
Messages: conversation,
|
Messages: conversation,
|
||||||
Tools: tools,
|
Tools: tools,
|
||||||
ToolChoice: toolchoice,
|
}
|
||||||
|
|
||||||
|
if choice != nil {
|
||||||
|
decision.ToolChoice = *choice
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := a.client.CreateChatCompletion(ctx, decision)
|
resp, err := a.client.CreateChatCompletion(ctx, decision)
|
||||||
@@ -42,6 +54,9 @@ func (a *Agent) decision(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jsonResp, _ := json.Marshal(resp)
|
||||||
|
xlog.Debug("Decision response", "response", string(jsonResp))
|
||||||
|
|
||||||
if len(resp.Choices) != 1 {
|
if len(resp.Choices) != 1 {
|
||||||
lastErr = fmt.Errorf("no choices: %d", len(resp.Choices))
|
lastErr = fmt.Errorf("no choices: %d", len(resp.Choices))
|
||||||
xlog.Warn("Attempt to make a decision failed", "attempt", attempts+1, "error", lastErr)
|
xlog.Warn("Attempt to make a decision failed", "attempt", attempts+1, "error", lastErr)
|
||||||
@@ -189,10 +204,7 @@ func (a *Agent) generateParameters(ctx context.Context, pickTemplate string, act
|
|||||||
result, attemptErr = a.decision(ctx,
|
result, attemptErr = a.decision(ctx,
|
||||||
cc,
|
cc,
|
||||||
a.availableActions().ToTools(),
|
a.availableActions().ToTools(),
|
||||||
openai.ToolChoice{
|
act.Definition().Name.String(),
|
||||||
Type: openai.ToolTypeFunction,
|
|
||||||
Function: openai.ToolFunction{Name: act.Definition().Name.String()},
|
|
||||||
},
|
|
||||||
maxAttempts,
|
maxAttempts,
|
||||||
)
|
)
|
||||||
if attemptErr == nil && result.actionParams != nil {
|
if attemptErr == nil && result.actionParams != nil {
|
||||||
@@ -367,7 +379,9 @@ func (a *Agent) prepareHUD() (promptHUD *PromptHUD) {
|
|||||||
func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.ChatCompletionMessage, maxRetries int) (types.Action, types.ActionParams, string, error) {
|
func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.ChatCompletionMessage, maxRetries int) (types.Action, types.ActionParams, string, error) {
|
||||||
c := messages
|
c := messages
|
||||||
|
|
||||||
xlog.Debug("[pickAction] picking action", "messages", messages)
|
xlog.Debug("[pickAction] picking action starts", "messages", messages)
|
||||||
|
|
||||||
|
// Identify the goal of this conversation
|
||||||
|
|
||||||
if !a.options.forceReasoning {
|
if !a.options.forceReasoning {
|
||||||
xlog.Debug("not forcing reasoning")
|
xlog.Debug("not forcing reasoning")
|
||||||
@@ -376,7 +390,7 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
|
|||||||
thought, err := a.decision(ctx,
|
thought, err := a.decision(ctx,
|
||||||
messages,
|
messages,
|
||||||
a.availableActions().ToTools(),
|
a.availableActions().ToTools(),
|
||||||
nil,
|
"",
|
||||||
maxRetries)
|
maxRetries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "", err
|
return nil, nil, "", err
|
||||||
@@ -415,11 +429,6 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
|
|||||||
}, c...)
|
}, c...)
|
||||||
}
|
}
|
||||||
|
|
||||||
actionsID := []string{}
|
|
||||||
for _, m := range a.availableActions() {
|
|
||||||
actionsID = append(actionsID, m.Definition().Name.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// thoughtPromptStringBuilder := strings.Builder{}
|
// thoughtPromptStringBuilder := strings.Builder{}
|
||||||
// thoughtPromptStringBuilder.WriteString("You have to pick an action based on the conversation and the prompt. Describe the full reasoning process for your choice. Here is a list of actions: ")
|
// thoughtPromptStringBuilder.WriteString("You have to pick an action based on the conversation and the prompt. Describe the full reasoning process for your choice. Here is a list of actions: ")
|
||||||
// for _, m := range a.availableActions() {
|
// for _, m := range a.availableActions() {
|
||||||
@@ -438,6 +447,7 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
|
|||||||
|
|
||||||
//thoughtConv := []openai.ChatCompletionMessage{}
|
//thoughtConv := []openai.ChatCompletionMessage{}
|
||||||
|
|
||||||
|
xlog.Debug("[pickAction] picking action", "messages", c)
|
||||||
thought, err := a.askLLM(ctx,
|
thought, err := a.askLLM(ctx,
|
||||||
c,
|
c,
|
||||||
maxRetries,
|
maxRetries,
|
||||||
@@ -453,23 +463,48 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
|
|||||||
// by grammar, let's decide if we have achieved the goal
|
// by grammar, let's decide if we have achieved the goal
|
||||||
// 1. analyze response and check if goal is achieved
|
// 1. analyze response and check if goal is achieved
|
||||||
|
|
||||||
|
// Extract the goal first
|
||||||
params, err := a.decision(ctx,
|
params, err := a.decision(ctx,
|
||||||
|
append(
|
||||||
[]openai.ChatCompletionMessage{
|
[]openai.ChatCompletionMessage{
|
||||||
{
|
{
|
||||||
Role: "system",
|
Role: "system",
|
||||||
Content: "Extract an action to perform from the following reasoning: ",
|
Content: "Your only task is to extract the goal from the following conversation",
|
||||||
|
}}, messages...),
|
||||||
|
types.Actions{action.NewGoal()}.ToTools(),
|
||||||
|
action.NewGoal().Definition().Name.String(), maxRetries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, "", fmt.Errorf("failed to get the action tool parameters: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
goalResponse := action.GoalResponse{}
|
||||||
|
err = params.actionParams.Unmarshal(&goalResponse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if goalResponse.Goal == "" {
|
||||||
|
xlog.Debug("[pickAction] no goal found")
|
||||||
|
return nil, nil, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the goal was achieved
|
||||||
|
params, err = a.decision(ctx,
|
||||||
|
[]openai.ChatCompletionMessage{
|
||||||
|
{
|
||||||
|
Role: "system",
|
||||||
|
Content: "You have to understand if the goal is achieved or not from the following reasoning. The goal: " + goalResponse.Goal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Role: "user",
|
Role: "user",
|
||||||
Content: originalReasoning,
|
Content: originalReasoning,
|
||||||
}},
|
}},
|
||||||
types.Actions{action.NewGoal()}.ToTools(),
|
types.Actions{action.NewGoal()}.ToTools(),
|
||||||
action.NewGoal().Definition().Name, maxRetries)
|
action.NewGoal().Definition().Name.String(), maxRetries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "", fmt.Errorf("failed to get the action tool parameters: %v", err)
|
return nil, nil, "", fmt.Errorf("failed to get the action tool parameters: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
goalResponse := action.GoalResponse{}
|
|
||||||
err = params.actionParams.Unmarshal(&goalResponse)
|
err = params.actionParams.Unmarshal(&goalResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "", err
|
return nil, nil, "", err
|
||||||
@@ -485,11 +520,25 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
|
|||||||
|
|
||||||
xlog.Debug("[pickAction] thought", "conv", c, "originalReasoning", originalReasoning)
|
xlog.Debug("[pickAction] thought", "conv", c, "originalReasoning", originalReasoning)
|
||||||
|
|
||||||
|
actionsID := []string{"reply"}
|
||||||
|
for _, m := range a.availableActions() {
|
||||||
|
actionsID = append(actionsID, m.Definition().Name.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
xlog.Debug("[pickAction] actionsID", "actionsID", actionsID)
|
||||||
|
|
||||||
|
intentionsTools := action.NewIntention(actionsID...)
|
||||||
// TODO: FORCE to select ana ction here
|
// TODO: FORCE to select ana ction here
|
||||||
// NOTE: we do not give the full conversation here to pick the action
|
// NOTE: we do not give the full conversation here to pick the action
|
||||||
// to avoid hallucinations
|
// to avoid hallucinations
|
||||||
|
|
||||||
|
// Extract an action
|
||||||
params, err = a.decision(ctx,
|
params, err = a.decision(ctx,
|
||||||
[]openai.ChatCompletionMessage{
|
[]openai.ChatCompletionMessage{
|
||||||
|
{
|
||||||
|
Role: "system",
|
||||||
|
Content: prompt,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Role: "system",
|
Role: "system",
|
||||||
Content: "Extract an action to perform from the following reasoning: ",
|
Content: "Extract an action to perform from the following reasoning: ",
|
||||||
@@ -498,37 +547,42 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
|
|||||||
Role: "user",
|
Role: "user",
|
||||||
Content: originalReasoning,
|
Content: originalReasoning,
|
||||||
}},
|
}},
|
||||||
a.availableActions().ToTools(),
|
types.Actions{intentionsTools}.ToTools(),
|
||||||
nil, maxRetries)
|
intentionsTools.Definition().Name.String(), maxRetries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, "", fmt.Errorf("failed to get the action tool parameters: %v", err)
|
return nil, nil, "", fmt.Errorf("failed to get the action tool parameters: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chosenAction := a.availableActions().Find(params.actioName)
|
if params.actionParams == nil {
|
||||||
|
xlog.Debug("[pickAction] no action params found")
|
||||||
|
return nil, nil, params.message, nil
|
||||||
|
}
|
||||||
|
|
||||||
// xlog.Debug("[pickAction] params", "params", params)
|
actionChoice := action.IntentResponse{}
|
||||||
|
err = params.actionParams.Unmarshal(&actionChoice)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
// if params.actionParams == nil {
|
if actionChoice.Tool == "" || actionChoice.Tool == "reply" {
|
||||||
// return nil, nil, params.message, nil
|
xlog.Debug("[pickAction] no action found, replying")
|
||||||
// }
|
return nil, nil, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// xlog.Debug("[pickAction] actionChoice", "actionChoice", params.actionParams, "message", params.message)
|
chosenAction := a.availableActions().Find(actionChoice.Tool)
|
||||||
|
|
||||||
// actionChoice := action.IntentResponse{}
|
xlog.Debug("[pickAction] chosenAction", "chosenAction", chosenAction, "actionName", actionChoice.Tool)
|
||||||
|
|
||||||
// err = params.actionParams.Unmarshal(&actionChoice)
|
// // Let's double check if the action is correct by asking the LLM to judge it
|
||||||
// if err != nil {
|
|
||||||
// return nil, nil, "", err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if actionChoice.Tool == "" || actionChoice.Tool == "none" {
|
// if chosenAction!= nil {
|
||||||
// return nil, nil, "", nil
|
// promptString:= "Given the following goal and thoughts, is the action correct? \n\n"
|
||||||
// }
|
// promptString+= fmt.Sprintf("Goal: %s\n", goalResponse.Goal)
|
||||||
|
// promptString+= fmt.Sprintf("Thoughts: %s\n", originalReasoning)
|
||||||
|
// promptString+= fmt.Sprintf("Action: %s\n", chosenAction.Definition().Name.String())
|
||||||
|
// promptString+= fmt.Sprintf("Action description: %s\n", chosenAction.Definition().Description)
|
||||||
|
// promptString+= fmt.Sprintf("Action parameters: %s\n", params.actionParams)
|
||||||
|
|
||||||
// // Find the action
|
|
||||||
// chosenAction := a.availableActions().Find(actionChoice.Tool)
|
|
||||||
// if chosenAction == nil {
|
|
||||||
// return nil, nil, "", fmt.Errorf("no action found for intent:" + actionChoice.Tool)
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return chosenAction, nil, originalReasoning, nil
|
return chosenAction, nil, originalReasoning, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user