From 80744c264a27fad90795a4216adeae0b2fd8ab2b Mon Sep 17 00:00:00 2001 From: Arrowarcher <37265468+Arrowarcher@users.noreply.github.com> Date: Tue, 11 Mar 2025 19:00:27 +0800 Subject: [PATCH 1/3] Update openaillm.go Update openaillm.go GenerateContent add ReasoningContent --- llms/openai/openaillm.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llms/openai/openaillm.go b/llms/openai/openaillm.go index 5710b6fc..eb59ec90 100644 --- a/llms/openai/openaillm.go +++ b/llms/openai/openaillm.go @@ -154,8 +154,9 @@ func (o *LLM) GenerateContent(ctx context.Context, messages []llms.MessageConten choices := make([]*llms.ContentChoice, len(result.Choices)) for i, c := range result.Choices { choices[i] = &llms.ContentChoice{ - Content: c.Message.Content, - StopReason: fmt.Sprint(c.FinishReason), + Content: c.Message.Content, + ReasoningContent: c.Message.ReasoningContent, + StopReason: fmt.Sprint(c.FinishReason), GenerationInfo: map[string]any{ "CompletionTokens": result.Usage.CompletionTokens, "PromptTokens": result.Usage.PromptTokens, From a4f671a62368c86da8cdf5de5272878f4e162427 Mon Sep 17 00:00:00 2001 From: arrowliu Date: Wed, 12 Mar 2025 11:30:09 +0800 Subject: [PATCH 2/3] add markdown parser --- outputparser/makrdown_parser.go | 63 ++++++++++++++++++++++ outputparser/markdown_parser_test.go | 78 ++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 outputparser/makrdown_parser.go create mode 100644 outputparser/markdown_parser_test.go diff --git a/outputparser/makrdown_parser.go b/outputparser/makrdown_parser.go new file mode 100644 index 00000000..ae047bdc --- /dev/null +++ b/outputparser/makrdown_parser.go @@ -0,0 +1,63 @@ +package outputparser + +import ( + "strings" + + "github.com/tmc/langchaingo/llms" + "github.com/tmc/langchaingo/schema" +) + +const ( + // _markdownFormatInstruction is the instruction for the LLM to format output as markdown. + _markdownFormatInstruction = "The output should be formatted in markdown: \n```markdown\nYour content here\n```" +) + +// Markdown is a simple output parser that extracts content from markdown code blocks. +type Markdown struct{} + +// NewMarkdown creates a new markdown output parser. +func NewMarkdown() Markdown { + return Markdown{} +} + +// Statically assert that Markdown implements the OutputParser interface. +var _ schema.OutputParser[any] = Markdown{} + +// parse extracts content from markdown code blocks in the given text. +func (p Markdown) parse(text string) (string, error) { + // Extract content from ```markdown ... ``` blocks + _, afterStart, ok := strings.Cut(text, "```markdown\n") + if !ok { + return "", ParseError{Text: text, Reason: "no ```markdown at start of output"} + } + + content, _, ok := strings.Cut(afterStart, "```") + if !ok { + return "", ParseError{Text: text, Reason: "no closing ``` at end of output"} + } + + // Trim whitespace from content + content = strings.TrimSpace(content) + + return content, nil +} + +// Parse extracts content from markdown code blocks. +func (p Markdown) Parse(text string) (any, error) { + return p.parse(text) +} + +// ParseWithPrompt does the same as Parse. +func (p Markdown) ParseWithPrompt(text string, _ llms.PromptValue) (any, error) { + return p.parse(text) +} + +// GetFormatInstructions returns a string explaining how the output should be formatted. +func (p Markdown) GetFormatInstructions() string { + return _markdownFormatInstruction +} + +// Type returns the type of the output parser. +func (p Markdown) Type() string { + return "markdown_parser" +} diff --git a/outputparser/markdown_parser_test.go b/outputparser/markdown_parser_test.go new file mode 100644 index 00000000..229ce564 --- /dev/null +++ b/outputparser/markdown_parser_test.go @@ -0,0 +1,78 @@ +package outputparser_test + +import ( + "testing" + + "github.com/tmc/langchaingo/outputparser" +) + +func TestMarkdown(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + input string + expected string + hasError bool + }{ + { + name: "Valid markdown block with no preceding text", + input: "```markdown\nSimple content\nwith multiple lines\n```", + expected: "Simple content\nwith multiple lines", + hasError: false, + }, + { + name: "Missing opening markdown tag", + input: "Here is some content:\n\nThis is not properly formatted.\n```", + expected: "", + hasError: true, + }, + { + name: "Missing closing tag", + input: "Here is some content:\n\n```markdown\nThis doesn't have a closing tag.", + expected: "", + hasError: true, + }, + { + name: "Empty markdown block", + input: "```markdown\n```", + expected: "", + hasError: false, + }, + { + name: "Multiple markdown blocks", + input: "First block:\n```markdown\nContent 1\n```\n\nSecond block:\n```markdown\nContent 2\n```", + expected: "Content 1", + hasError: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + parser := outputparser.NewMarkdown() + + result, err := parser.Parse(tc.input) + + // Check error status + if tc.hasError && err == nil { + t.Errorf("Expected an error but got none") + } + + if !tc.hasError && err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // If we're not expecting an error, check the result + if !tc.hasError { + content, ok := result.(string) + if !ok { + t.Errorf("Expected result to be string, got %T", result) + } + + if content != tc.expected { + t.Errorf("Expected:\n%s\n\nGot:\n%s", tc.expected, content) + } + } + }) + } +} From e94080281de8d2bf084f3798d463bfc460e347a2 Mon Sep 17 00:00:00 2001 From: arrowliu Date: Mon, 17 Mar 2025 19:22:54 +0800 Subject: [PATCH 3/3] fix:Markdown blocks and code blocks --- outputparser/makrdown_parser.go | 19 +++++++++++++------ outputparser/markdown_parser_test.go | 6 +++--- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/outputparser/makrdown_parser.go b/outputparser/makrdown_parser.go index ae047bdc..eaec5abe 100644 --- a/outputparser/makrdown_parser.go +++ b/outputparser/makrdown_parser.go @@ -25,18 +25,25 @@ var _ schema.OutputParser[any] = Markdown{} // parse extracts content from markdown code blocks in the given text. func (p Markdown) parse(text string) (string, error) { - // Extract content from ```markdown ... ``` blocks - _, afterStart, ok := strings.Cut(text, "```markdown\n") - if !ok { + // Find the starting ```markdown + startIdx := strings.Index(text, "```markdown\n") + if startIdx == -1 { return "", ParseError{Text: text, Reason: "no ```markdown at start of output"} } - content, _, ok := strings.Cut(afterStart, "```") - if !ok { + // Move to the content starting position + contentStart := startIdx + len("```markdown\n") + + // Find the last ``` + lastBacktickIdx := strings.LastIndex(text, "```") + if lastBacktickIdx <= contentStart { return "", ParseError{Text: text, Reason: "no closing ``` at end of output"} } - // Trim whitespace from content + // Extract the content + content := text[contentStart:lastBacktickIdx] + + // Trim whitespace content = strings.TrimSpace(content) return content, nil diff --git a/outputparser/markdown_parser_test.go b/outputparser/markdown_parser_test.go index 229ce564..8d3fd1d7 100644 --- a/outputparser/markdown_parser_test.go +++ b/outputparser/markdown_parser_test.go @@ -40,9 +40,9 @@ func TestMarkdown(t *testing.T) { hasError: false, }, { - name: "Multiple markdown blocks", - input: "First block:\n```markdown\nContent 1\n```\n\nSecond block:\n```markdown\nContent 2\n```", - expected: "Content 1", + name: "Markdown blocks and code blocks", + input: "First block:\n```markdown\nContent 1\n\nCode block:\n```csharp\nContent 2\n``` 13456```", + expected: "Content 1\n\nCode block:\n```csharp\nContent 2\n``` 13456", hasError: false, }, }