feat: add AI Querier module with custom output schema support and refactor common model calling logic

- Add new AI Querier module for structured information extraction from screenshots
- Support custom output schema for structured data response
- Implement automatic type conversion and data validation
- Add comprehensive test suite with various data structure examples
- Refactor callModelWithLogging to utils.go as shared function for planner, asserter, and querier
- Eliminate code duplication across AI modules (30+ lines of repeated code)
- Improve maintainability with unified logging and timing logic
- Add environment variable checks in test setup to handle missing API keys gracefully

Key features:
- Custom output schema support with JSON Schema generation
- Automatic data type conversion with reflection
- Fallback mechanisms for robust parsing
- Comprehensive documentation and usage examples
- Backward compatibility with existing functionality
This commit is contained in:
lilong.129
2025-06-10 20:41:35 +08:00
parent fa9a53d2ae
commit 7c45acd061
10 changed files with 1495 additions and 22 deletions

View File

@@ -1,9 +1,17 @@
package ai
import (
"context"
"regexp"
"strings"
"time"
"unicode/utf8"
"github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/schema"
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/v5/uixt/option"
)
// extractJSONFromContent extracts JSON content from various formats in the response
@@ -102,3 +110,29 @@ func extractJSONFromContent(content string) string {
return ""
}
// callModelWithLogging is a common function to call model with logging and timing
// It handles the common pattern of:
// 1. Log request
// 2. Start timing
// 3. Call model.Generate
// 4. Log timing and model info
// 5. Log response
func callModelWithLogging(ctx context.Context, model model.ToolCallingChatModel, history ConversationHistory, modelType option.LLMServiceType, operation string) (*schema.Message, error) {
logRequest(history)
startTime := time.Now()
defer func() {
log.Debug().Float64("elapsed(s)", time.Since(startTime).Seconds()).
Str("model", string(modelType)).
Msgf("call model service for %s", operation)
}()
message, err := model.Generate(ctx, history)
if err != nil {
return nil, err
}
logResponse(message)
return message, nil
}