package search import ( "context" "net/http" "net/url" ) // aliyunIQSProfile 是阿里云信息查询服务(AI 联网搜索,IQS;design/27 §2.1,分册 15)。 // // 接入形态对本仓最友好:**GET `/search/genericSearch` + `X-API-Key`(免签名、免 SDK)** // ⇒ 标准库即可,恒不破「零新依赖」。 // // 分册 15 确证的两个硬约束: // // - 官方原文:**默认返回网页 10 条,暂不支持调整** ⇒ 本 provider 忽略 Query.Count // (本地截断仍生效,见 io 层的 Finalize)。 // - `mainText` 默认只给**前 500 字符**(要 3000 字需联系客户经理开通)⇒ 正文偏短是 // 上游口径,不是本仓截断。 type aliyunIQS struct{ cfg Config } // aliyunIQSPath 是联网搜索端点路径(分册 15 官方原文:GET /search/genericSearch?query=)。 const aliyunIQSPath = "/search/genericSearch" // newAliyunIQS 造一家阿里云 IQS provider。 func newAliyunIQS(cfg Config) Provider { return &aliyunIQS{cfg: cfg} } // Name 实现 Provider。 func (p *aliyunIQS) Name() string { return NameAliyunIQS } // Search 实现 Provider。 func (p *aliyunIQS) Search(ctx context.Context, q Query) ([]Result, error) { target := baseURLJoin(p.cfg.BaseURL, aliyunIQSPath) + "?query=" + url.QueryEscape(q.Text) data, err := do(ctx, p.cfg, request{ Method: http.MethodGet, URL: target, Headers: map[string]string{"X-API-Key": p.cfg.APIKey}, }) if err != nil { return nil, err } return extractResults(data, aliyunIQSSpec()) } // aliyunIQSSpec 是 IQS 的响应形状(分册 15「响应字段」官方原文确证): // `pageItems[].{title,link,snippet,mainText,markdownText,publishTime,score}`。 // 正文优先取 `mainText`(纯文本,更适合进提示词),其次 `markdownText`。 func aliyunIQSSpec() spec { return spec{ Arrays: []string{"pageItems"}, Title: []string{"title"}, Link: []string{"link"}, Snippet: []string{"snippet"}, Content: []string{"mainText", "markdownText"}, Published: []string{"publishTime"}, Score: []string{"score"}, } }