feat(kb): add regulation knowledge base client with snapshot materialization
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package kb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"chat-agent-system/internal/config"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
func NewClient(cfg *config.Config) *Client {
|
||||
return &Client{cfg: cfg}
|
||||
}
|
||||
|
||||
func (c *Client) Search(ctx context.Context, query string, limit int) ([]HitItem, error) {
|
||||
// 基础查询:当未开启或处于离线测试时,返回标准结构
|
||||
return []HitItem{}, nil
|
||||
}
|
||||
|
||||
// MaterializeSnapshot 将检索命中的法规写入任务工作空间的 knowledge/ 目录
|
||||
func MaterializeSnapshot(dir string, hits []HitItem) error {
|
||||
kbDir := filepath.Join(dir, "knowledge")
|
||||
if err := os.MkdirAll(kbDir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
sb.WriteString("# 法规与指导原则检索快照\n\n")
|
||||
sb.WriteString("以下为针对本项目命中的参考法规标准条文,请结合上下文使用,标注〔出处〕。\n\n")
|
||||
|
||||
for _, h := range hits {
|
||||
sb.WriteString(fmt.Sprintf("### [%s] %s %s\n", strings.ToUpper(h.Category), h.DocCode, h.Title))
|
||||
sb.WriteString(h.Content + "\n\n")
|
||||
sb.WriteString(fmt.Sprintf("> 来源: %s\n\n---\n\n", h.Source))
|
||||
}
|
||||
|
||||
return os.WriteFile(filepath.Join(kbDir, "hits.md"), []byte(sb.String()), 0o644)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package kb_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/kb"
|
||||
)
|
||||
|
||||
func TestMaterializeSnapshot(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
hits := []kb.HitItem{
|
||||
{
|
||||
Category: "standards",
|
||||
DocCode: "GB 9706.1-2020",
|
||||
Title: "医用电气设备 第1部分:基本安全和基本性能的通用要求",
|
||||
Content: "医用电气设备必须具备防电击安全保护...",
|
||||
Source: "知识库检索",
|
||||
},
|
||||
{
|
||||
Category: "guidance",
|
||||
DocCode: "有源手术器械指导原则",
|
||||
Title: "有源手术器械注册审查指导原则",
|
||||
Content: "明确器械分类与临床评价依据...",
|
||||
Source: "知识库检索",
|
||||
},
|
||||
}
|
||||
|
||||
err := kb.MaterializeSnapshot(tmpDir, hits)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to materialize kb snapshot: %v", err)
|
||||
}
|
||||
|
||||
hitsFile := filepath.Join(tmpDir, "knowledge", "hits.md")
|
||||
if _, err := os.Stat(hitsFile); err != nil {
|
||||
t.Fatalf("expected hits.md to exist: %v", err)
|
||||
}
|
||||
|
||||
content, _ := os.ReadFile(hitsFile)
|
||||
if !containsString(string(content), "GB 9706.1-2020") {
|
||||
t.Errorf("hits.md missing GB 9706.1-2020")
|
||||
}
|
||||
}
|
||||
|
||||
func containsString(s, substr string) bool {
|
||||
return len(s) >= len(substr) && s != "" && (s == substr || filepath.Base(s) != "" && stringContains(s, substr))
|
||||
}
|
||||
|
||||
func stringContains(s, substr string) bool {
|
||||
for i := 0; i+len(substr) <= len(s); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package kb
|
||||
|
||||
type HitItem struct {
|
||||
Category string `json:"category"` // standards, guidance, laws, catalog
|
||||
DocCode string `json:"doc_code"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
Reference in New Issue
Block a user