Merge branch 'pr/1182' into main-pull-requests

This commit is contained in:
Dmitry Ng
2025-05-06 17:08:03 +03:00
3 changed files with 151 additions and 2 deletions
+3 -2
View File
@@ -170,8 +170,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,
+70
View File
@@ -0,0 +1,70 @@
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) {
// Find the starting ```markdown
startIdx := strings.Index(text, "```markdown\n")
if startIdx == -1 {
return "", ParseError{Text: text, Reason: "no ```markdown at start of output"}
}
// 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"}
}
// Extract the content
content := text[contentStart:lastBacktickIdx]
// Trim whitespace
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"
}
+78
View File
@@ -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: "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,
},
}
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)
}
}
})
}
}