Skip to content

feat: change llm model and refactor code structure#33

Merged
sehwan505 merged 8 commits intomainfrom
feature/llm-use
Dec 2, 2025
Merged

feat: change llm model and refactor code structure#33
sehwan505 merged 8 commits intomainfrom
feature/llm-use

Conversation

@sehwan505
Copy link
Contributor

@sehwan505 sehwan505 commented Dec 1, 2025

  • LLM 모델 변경
  • 프롬프트 개선
  • LLM 사용 시 빌더 패턴 적용

@sehwan505 sehwan505 marked this pull request as ready for review December 1, 2025 04:59
@sehwan505 sehwan505 requested a review from Copilot December 1, 2025 05:01
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the LLM integration by introducing a builder pattern for LLM requests, changing the default models, improving prompts for more reliable responses, and adding support for MCP (Model Context Protocol) session integration. The key architectural change is replacing the direct Complete() method with a more flexible Request().Execute() pattern that supports different model tiers and reasoning levels.

  • Introduces builder pattern for LLM client with fast (gpt-4o-mini) and power (intended as o3-mini) model tiers
  • Enhances validation prompts with clearer instructions and confidence levels
  • Adds MCP session support for using host LLM instead of direct OpenAI API
  • Removes model selection flags from CLI commands (centralized in code)

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
internal/llm/client.go Major refactor introducing builder pattern, dual-model support, and MCP integration
internal/validator/llm_validator.go Enhanced prompts with confidence levels and improved JSON parsing logic
internal/validator/validator.go Updated to use new builder API
internal/mcp/server.go Added MCP session support for LLM client and context propagation
internal/converter/converter.go Added parallel rule processing and updated to builder API
internal/adapter/*/converter.go Updated all adapters to use new builder API with power model
internal/cmd/*.go Removed model selection flags, updated example documentation
internal/adapter/checkstyle/converter.go Added property validation to prevent invalid configurations
cmd/test-linter/main.go New test utility for ESLint adapter
go.mod, go.sum Removed unused doublestar dependency, reordered entries
tests/e2e/*.go Removed explicit model specifications from tests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

Comment on lines +43 to +44
# Convert for Java with specific model
sym convert -i user-policy.json --targets checkstyle,pmd --openai-model gpt-5-mini
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example references the removed --openai-model flag and uses the non-existent 'gpt-5-mini' model. Since the flag was removed in line 59 of the diff, this example is now invalid and should be removed or updated to reflect the current CLI interface.

Suggested change
# Convert for Java with specific model
sym convert -i user-policy.json --targets checkstyle,pmd --openai-model gpt-5-mini
# Convert for Java linters
sym convert -i user-policy.json --targets checkstyle,pmd

Copilot uses AI. Check for mistakes.
Comment on lines +287 to +324
// parseJSON parses JSON string into the target struct
func parseJSON(jsonStr string, target interface{}) error {
decoder := strings.NewReader(jsonStr)
return decodeJSON(decoder, target)
}

// decodeJSON decodes JSON from a reader (avoiding import cycle with encoding/json)
func decodeJSON(reader *strings.Reader, target interface{}) error {
// Manual parsing for the specific structure we need
content, _ := readAll(reader)

// Parse boolean field "violates"
if resp, ok := target.(*jsonValidationResponse); ok {
resp.Violates = strings.Contains(strings.ToLower(content), `"violates":true`) ||
strings.Contains(strings.ToLower(content), `"violates": true`)

resp.Confidence = extractJSONField(content, "confidence")
resp.Description = extractJSONField(content, "description")
resp.Suggestion = extractJSONField(content, "suggestion")
}

return nil
}

func readAll(reader *strings.Reader) (string, error) {
var builder strings.Builder
buf := make([]byte, 1024)
for {
n, err := reader.Read(buf)
if n > 0 {
builder.Write(buf[:n])
}
if err != nil {
break
}
}
return builder.String(), nil
}
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This custom JSON parsing implementation is unnecessarily complex and error-prone. The comment on line 293 mentions 'avoiding import cycle with encoding/json', but there is no import cycle issue here. The standard library's json.Unmarshal() should be used instead: json.Unmarshal([]byte(jsonStr), target). This would eliminate the need for parseJSON, decodeJSON, and readAll functions while being more reliable.

Copilot uses AI. Check for mistakes.

// Call LLM
response, err := v.client.Complete(ctx, systemPrompt, userPrompt)
// Call LLM with low reasoning (needs thought for code validation)
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Corrected spelling in comment. Should be 'some thought' not just 'thought' for clarity, or simply 'reasoning' since the parameter is already 'reasoning'. Consider: 'Call LLM with reasoning (needs some thought for code validation)' or 'Call LLM with reasoning for code validation'.

Suggested change
// Call LLM with low reasoning (needs thought for code validation)
// Call LLM with reasoning for code validation

Copilot uses AI. Check for mistakes.
Messages: []openAIMessage{
{Role: "system", Content: systemPrompt},
{Role: "user", Content: userPrompt},
{Role: "user", Content: r.system + "\n\n" + r.user},
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combining system and user prompts into a single user message changes the semantic meaning. OpenAI's API treats 'system' and 'user' roles differently - the system message sets the behavior/context for the assistant, while user messages are the actual user input. This combination may reduce the effectiveness of the system prompt. Consider preserving the two-message structure as shown in the removed code (lines 219-221 in the old version).

Suggested change
{Role: "user", Content: r.system + "\n\n" + r.user},
{Role: "system", Content: r.system},
{Role: "user", Content: r.user},

Copilot uses AI. Check for mistakes.
Temperature float64 `json:"temperature,omitempty"`
Model string `json:"model"`
Messages []openAIMessage `json:"messages"`
MaxTokens int `json:"max_completion_tokens,omitempty"`
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field name changed from 'max_tokens' to 'max_completion_tokens'. While 'max_completion_tokens' is the newer OpenAI API parameter name, verify that this is supported by all models being used (gpt-4o-mini and the intended o3-mini). Some older API versions or models may still require 'max_tokens'.

Copilot uses AI. Check for mistakes.

// Call LLM
response, err := c.llmClient.Complete(ctx, systemPrompt, userPrompt)
// Call LLM with power model + low reasoning (needs some thought for linter selection)
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says 'low reasoning' but the code uses llm.ReasoningMedium. These should match - either update the comment to say 'medium reasoning' or change the code to use llm.ReasoningLow.

Suggested change
// Call LLM with power model + low reasoning (needs some thought for linter selection)
// Call LLM with power model + medium reasoning (needs some thought for linter selection)

Copilot uses AI. Check for mistakes.
defaultMaxTokens = 1000
defaultTemperature = 0.3
defaultTimeout = 30 * time.Second
defaultTemperature = 1.0
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temperature of 1.0 is quite high for structured output like JSON. The previous value was 0.3, which is more appropriate for deterministic, structured responses. High temperature (1.0) increases randomness and may result in less consistent JSON formatting, which could cause parsing errors. Consider keeping temperature at 0.3 or at most 0.5 for reliability.

Suggested change
defaultTemperature = 1.0
defaultTemperature = 0.3

Copilot uses AI. Check for mistakes.

jsonStr := response[startIdx : endIdx+1]

// Parse JSON properly using encoding/json
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is misleading because the code does not actually use encoding/json - it uses custom string parsing. Either update the comment to reflect the actual implementation ('Parse JSON using custom string parsing') or refactor to actually use encoding/json as suggested in Comment 3.

Suggested change
// Parse JSON properly using encoding/json
// Parse JSON using custom function, fallback to string-based parsing

Copilot uses AI. Check for mistakes.
@sehwan505 sehwan505 merged commit 7c09c29 into main Dec 2, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants