From 1196f409d86bc61e7596eb274840244a62ce84ba Mon Sep 17 00:00:00 2001
From: ai_xiaopei <xiaopei@aisim.cn>
Date: Wed, 29 Jul 2026 14:58:19 +0800
Subject: [PATCH] feat: config priority over env vars, export LoadConfig, add review feature
---
internal/llm/client.go | 98 +++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 87 insertions(+), 11 deletions(-)
diff --git a/internal/llm/client.go b/internal/llm/client.go
index 5ffd7e2..883cc63 100644
--- a/internal/llm/client.go
+++ b/internal/llm/client.go
@@ -70,19 +70,20 @@
// SearchCandidate 搜索候选
type SearchCandidate struct {
- Title string `json:"title"`
- Path string `json:"path"`
- Score float64 `json:"score"`
+ Title string `json:"title"`
+ Path string `json:"path"`
+ Score float64 `json:"score"`
+ Content string `json:"content,omitempty"` // 文件内容(截取前5000字)
}
// NewClient 创建 LLM 客户端
func NewClient() *Client {
- config := loadConfig()
+ config := LoadConfig()
return &Client{config: config, usePrimary: true}
}
-// loadConfig 加载配置文件
-func loadConfig() Config {
+// LoadConfig 加载配置文件(导出供其他包使用)
+func LoadConfig() Config {
var config Config
// 配置文件路径
@@ -193,17 +194,25 @@
}
// GenerateMergeHint 生成合并指示
-func (c *Client) GenerateMergeHint(draftContent string, candidates []SearchCandidate) (*MergeHint, error) {
+func (c *Client) GenerateMergeHint(draftContent string, candidates []SearchCandidate, dirStructure string) (*MergeHint, error) {
prompt := fmt.Sprintf(`你是一个知识库管理助手。请判断以下草稿与哪些知识库文档相关。
+
+## 知识库目录结构
+%s
## 草稿内容
%s
## 候选文档(Top 3)
-`, draftContent)
+`, dirStructure, draftContent)
for i, cand := range candidates {
- prompt += fmt.Sprintf("%d. 标题: %s, 路径: %s, 相关度: %.2f\n", i+1, cand.Title, cand.Path, cand.Score)
+ prompt += fmt.Sprintf("### %d. %s\n", i+1, cand.Title)
+ prompt += fmt.Sprintf("- 路径: %s\n", cand.Path)
+ prompt += fmt.Sprintf("- 相关度: %.2f\n\n", cand.Score)
+ if cand.Content != "" {
+ prompt += fmt.Sprintf("**文档内容**:\n```\n%s\n```\n\n", cand.Content)
+ }
}
prompt += `
@@ -213,7 +222,7 @@
{
"recommendation": {
"action": "merge|new|split",
- "target": "目标路径(如果 action=merge)",
+ "target": "目标路径(如果 action=merge,必须是上述目录结构中存在的目录)",
"reason": "判断理由",
"confidence": "high|medium|low"
},
@@ -228,11 +237,16 @@
判断标准:
- action=merge: 草稿内容与某个候选文档高度相关,应该合并
-- action=new: 草稿内容是全新的,应该新建文档
+- action=new: 草稿内容是全新的,应该新建文档(target 填写建议的目录路径)
- action=split: 草稿内容包含多个独立主题,应该拆分
- confidence=high: 判断很确定
- confidence=medium: 判断比较确定
- confidence=low: 判断不太确定
+
+分类原则:
+- 平台专属内容放对应平台目录下(如电子秤平台/智能枪/)
+- 多平台共用的硬件知识放 共有硬件/ 下
+- 跨平台通用知识放 通用/通用/
只输出 JSON,不要其他内容。`
@@ -249,6 +263,68 @@
return &result, nil
}
+// GenerateReviewPreview 生成审阅预览概要(3句话概括目标FAQ)
+func (c *Client) GenerateReviewPreview(targetTitle, targetContent string) (string, error) {
+ // 截取前2000字符作为上下文
+ contentPreview := targetContent
+ if len(contentPreview) > 2000 {
+ contentPreview = contentPreview[:2000] + "..."
+ }
+
+ prompt := fmt.Sprintf(`请用3句话概括以下知识库文档的核心内容,帮助用户快速了解这个文档讲的是什么:
+
+## 文档标题
+%s
+
+## 文档内容(部分)
+%s
+
+要求:
+1. 第一句:这个文档解决什么问题/讲什么主题
+2. 第二句:核心内容/关键要点
+3. 第三句:适用场景/使用条件
+
+直接输出3句话,不要编号,不要其他内容。`, targetTitle, contentPreview)
+
+ response, err := c.callLLMWithRetry(prompt)
+ if err != nil {
+ return "", err
+ }
+
+ return strings.TrimSpace(response), nil
+}
+
+// ClassifyDocuments 分类文档
+func (c *Client) ClassifyDocuments(prompt string) (string, error) {
+ response, err := c.callLLMWithRetry(prompt)
+ if err != nil {
+ return "", err
+ }
+
+ // 解析 JSON
+ var result []struct {
+ Path string `json:"path"`
+ Platform string `json:"platform"`
+ Device string `json:"device"`
+ ContentType string `json:"content_type"`
+ Confidence float64 `json:"confidence"`
+ }
+
+ if err := parseJSON(response, &result); err != nil {
+ return "", fmt.Errorf("解析 LLM 响应失败: %w", err)
+ }
+
+ // 转换回 JSON 字符串
+ jsonBytes, err := json.Marshal(result)
+ if err != nil {
+ return "", err
+ }
+
+ return string(jsonBytes), nil
+}
+
+// ClassifyDocuments 分类文档
+
// callLLMWithRetry 带重试的 LLM 调用
func (c *Client) callLLMWithRetry(prompt string) (string, error) {
// 第一次尝试
--
Gitblit v1.9.1