Skip to content

Commit

Permalink
feat(functions): allow response_regex to be a list (#2447)
Browse files Browse the repository at this point in the history
feat(functions): allow regex match to be a list

Signed-off-by: Ettore Di Giacinto <[email protected]>
  • Loading branch information
mudler authored May 31, 2024
1 parent ff8a696 commit 5d31e52
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 16 deletions.
5 changes: 3 additions & 2 deletions docs/content/docs/features/openai-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ parameters:
function:
# set to true to not use grammars
no_grammar: true
# set a regex to extract the function tool arguments from the LLM response
response_regex: "(?P<function>\w+)\s*\((?P<arguments>.*)\)"
# set one or more regexes used to extract the function tool arguments from the LLM response
response_regex:
- "(?P<function>\w+)\s*\((?P<arguments>.*)\)"
```
The response regex have to be a regex with named parameters to allow to scan the function name and the arguments. For instance, consider:
Expand Down
28 changes: 15 additions & 13 deletions pkg/functions/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type FunctionsConfig struct {
NoActionDescriptionName string `yaml:"no_action_description_name"`

// ResponseRegex is a named regex to extract the function name and arguments from the response
ResponseRegex string `yaml:"response_regex"`
ResponseRegex []string `yaml:"response_regex"`

// JSONRegexMatch is a regex to extract the JSON object from the response
JSONRegexMatch []string `yaml:"json_regex_match"`
Expand Down Expand Up @@ -228,24 +228,26 @@ func ParseFunctionCall(llmresult string, functionConfig FunctionsConfig) []FuncC
}
}

if functionConfig.ResponseRegex != "" {
if len(functionConfig.ResponseRegex) > 0 {
// We use named regexes here to extract the function name and arguments
// obviously, this expects the LLM to be stable and return correctly formatted JSON
// TODO: optimize this and pre-compile it
var respRegex = regexp.MustCompile(functionConfig.ResponseRegex)
matches := respRegex.FindAllStringSubmatch(llmresult, -1)
for _, match := range matches {
for i, name := range respRegex.SubexpNames() {
if i != 0 && name != "" && len(match) > i {
result[name] = match[i]
for _, r := range functionConfig.ResponseRegex {
var respRegex = regexp.MustCompile(r)
matches := respRegex.FindAllStringSubmatch(llmresult, -1)
for _, match := range matches {
for i, name := range respRegex.SubexpNames() {
if i != 0 && name != "" && len(match) > i {
result[name] = match[i]
}
}
}

functionName := result[functionNameKey]
if functionName == "" {
return results
functionName := result[functionNameKey]
if functionName == "" {
return results
}
results = append(results, FuncCallResults{Name: result[functionNameKey], Arguments: result["arguments"]})
}
results = append(results, FuncCallResults{Name: result[functionNameKey], Arguments: result["arguments"]})
}
} else {
if len(llmResults) == 0 {
Expand Down
2 changes: 1 addition & 1 deletion pkg/functions/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var _ = Describe("LocalAI function parse tests", func() {
Context("when not using grammars and regex is needed", func() {
It("should extract function name and arguments from the regex", func() {
input := `add({"x":5,"y":3})`
functionConfig.ResponseRegex = `(?P<function>\w+)\s*\((?P<arguments>.*)\)`
functionConfig.ResponseRegex = []string{`(?P<function>\w+)\s*\((?P<arguments>.*)\)`}

results := ParseFunctionCall(input, functionConfig)
Expect(results).To(HaveLen(1))
Expand Down

0 comments on commit 5d31e52

Please sign in to comment.