mirror of
https://github.com/vxcontrol/langchaingo.git
synced 2026-07-21 00:45:22 -04:00
Merge branch 'pr/1182' into main-pull-requests
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user