â»æ¬èšäºã¯ Claude Code ãšã®ååã§å·çãã人éãã¬ãã¥ãŒã®äžæçš¿ããŠããŸãã 1. ã¯ããã« ããã«ã¡ã¯ãå
±éãµãŒãã¹éçºã°ã«ãŒãã®é³¥å±
( @yu_torii )ã§ãã ååã®èšäºã§ã¯ãSlack äžã§ LLM ãæŽ»çšãã瀟å
ãã£ãããããã®å®è£
äºäŸã玹ä»ããŸããã @ card ä»åã¯ããã®ããã¯ããã°ã®ãé¢é£ããèšäºããšãé¢é£ããæ±äººãæ©èœããŒãããåæ§ç¯ãã話ãããŸãã ãé¢é£ããèšäºããé¢é£ããæ±äººããšã¯ åèšäºããŒãžã®äžéšã«ã2ã€ã®ã¬ã³ã¡ã³ãã»ã¯ã·ã§ã³ããããŸãã é¢é£ããèšäº: çŸåšèªãã§ããèšäºãšå
容ãè¿ãèšäºãæå€§12件衚瀺 é¢é£ããæ±äºº: èšäºã®æè¡é åã«é¢é£ãã KINTO Technologies ã®æ±äººæ
å ±ãæå€§8件衚瀺 èªè
ãèå³ã®ããæè¡é åãæ·±æãããå°ç·ã§ãããéå»ã®èšäºã®çºèŠã«ãã€ãªãããŸããæ¡çšãžã®æ¥ç¹ã§ããããŸãã ä»çµã¿ã®åºæ¬ïŒEmbedding ãšã³ãµã€ã³é¡äŒŒåºŠ ãã®æ©èœã®æ žã¯ Embedding ïŒåã蟌ã¿ãã¯ãã«ïŒã§ããEmbedding ã¢ãã«ã«ããã¹ããå
¥åãããšããã®æå³ãè¡šãæ°çŸãæ°å次å
ã®æ°å€ãã¯ãã«ãè¿ã£ãŠããŸããæå³çã«è¿ãããã¹ãå士ã¯ããã¯ãã«ç©ºéäžã§è¿ãäœçœ®ã«é
眮ãããŸãã 2 ã€ã®ãã¯ãã«ã®ãè¿ãããæž¬ãææšã ã³ãµã€ã³é¡äŒŒåºŠ ã§ããå€ã 1 ã«è¿ãã»ã©æå³ãè¿ãã0 ã«è¿ãã»ã©ç¡é¢ä¿ïŒçŽäº€ïŒã§ãããã¹ãŠã®èšäºã Embedding ãããã¢ããšã«ã³ãµã€ã³é¡äŒŒåºŠãèšç®ããŠã¹ã³ã¢ã®é«ãé ã«äžŠã¹ãã°ããé¢é£ããèšäºãã®ã©ã³ãã³ã°ãåŸãããŸãã æ§ã·ã¹ãã ã®èª²é¡ ãã®æ©èœã¯ä»¥åãPython + Azure OpenAI ã® Embedding API ã§å®è£
ãããŠããŸãããéçšãç¶ããäžã§ 3 ã€ã®åé¡ãåºãŠããŸããã å·®åæŽæ°ãç¡ããæ¯åå
šèšäºãå Embed CI ãèµ°ããã³ã«å
šèšäºïŒåœæ 900 ä»¶è¶
ïŒã Azure OpenAI ã«éã£ãŠ Embedding ããŠããŸããã1 èšäºã®è¿œå ã§ãå
šä»¶ååŠçãèµ°ãããã«ãæéã®å€§åãå ããŠããŸããã Azure OpenAI ã® 429 (Rate Limit) ãšã©ãŒãé »çº 900 ä»¶è¶
ã®èšäºãäžæ°ã«éããšãAzure OpenAI ã®ã¬ãŒãå¶éã«é »ç¹ã«ãããããŠããŸããããªãã©ã€ããžãã¯ãå
¥ããŠãã¿ã€ãã³ã°æ¬¡ç¬¬ã§ CI ã倱æããåå®è¡ãå¿
èŠã«ãªãããšãçãããããŸããã§ããã å€éš API äŸå = ã³ã¹ãå¢å Embedding API ã®åŒã³åºãåæ°ããã«ãã®ãã³ã«ç©ã¿äžãããã³ã¹ããå¢ãç¶ããŠããŸãããèšäºæ°ãå¢ããã»ã©ç¶æ³ã¯æªåããæ§é ã§ãã ä»åãã£ãããš ãããã®åé¡ã解決ãããããGo + OllamaïŒããŒã«ã« EmbeddingïŒã§ã·ã¹ãã ãäžããåæ§ç¯ããŸããã SHA-256 ããã·ã¥ã§å€æŽèšäºã ãå Embed ããå·®åæŽæ°ãšãOllama ã«ãã CI ã©ã³ããŒäžã§ã®ããŒã«ã«å®è¡ïŒå€éš API åŒã³åºããŒãïŒã§ãæ§ã·ã¹ãã ã® 3 ã€ã®èª²é¡ãè§£æ¶ããŸããã PoC ã§ã®ã¢ãã«éžå®ããããã©ãŒãã³ã¹æé©åãCI/CD ãã€ãã©ã€ã³ã®æ§ç¯ãŸã§ãå®è£
ã®å
šäœåãæžããŸããéçºã«ã¯ Claude Code ã䜿ããŸããïŒããŸãã§è§ŠããŸãïŒã ãã®èšäºã§åŸãããããš Go + Ollama + Qwen3-Embedding ã§ããŒã«ã« Embedding ã«ããé¡äŒŒåºŠèšç®ãçµãæ¹æ³ Ollama num_ctx ã®ãµã€ã¬ã³ããã©ã³ã±ãŒã·ã§ã³ïŒç¡èŠåã®æååãè©°ãïŒåé¡ äºåæ£èŠåãš min-heap Top-K ã«ããã³ãµã€ã³é¡äŒŒåºŠã©ã³ãã³ã°ã®å¹çå SHA-256 å·®åãã£ãã·ã¥ã§å€æŽèšäºã ãå Embed ããä»çµã¿ :::message ãã®èšäºã®å
容ã¯å·çæç¹ïŒ2026幎4æïŒã®å®è£
ã«åºã¥ããŠããŸããOllama ã Qwen3-Embedding ã®ããŒãžã§ã³ã¢ããã«ãããAPI ã®ä»æ§ãããã©ãŒãã³ã¹ç¹æ§ãå€ããå¯èœæ§ããããŸãããŸããèšäºäžã®ãã³ãããŒã¯å€ã¯ GitHub Actions ã©ã³ããŒã§ã®èšæž¬çµæã§ãããç°å¢ã«ãã£ãŠç°ãªããŸãã ::: 2. PoC æ€èšŒãšã¢ãã«éžå® æ§ã·ã¹ãã ã®èª²é¡ïŒã»ã¯ã·ã§ã³ 1 ã§è¿°ã¹ã 429 ãšã©ãŒã»å
šéå®è¡ã»ã³ã¹ãå¢å ïŒã解決ãããããããŒã«ã« Embedding ãžã®ç§»è¡ã決ããŸãããGo ã§äœ¿ãã Embedding ã©ã€ãã©ãªã 3 ã€ã®æ¹åŒã§ PoC æ€èšŒããŸããã 3 ã€ã® PoC ã¢ãããŒã æ¹åŒ 1: hugotïŒPure Go ONNX ã©ã³ã¿ã€ã ïŒ knights-analytics/hugot 㯠Go ãã€ãã£ãã® ONNX ã©ã³ã¿ã€ã ã§ãbge-m3 ã Qwen3 ã® ONNX ã¢ãã«ãçŽæ¥å®è¡ã§ããŸããcgo äžèŠã§ãããONNX ã¢ãã«ãã¡ã€ã«ã®ãµã€ãºã巚倧ïŒbge-m3 ã§çŽ 2.2GBïŒã§ãCI ç°å¢ã§ã®ããŠã³ããŒããšã¡ã¢ãªç®¡çã«èª²é¡ããããŸããã æ¹åŒ 2: kelindar/searchïŒllama.cpp via puregoïŒ kelindar/search ã¯äžèŠ Pure Go ã«èŠããŸãããå
éšã§ã¯ purego çµç±ã§ llama.cpp ã®ãã€ããªãåŒã³åºããŠããŸããcgo ã¯äœ¿ã£ãŠããŸããããå®è³ªçã« llama.cpp ãã€ããªãžã®å€éšäŸåããããŸããããcgo äžèŠãã®è¡šé¢çãªç¹åŸŽã«æããããããæ¡ä»¶ã§ãã æ¹åŒ 3: Ollama APIïŒHTTP ã¯ã©ã€ã¢ã³ãïŒ éžãã ã®ã¯ Ollama ã® HTTP API ã Go ã¯ã©ã€ã¢ã³ãããåŒã¶æ¹åŒã§ãã client, err := api.ClientFromEnvironment() if err != nil { slog.Error("Ollama ã¯ã©ã€ã¢ã³ãäœæå€±æ", "error", err) os.Exit(1) } resp, err := client.Embed(ctx, &api.EmbedRequest{ Model: model, Input: testTexts, }) æ¯èŒè¡š æ¹åŒ cgo ã¢ãã«ç®¡ç ãããå¯Ÿå¿ ã³ã³ããã¹ãå¶åŸ¡ å€å® hugot (ONNX) äžèŠ æå â à Ⳡã¢ãã«ãµã€ãºåé¡ kelindar (llama.cpp) purego çµç±ã§äžèŠã«èŠããã llama.cpp ãã€ããªäŸå æå à à à å®è³ªå€éšäŸå Ollama API äžèŠ èªå â â ( num_ctx ) â éžå®ã®æ±ºãæ cgo äžèŠã§ GOOS=linux GOARCH=arm64 go build äžçºã®ã¯ãã¹ã³ã³ãã€ã«ãå£ããªããOllama ãã¢ãã«ã®ããŠã³ããŒãããã©ã€ããµã€ã¯ã«ç®¡çãŸã§æ
ããããã Embed API ã§è€æ°ããã¹ããäžåºŠã«éä¿¡ã§ããã num_ctx ã§ã³ã³ããã¹ããŠã£ã³ããŠãæç€ºå¶åŸ¡ã§ããã ãªã Qwen3-Embedding-0.6B ã Qwen3-Embedding-0.6B ãéžãã çç±ã¯ã2025 幎ãªãªãŒã¹ã®ææ°ã¢ãã«ã§ãéåååŸ 639MB ãš CI ã©ã³ããŒã®ã¡ã¢ãªã«åãŸããµã€ãºã ã£ãããšã1024 次å
ãã¯ãã«ã§è¡šçŸåãšèšç®éã®ãã©ã³ã¹ãè¯ããæ¥æ¬èªã»è±èªã®ãã€ãªã³ã¬ã«ãµããŒãã¯ãåœããã°ã®éçšäžã®å¿
é èŠä»¶ã§ãããRAG ã®æ€çŽ¢ç²ŸåºŠãæ±ããããã¿ã¹ã¯ã§ã¯ãªãé¢é£èšäºã®æšèŠçšéãªã®ã§ãæé«ç²ŸåºŠã¢ãã«ã¯äžèŠã§ãã :::details éååãšã¯ éååïŒQuantizationïŒã¯ãã¢ãã«ã®éã¿ïŒãã©ã¡ãŒã¿ïŒãå
ã®ç²ŸåºŠïŒéåžž float16 = 16bitïŒããããå°ãªããããæ°ïŒ8bitã4bit ãªã©ïŒã«å€æããææ³ã§ãã粟床ã¯ãããã«äœäžããŸãããã¢ãã«ãµã€ãºãšã¡ã¢ãªäœ¿çšéã倧å¹
ã«åæžã§ããŸãã Qwen3-Embedding-0.6B 㯠Ollama ã§ Q8_0ïŒ8bit éååïŒ ãšããŠé
åžãããŠããã595M ãã©ã¡ãŒã¿ã§ 639MBãäžæ¹ãbge-m3 㯠F16ïŒ16bitïŒé
åžã®ããããã©ã¡ãŒã¿æ°ã¯ã»ãŒåãïŒ568MïŒã§ããµã€ãºã 1.2GB ãšçŽ 2 åã«ãªããŸãã ::: :::message PoC ã®æ®µéã§ã¯ bge-m3 ãåè£ã§ããããã¢ãã«ãµã€ãºã ãã§ãªããã³ãããŒã¯ã§ã Qwen3 ãåªäœã§ããã MTEB ãã³ãããŒã¯ ã®è±èªæ€çŽ¢ïŒ61.82 vs 57.03ïŒãå€èšèªæ€çŽ¢ïŒ64.64 vs 58.36ïŒãã³ãŒãæ€çŽ¢ïŒ75.41 vs 41.38ïŒã§ Qwen3-Embedding-0.6B ãäžåã£ãŠããŸããbge-m3 ãåªäœãªã®ã¯é·ææ€çŽ¢ïŒMLDR: 59.51 vs 50.26ïŒã§ãããå
é 4000 æåã«åãè©°ããæ¬ã·ã¹ãã ã§ã¯è©²åœããŸãããOllama ã§ã®ã¢ãã«ãµã€ãºãçŽååïŒ639MB vs 1.2GBïŒã§ãCI ãã£ãã·ã¥ã®å¹çãå«ããŠç·åçã« Qwen3 ãéžæããŸããã ::: 3. ã¢ãŒããã¯ãã£ã®å
šäœå ãã€ãã©ã€ã³ flowchart LR A["_posts/*.md"] --> B["Markdown<br>ã¯ãªãŒãã³ã°"] B --> C["Ollama Embed API<br>(Qwen3-Embedding)"] C --> D["SHA-256<br>ãã£ãã·ã¥"] D --> E["ã³ãµã€ã³é¡äŒŒåºŠ<br>ã©ã³ãã³ã°"] E --> F["related_posts.json"] Markdown ãã¯ãªãŒãã³ã°ã㊠Ollama ã§ Embedding ãååŸããã³ãµã€ã³é¡äŒŒåºŠã§ã©ã³ãã³ã°ã㊠JSON ãåºåããŸãã ããã±ãŒãžæ§æ cmd/related-content-gen/ âââ main.go # CLI ãšã³ããªãã€ã³ã âââ internal/ â âââ markdown/ # Markdown ããŒã¹ã»ã¯ãªãŒãã³ã° â â âââ cleaner.go # frontmatter é€å»ãURL/assets é€å» â â âââ parser.go # _posts/*.md ã®èªã¿èŸŒã¿ â âââ embedding/ # Ollama ã¯ã©ã€ã¢ã³ãã»ãã£ãã·ã¥ â â âââ client.go # Embed API ã©ãããŒïŒnum_ctx å¶åŸ¡ïŒ â â âââ cache.go # SHA-256 ããã·ã¥ããŒã¹ã®å·®åæŽæ° â âââ similarity/ # é¡äŒŒåºŠèšç®ã»ã©ã³ãã³ã° â â âââ cosine.go # ã³ãµã€ã³é¡äŒŒåºŠïŒãã¹ãçšïŒ â â âââ ranking.go # L2æ£èŠå + dotProductãmin-heap Top-K â âââ output/ # JSON åºå â âââ json.go # UTF-8ã4ã¹ããŒã¹ã€ã³ãã³ããHTMLãšã¹ã±ãŒããªã âââ go.mod internal ããã±ãŒãžã«åé¢ããããšã§ãåããã±ãŒãžãåäžè²¬ä»»ãæã¡ãç¬ç«ããŠãã¹ãå¯èœã«ãªã£ãŠããŸãã run() 颿°ã®ãã€ãã©ã€ã³ ã¡ã€ã³åŠç㯠run() 颿°ã«éçŽãããŠããŸãã func run(...) error { // 1. èšäºã®èªã¿èŸŒã¿ãšã¯ãªãŒãã³ã° posts, err := markdown.ParsePosts(postsDir) // 2. Ollama ã¯ã©ã€ã¢ã³ãäœæ client, err := embedding.NewClient(ollamaURL, model, numCtx) // 3. ãã£ãã·ã¥èªã¿èŸŒã¿ â äžèŠãšã³ããªåé€ â 倿Žèšäºæ€åº cache, err := embedding.LoadCache(cacheFile) cache.Prune(posts) dirty := cache.FindDirty(posts, model) // 4. 倿Žåã®ã¿ EmbedïŒ1ä»¶ãã€åŠçããŠéœåºŠãã£ãã·ã¥ä¿åïŒ for _, p := range dirty { vectors, err := client.Embed(ctx, []string{text}) cache.Entries[p.Slug] = embedding.CacheEntry{...} cache.Save(cacheFile) // äžæèæ§ã®ããæ¯åä¿å } // 5. ã³ãµã€ã³é¡äŒŒåºŠã§ã©ã³ãã³ã° rankings := similarity.RankRelatedPosts(postVectors, 12) // 6. JSON åºå output.WriteJSON(outPath, postsOutput) } Next.js ããã³ããšã³ããšã®é£æº åºåããã JSON 㯠Next.js ã® getStaticProps ã§ãã«ãæã«èªã¿èŸŒãŸããŸãã static/related_posts/related_posts.json â lib/related_posts.ts ãèªã¿èŸŒã¿ ããã³ããšã³ãåŽã§ã¯ãJSON ã«é¢é£èšäºããŒã¿ãããã°ããã䜿ããç¡ããã°ã«ããŽãªããŒã¹ã®ãã©ãŒã«ããã¯ã«åãæ¿ãããŸããGo CLI ãšããã³ããšã³ãã®éã®å¥çŽã¯ããã® JSON ã¹ããŒãã ãã§ãã 4. Markdown ã®ã¯ãªãŒãã³ã°ãšååŠç åœããã°ã®èšäºã¯ Zenn Markdown ïŒ :::message ã :::details ã @[card]() ãªã©ïŒã§æžãããŠããŸããåèšäºãã¡ã€ã«ã®å
é ã«ã¯ YAML frontmatterïŒã¿ã€ãã«ãèè
ãå
¬éæ¥ãã«ããŽãªãªã©ã®ã¡ã¿æ
å ±ïŒãããããããããã®ãŸãŸ Embed ãããšãã€ãºã«ãªããŸãã ã¯ãªãŒãã³ã°ãã€ãã©ã€ã³ frontmatter ã®åé¢: --- ã§å²ãŸãã YAML ããããŒããã¿ã€ãã«ã ãæœåºããæ®ãã®ã¡ã¿æ
å ±ïŒauthor, date, category çïŒã¯é€å» URL ã®é€å»: http:// / https:// ã§å§ãŸããã¹ãŠã® URL ãé€å» ã¢ã»ãããªã³ã¯ã®é€å»: /assets/ ãå«ããªã³ã¯ïŒç»åãã¹ãªã©ïŒãé€å» ã¯ãªãŒãã³ã°ã®ãšã³ããªãã€ã³ã㯠CleanMarkdown 颿°ã§ãfrontmatter ããã¿ã€ãã«ãæœåºãã€ã€ãæ¬æã®ãã€ãºãé€å»ããŸããfrontmatter ããŒã¹ã«ã¯ strings.Cut ã䜿ãã --- ããªãã¿éã® YAML ã gopkg.in/yaml.v3 ã§è§£æããŠããŸãã :::details ã³ãŒãã®è©³çްïŒcleaner.go / parser.goïŒ var ( reURL = regexp.MustCompile(`https?://[^\s)\]>]+`) reAsset = regexp.MustCompile(`!?\[[^\]]*\]\(/assets/[^)]+\)|/assets/[^\s)]+`) ) func CleanMarkdown(raw []byte) (title, content string) { s := string(raw) if len(s) == 0 { return "", "" } title, body := splitFrontmatter(s) body = removeURLs(body) body = removeAssetLinks(body) return title, body } func splitFrontmatter(s string) (title, body string) { const delimiter = "---" _, after, ok := strings.Cut(s, delimiter) if !ok { return "", s } before, after, ok := strings.Cut(after, delimiter) if !ok { return "", s } var fm frontmatter if err := yaml.Unmarshal([]byte(before), &fm); err == nil { title = fm.Title } return title, after } type Post struct { Slug string // ãã¡ã€ã«åãã .md ãé€å» Title string // frontmatter ã® title ãã£ãŒã«ã Content string // ã¯ãªãŒãã³ã°æžã¿æ¬æ } func ParsePosts(dir string) ([]Post, error) { entries, err := os.ReadDir(dir) // ... *.md ãã¡ã€ã«ãèªã¿èŸŒã¿ãCleanMarkdown ã§åŠç return posts, nil } ::: ãã€ã³ãã¯ãEmbedding æã«ã¿ã€ãã«ãããã¹ãã®å
é ã«çµåããããšïŒ title + "\n" + content ïŒãã»ã¯ã·ã§ã³ 5.1 ã§è¿°ã¹ãŸãããEmbedding ã¢ãã«ã¯ããã¹ãã®å
é éšåãéèŠããåŸåããããããã¿ã€ãã«ã®æ
å ±ããã¯ãã«ã«åŒ·ãåæ ãããŸãã 5. Embedding ã®æé©å Embedding åŠçã®é«éåã§ 2 ã€ã®å·¥å€«ãããŸããã 5.1 : ããã¹ããå
é 4,000 æåã«åãè©°ããŠåŠçæéãçŽ 1/8 ã«ççž® 5.2 : å®è£
äžã«èžãã Ollama num_ctx ã®ç¡èŠååãè©°ãåé¡ 5.1 ããã¹ãåãè©°ãã®æé©å æåã¯èšäºã®å
šæããã®ãŸãŸ Ollama ã«éã£ãŠããŸãããCI ã§å®è¡ãããšãå
šèšäºã® Embedding ã«æ°åæéãããèšç®ã§ããå
šæãæ¬åœã«å¿
èŠãªã®ããæ€èšŒããŸããã ãŸããå
šèšäºã®ã¯ãªãŒãã³ã°æžã¿ããã¹ãé·ã®ååžã調ã¹ãŸããã å¹³å: çŽ 8,000 æå äžå€®å€: çŽ 6,300 æå äžäœ 10%: 14,600 æåä»¥äž æå€§: 53,000 æåè¶
倧åã®èšäºã¯ 10,000 æå以å
ã«åãŸããŸãããäžéšã®é·æèšäºã¯ 40,000 æåãè¶
ããŸããé·ãèšäºã®åŸåã«ã¯åèæç®ãªã¹ããè£è¶³æ
å ±ãå€ããèšäºã®ããŒãã衚ãæ
å ±ã¯å
é ã«éäžããåŸåããããŸããã ããã§ãå
é N æåã«åãè©°ããŠãå質ãç¶æã§ãããïŒããæ€èšŒãããããé·æã®äžäœ 5 èšäºã§ å
šæ EmbeddingïŒ num_ctx=8192 æç€ºæå®ïŒãããŒã¹ã©ã€ã³ ãšããŠãåãè©°ãæåæ°ãå€ããŠé¡äŒŒåºŠãšéåºŠãæ¯èŒããŸããã åãè©°ã ããŒã¹ã©ã€ã³ãšã®é¡äŒŒåºŠ å¹³åé床 é«éå å
šæ 1.000 229 ç§ 1.0x 2,000 æå 0.868 13 ç§ 17.6x 4,000 æå 0.887 29 ç§ 7.9x 6,000 æå 0.902 42 ç§ 5.5x 8,000 æå 0.909 53 ç§ 4.3x 4,000 â 8,000 æåã«å¢ãããŠãé¡äŒŒåºŠã®æ¹å㯠+2.2 ãã€ã³ã ïŒ0.887 â 0.909ïŒã«çãŸããŸãããé床㯠1.8 åé
ããªããŸããé¢é£èšäºã®ã©ã³ãã³ã°å質ã«åœ±é¿ãåºãªãããšãæ¬çªããŒã¿ã§ç¢ºèªããäžã§ã å
é 4,000 æå + num_ctx=8192 ãæ¡çšããŸããã :::message ãªãå
é ã®åãè©°ããæå¹ãïŒ 2 ã€ã®èŠå ãçžä¹ããŠããŸãã ã¢ãã«ã®äœçœ®ãã€ã¢ã¹ : Transformer ããŒã¹ã® Embedding ã¢ãã«ã§ã¯ãããã¹ãå
é ãžã®æ¹ä¹±ããã¯ãã«ã«äžãã圱é¿ãæ«å°ŸããçŽ 15% 倧ããããšãå ±åãããŠããŸãïŒ arXiv:2412.15241 ïŒãQwen3-Embedding ã RoPE ãæ¡çšãã Transformer ã¢ãã«ã§ãããåæ§ã®åŸåããããšèããããŸãã ã³ã³ãã³ãã®æ§é ãã€ã¢ã¹ : æè¡ããã°ã¯ãã¿ã€ãã«âå°å
¥âæŠèŠâ詳现ãã®éãã©ãããæ§é ãæã¡ãããŒãæ
å ±ãåé ã«éäžããŸãïŒãããã Lead Bias ïŒã ::: 5.2 Ollama ã® num_ctx ã«æœãèœãšã穎 5.1 ã®æ€èšŒã«å
¥ãåã«ã num_ctx åšãã§çœ ãèžã¿ãŸãããOllama ã§ Embedding ãæ±ã人ã¯å
šå¡åŒã£ãããããåé¡ã§ãã äœãèµ·ããã åãè©°ããæ€èšŒããåã«ããŸã num_ctx ã®å¹æã確èªããããšæ¬¡ã® 2 ãã¿ãŒã³ã§å
šæ Embedding ãæ¯èŒããŸããã A: å
šæ + num_ctx=4096 B: å
šæ + num_ctx=8192 A ãš B ã®ã³ãµã€ã³é¡äŒŒåºŠãå
šèšäºã§ 1.000 ã§ãããå®å
šã«åäžã®ãã¯ãã«ã§ããåŠçæéãå¹³åçŽ 70 ç§ã§å·®ããªãã35,000 æåè¶
ã®èšäºã§ã³ã³ããã¹ãé·ãåã«ããã®ã«ãçµæãå€ãã£ãŠããŸããã èšäº æåæ° å¹³ååŠçæé(ç§) A-B é¡äŒŒåºŠ torii-ai_tool_slack 35,417 68 1.000 Android-Compose-OO-Nav 37,803 76 1.000 aurora-mysql-stats 32,648 71 1.000 Jetpack-Compose-Anim 34,621 65 1.000 SecureDBPassword 38,978 69 1.000 å¹³å çŽ 70 ç§ 1.000 åå : Options ã«å
¥ããªããš num_ctx ã¯å¹ããªã num_ctx ã EmbedRequest.Options ã§ æç€ºçã«æž¡ããªãéã ãOllama 㯠VRAM ã«å¿ããããã©ã«ãå€ ïŒ24GiB æªæºã§ 4kã24-48GiB ã§ 32kã48GiB 以äžã§ 256kã OLLAMA_CONTEXT_LENGTH ç°å¢å€æ°ã§å€æŽå¯èœïŒã䜿ããè¶
éåãç¡èŠåã§åãè©°ããŸãã ãã¿ãŒã³ B ã§ num_ctx=8192 ãèšå®ããã€ããããAPI ã® Options ã«æž¡ãããŠããããA ãšåã 4096 ããŒã¯ã³ã§åŠçãããŠããŸãããé¡äŒŒåºŠ 1.000 ã¯ãäž¡æ¹ãšãåãå
¥åãåŠçããŠãã蚌æ ã§ãã :::message alert 泚æ: Ollama ã¯å
¥åããã¹ããã³ã³ããã¹ãé·ãè¶
ããŠããšã©ãŒãè¿ããŸãããAPI ã¬ã¹ãã³ã¹ã«ãåãè©°ãã®æç¡ã瀺ããã£ãŒã«ãããããŸãããæå³ããäžå®å
šãª Embedding ãçæãããå¯èœæ§ããããŸãããã㯠Ollama ã® Issue #14259 ã§ãå ±åãããŠããŸãã ::: ä¿®æ£ãšå¹æã®ç¢ºèª num_ctx ã EmbedRequest.Options ã§æç€ºçã«æž¡ãããä¿®æ£ããã®ããæ¬¡ã®å®è£
ã§ãã func (c *Client) Embed(ctx context.Context, texts []string) ([][]float32, error) { req := &api.EmbedRequest{ Model: c.model, Input: texts, } if c.numCtx > 0 { req.Options = map[string]any{"num_ctx": c.numCtx} } resp, err := c.api.Embed(ctx, req) if err != nil { return nil, fmt.Errorf("Ollama Embed API ãšã©ãŒ: %w", err) } // ã¬ã¹ãã³ã¹ã®ããªããŒã·ã§ã³ïŒä»¶æ°ã»ç©ºãã¯ãã«ãã§ãã¯ïŒ if len(resp.Embeddings) != len(texts) { return nil, fmt.Errorf("ã¬ã¹ãã³ã¹æ°ãäžäžèŽ: %d embeddings / %d texts", len(resp.Embeddings), len(texts)) } return resp.Embeddings, nil } ä¿®æ£åŸã¯ A-B é¡äŒŒåºŠã 0.947 ã«äžãããB ã®åŠçæé㯠A ã®çŽ 3 åïŒ229 ç§ vs 78 ç§ïŒã«ãªããŸããã8192 ããŒã¯ã³åãåŠçããŠããããšãæéãããè£ä»ããããŸãã èšäº æåæ° A(ç§) B(ç§) A-B é¡äŒŒåºŠ torii-ai_tool_slack 35,417 77 224 0.969 Android-Compose-OO-Nav 37,803 81 218 0.920 aurora-mysql-stats 32,648 84 224 0.919 Jetpack-Compose-Anim 34,621 74 243 0.947 SecureDBPassword 38,978 73 238 0.977 å¹³å 78 229 0.947 CLI ã®ããã©ã«ãå€ã¯ --num-ctx=8192 ã«èšå®ãã4000 æååãè©°ããšçµã¿åãããããšã§ç¡èŠåã®æååãè©°ããçºçããªãããšãä¿èšŒããŠããŸãã Ollama å©çšè
ãžã®æèš Ollama ã§ Embedding ã LLM ãæ±ããªãïŒ num_ctx 㯠Modelfile ã® PARAMETER ããAPI ã® Options.num_ctx ã§ æç€ºçã«èšå®ãã å
¥åã®ããŒã¯ã³æ°ãäºåã«ææ¡ããã³ã³ããã¹ãé·ã«åãŸãã確èªãã é¡äŒŒåºŠãå質ãããªããå€ãããªãããšãã¯ãç¡èŠååãè©°ããçã 5.3 ã³ãŒããããã¯ã¯æ®ãã¹ããïŒ å
é 4000 æåã®ãã¡ãã³ãŒããããã¯ã倧éã«å«ãŸããèšäºããããŸããAndroid Compose ã®ããã²ãŒã·ã§ã³èšäºã§ã¯ 2,213 æåïŒ55%è¶
ïŒãã³ãŒãã§ãããã³ãŒããé€å»ããŠæ¬æãå¢ããæ¹ãè¯ãããã«æããŸãã æ¥è±ç¿»èš³ãã¢ïŒåã postId ã§ locale ãç°ãªãèšäºïŒã®ã³ãµã€ã³é¡äŒŒåºŠã§æ€èšŒããŸããã ã³ãŒããããã¯ãã: 0.893 ã³ãŒããããã¯é€å»: 0.868 ã³ãŒããããã¯ãé€å»ãããšé¡äŒŒåºŠãäžãããŸããã ã¯ã©ã¹åã颿°åãã©ã€ãã©ãªåïŒ NavHost ã Composable ã goroutine ãªã©ïŒã¯èšèªã«äŸåããŸãããæ¥æ¬èªã®èšäºã§ãè±èªã®èšäºã§ããåãæè¡ãªãã³ãŒãäžã«åãããŒã¯ãŒããåºçŸããŸããã³ãŒããããã¯ã¯ã¯ãªãŒãã³ã°å¯Ÿè±¡ããé€å€ïŒæ®ãïŒãšããŸããã åãè©°ãã®å®è£
const maxEmbedRunes = 4000 for _, p := range dirty { text := p.Title + "\n" + p.Content if p.Content == "" { text = p.Title } if runes := []rune(text); len(runes) > maxEmbedRunes { text = string(runes[:maxEmbedRunes]) } vectors, err := client.Embed(ctx, []string{text}) // ... } []rune ã«å€æããŠããã¹ã©ã€ã¹ããããšã§ããã«ããã€ãæåïŒæ¥æ¬èªïŒã®éäžã§åããããšãé²ãã§ããŸãã 6. SHA-256 å·®åãã£ãã·ã¥ã«ããå¹çå ã»ã¯ã·ã§ã³ 1 ã§è¿°ã¹ããæ¯åå
šéå®è¡ãã®åé¡ã解決ãããããå·®åãã£ãã·ã¥ãå°å
¥ããŸããããååããäœãå€ãã£ããããé«éã«å€å®ããå¿
èŠããããŸããããã¡ã€ã«ã®æŽæ°æ¥æïŒmtimeïŒã¯ Git ã®ãã§ãã¯ã¢ãŠãã§ãªã»ããããããã CI ç°å¢ã§ã¯äœ¿ããŸãããããã§ãã³ã³ãã³ãèªäœã® SHA-256 ããã·ã¥ã§å€æŽãæ€ç¥ããæ¹åŒãæ¡çšããŸããã ãã£ãã·ã¥ã®èšèš type Cache struct { Version int `json:"version"` ModelName string `json:"model_name"` Entries map[string]CacheEntry `json:"entries"` } type CacheEntry struct { ContentHash string `json:"content_hash"` Vector []float32 `json:"vector"` } SHA-256 ã«ãã倿޿€ç¥ èšäºã®ã¿ã€ãã«ã𿬿ãçµåã㊠SHA-256 ããã·ã¥ãèšç®ããååã®ãã£ãã·ã¥ãšæ¯èŒããŸãã func ContentHash(title, content string) string { h := sha256.New() h.Write([]byte(title + "\n" + content)) return hex.EncodeToString(h.Sum(nil)) } func (c *Cache) FindDirty(posts []markdown.Post, modelName string) []markdown.Post { if c.ModelName != modelName { return posts // ã¢ãã«å€æŽ â å
šèšäºãåEmbed } var dirty []markdown.Post for _, p := range posts { entry, ok := c.Entries[p.Slug] if !ok || entry.ContentHash != ContentHash(p.Title, p.Content) { dirty = append(dirty, p) } } return dirty } ã¢ãã«åãå€ãããšå
šèšäºã dirty ã«ãªããŸããEmbedding ã¢ãã«ãå€ããã°æ¬¡å
æ°ããã¯ãã«ç©ºéãç°ãªããããå€ããã£ãã·ã¥ã¯ç¡å¹ã§ãã ãã£ãã·ã¥ãã㌠flowchart TB A["èšäºèªã¿èŸŒã¿<br>(956ä»¶)"] --> B["ãã£ãã·ã¥èªã¿èŸŒã¿"] B --> C{"ã¢ãã«å€æŽ?"} C -->|Yes| D["å
šèšäºãEmbed"] C -->|No| E["SHA-256æ¯èŒ"] E --> F{"倿Žãã?"} F -->|Yes| G["倿Žåã®ã¿Embed"] F -->|No| H["ã¹ããã"] D --> I["1ä»¶ãã€ä¿å<br>(äžæèæ§)"] G --> I Embed ã®ãã³ã«ãã£ãã·ã¥ãã¡ã€ã«ãä¿åããŸããCI ã®ã¿ã€ã ã¢ãŠããäžæãèµ·ããŠãããããŸã§åŠçããåã¯ãã£ãã·ã¥ã«æ®ããŸããæ¬¡åå®è¡æã¯äžæç®æããåéã§ãããããååã®å
šé Embedding ãè€æ°åã«åããŠé²ããããŸãã ååæ§ç¯ã§å¹ãããäžæèæ§ã ãã®ã1 èšäºããšã« cache ãã¡ã€ã«ãžä¿åããšããèšèšããååæ§ç¯ã§å®éã«åœ¹ã«ç«ã¡ãŸããã åœæ 956 ä»¶ãã£ãå
šèšäºã®ååå
šéãã«ãã§ã¯ãOllama ã§ã® Embedding åŠçã GitHub Actions ã® job timeoutïŒ timeout-minutes: 60 ïŒã«åãŸããã5 åé£ç¶ã§ 60 å timeout ã«å°éããŸãããããã§ã 6 åç®ã® run ã§å®èµ°ã§ããã®ã¯ãå cancelled run ã§å®äºããŠããåã® Embedding ãæ¬¡ã® run ã«åŒãç¶ãããããã§ãã run çµæ Generate related content 1 ã 5 åç® timeout å 60 å 6 åç® success 55 å çŽ¯èš çŽ 6 æé ãããæç«ãããã®ã¯ 2 ã€ã®åã¿åããã§ãã ã¢ããªåŽ : 1 èšäº Embed ããããšã« output/embeddings_cache.json ãžä¿å CI åŽ : actions/cache/save@v5 ã if: always() ã§èµ°ããã - name: Save embeddings cache if: always() # timeout/cancel æã cache save ãèµ°ããã uses: actions/cache/save@v5 with: path: output/embeddings_cache.json key: embeddings-cache-${{ hashFiles('_posts/**') }}-${{ github.run_id }} if: always() ãä»ããŠãããšãjob ã timeout/cancel ã§çµãããšãã«ã cache save ã¹ããããèµ°ããŸããçµæãéäžãŸã§åŠçãã Embedding 㯠cache ã«æ®ããæ¬¡ run 㯠restore-keys ã®ãã©ãŒã«ããã¯ã§å run ã® cache ãæŸã£ãŠæ®ãåããç¶è¡ã§ããã ãã®ä»çµã¿ããªããã°ã60 å timeout ã§æ¯å Embedding ãå·»ãæ»ãã6 æéã§å®èµ°ããããšã¯ãªãã£ãã¯ãã§ãã 7. ã³ãµã€ã³é¡äŒŒåºŠã©ã³ãã³ã°ã®æé©å Embedding ãã¯ãã«ãåŸãããããèšäºéã®é¡äŒŒåºŠãèšç®ããŠã©ã³ãã³ã°ãçæããŸãã956 èšäºã®åèšäºãä»ã® 955 ä»¶ãšæ¯èŒãããããçŽ 91 äžåã®å
ç©èšç®ãèµ°ããŸãããã®èŠæš¡ãªã FAISS çã® ANNïŒè¿äŒŒæè¿åæ¢çŽ¢ïŒã©ã€ãã©ãªãå°å
¥ããããããbrute-force ã®æ¹ãã·ã³ãã«ã§äŸåãå¢ããŸããã æåã®å®è£
ïŒæ¯åãã«ã èšç® + å
šä»¶ãœãŒãïŒã§ã¯ãã¹ãã§çŽ 1.6 ç§ããã£ãŠããŸãããäºåæ£èŠå + min-heap ãžã®å€æŽãšãã«ãŒãã¢ã³ããŒãªã³ã°ã® 2 段éã§ 730ms ãŸã§æ¹åããŸããã :::::details æé©åã®è©³çް 1. äºåæ£èŠå (Pre-normalization) ã³ãµã€ã³é¡äŒŒåºŠã®åŒã¯ä»¥äžã§ãã $$ \cos(a, b) = \frac{a \cdot b}{|a| \times |b|} $$ æ¯å 2 ã€ã®ãã¯ãã«ã®é·ãïŒãã«ã $|a|$ïŒãèšç®ããã®ã¯ç¡é§ãªã®ã§ãå
šãã¯ãã«ã®é·ããäºåã« 1 ã«æããŠãããŸãïŒæ£èŠåïŒããããšåæ¯ã $1 \times 1 = 1$ ã«ãªããã³ãµã€ã³é¡äŒŒåºŠã¯å
ç© $a \cdot b$ïŒåèŠçŽ ãæããŠè¶³ãã ãïŒãšçãããªããŸããæ£èŠåã¯èšäºæ°åïŒ956åïŒã ãããã®åŸã® 91 äžåã®ãã¢æ¯èŒã§ã¯æãç®ãšè¶³ãç®ã ãã§æžã¿ãŸãã :::details ã³ãµã€ã³é¡äŒŒåºŠã®è£è¶³ å
ç© $a \cdot b$ 㯠2 ã€ã®ãã¯ãã«ã®åèŠçŽ ãæããŠè¶³ããå€ã§ããæå³ãè¿ãèšäºå士ã¯å
ç©ã倧ãããªããŸãããé·ãèšäºã®ãã¯ãã«ã¯å€ã倧ãããªããã¡ã§ãå
ç©ã ãã ãšããã¯ãã«ã®é·ããã«åŒã£åŒµãããŸãããã«ã $|a|$ ã§å²ãããšã§é·ãã®åœ±é¿ãæ¶ããçŽç²ã«ãåããïŒæå³ã®è¿ãïŒã ããæ¯èŒããã®ãã³ãµã€ã³é¡äŒŒåºŠã§ããçµæã¯ $-1$ ã $1$ ã®ç¯å²ã§ã1 ã«è¿ãã»ã©æå³ãè¿ãã æ£èŠåãšã¯ãåèŠçŽ ããã«ã ã§å²ã£ãŠãã¯ãã«ã®é·ãã 1 ã«ããåŠçã§ããåãã¯ãã®ãŸãŸãé·ãã ãæããŸãã å
: a = [3, 4] â é·ã = â(9+16) = 5 æ£èŠå: a' = [0.6, 0.8] â é·ã = â(0.36+0.64) = 1 ::: 2. min-heap Top-K å
š 955 ä»¶ã®ã¹ã³ã¢ã sort.Slice ã§ãœãŒãããŠããŸããããå®éã«å¿
èŠãªã®ã¯äžäœ 12 ä»¶ã ãããµã€ãº 12 ã® min-heapïŒGo æšæºã©ã€ãã©ãªã® container/heap ïŒã䜿ããã¹ã³ã¢ãæå°å€ãã倧ãããã°å
¥ãæ¿ããæ¹åŒã«å€æŽãèšç®é㯠$O(N \log N)$ ãã $O(N \log K)$ ã«æ¹åããŸãã 3. ã«ãŒãã¢ã³ããŒãªã³ã° å
ç©èšç®ã®ããããã¹ïŒçŽ 91 äžå à 1024 次å
ïŒã« 4-way ã«ãŒãã¢ã³ããŒãªã³ã°ãé©çšã4 ã€ã®ç¬ç«ããã¢ãã¥ã ã¬ãŒã¿å€æ°ã䜿ãããšã§ãåã®ã«ãŒãçµæãžã®äŸåãæã¡åããCPU ãä¹ç®ãšå ç®ã䞊åå®è¡ã§ããããã«ãªããŸãã :::details ã«ãŒãã¢ã³ããŒãªã³ã°ã®è£è¶³ éåžžã®ã«ãŒãã§ã¯ 1 ã€ã®å€æ° sum ã«é çªã«è¶³ããŠãããŸãã sum += a[0]*b[0] ã®çµæãåºããŸã§æ¬¡ã® sum += a[1]*b[1] ãå§ããããŸããïŒããŒã¿äŸåïŒã 4-way ã§ã¯ 4 ã€ã®å€æ° s0, s1, s2, s3 ã«åããŠãããããç¬ç«ã«èšç®ããŸããCPU ã¯äŸåé¢ä¿ã®ãªãåœä»€ãåæã«å®è¡ã§ããããïŒåœä»€ã¬ãã«äžŠåæ§ïŒã4 ã€ã®ä¹ç®ã»å ç®ã䞊åã«èµ°ããŸããæåŸã« s0 + s1 + s2 + s3 ã§åèšããã ãã§ãã éåžž: sum += a[0]*b[0] â sum += a[1]*b[1] â sum += a[2]*b[2] â sum += a[3]*b[3] ïŒåã®çµæãåŸ
ã£ãŠããæ¬¡ãžïŒ 4-way: s0 += a[0]*b[0] s1 += a[1]*b[1] s2 += a[2]*b[2] s3 += a[3]*b[3] ïŒ4ã€åæã«å®è¡ïŒ â s0 + s1 + s2 + s3 ::: // äºåæ£èŠå: å
šãã¯ãã«ã®ãã«ã ã 1 ã«ãã normalized := normalizeAll(slugs, vectors) // min-heap Top-K: äžäœ maxResults ä»¶ã ããå¹ççã«æœåº h := &minHeap{} for j, other := range slugs { if i == j { continue } score := dotProduct(vi, normalized[j]) if h.Len() < maxResults { heap.Push(h, ScoredItem{Key: other, Score: score}) } else if score > (*h)[0].Score { (*h)[0] = ScoredItem{Key: other, Score: score} heap.Fix(h, 0) } } // 4-way ã«ãŒãã¢ã³ããŒãªã³ã° func dotProduct(a, b []float32) float32 { var s0, s1, s2, s3 float32 n := len(a) i := 0 for ; i <= n-4; i += 4 { s0 += a[i]*b[i]; s1 += a[i+1]*b[i+1] s2 += a[i+2]*b[i+2]; s3 += a[i+3]*b[i+3] } for ; i < n; i++ { s0 += a[i] * b[i] } return s0 + s1 + s2 + s3 } ::::: ããã©ãŒãã³ã¹æšç§» æ®µé ææ³ ã©ã³ãã³ã°åŠçæéïŒ956èšäºïŒ åæ æ¯åãã«ã èšç® + sort.Slice ~1.58s 1 äºåæ£èŠå + min-heap Top-K ~1.18s 2 + ã«ãŒãã¢ã³ããŒãªã³ã°ïŒ4-wayïŒ 730ms æçµçãªã¹ããã¯ïŒ ææš å€ èšäºæ° 956 ä»¶ ãã¯ãã«æ¬¡å
æ° 1024 é¡äŒŒåºŠèšç®åæ° çŽ 912,980 åïŒ956 à 955ïŒ ã©ã³ãã³ã°åŠçæé 730ms ãªããGo ã® map ã¯ã€ãã¬ãŒã·ã§ã³é åºãéæ±ºå®çã§ããåãå
¥åã«å¯ŸããŠåžžã«åã JSON åºåãåŸãããã slices.Sort ã§ã¹ã©ãã°ããœãŒãããŠããåŠçããŠããŸãããããå¿ãããš CI ã®ãã³ã« diff ãçºçããäžèŠãªã³ããããçãŸããŠããŸããŸãã 8. GitHub Actions ã§ã® CI/CD ã¯ãŒã¯ãããŒå
šäœå flowchart LR A["create-branch"] --> B["generate-related-content<br>(ARM runner + Ollama)"] A --> C["generate-metadata"] A --> D["generate-search-index"] B --> E["create-pull-request"] C --> E D --> E E --> F["auto-merge"] create-branch ã§ãã©ã³ããäœæããåŸã3 ã€ã®ãžã§ãã䞊åå®è¡ãããŸãã ARM ã©ã³ããŒã®éžæ Embedding åŠçã«ã¯ arm-ubuntu-latest-4 ã©ã³ããŒã䜿çšããŠããŸããGitHub ã® ARM ã©ã³ããŒã¯ x86 ã®çŽåé¡ïŒ1åããã $0.004 vs $0.008ïŒã§ãååã®å
šé Embedding ã®ããã«æ°æéããããžã§ãã§ã¯ã³ã¹ãå·®ã倧ãããªããŸãã Ollama ã¢ãã«ãã£ãã·ã¥ 639MB ã®ã¢ãã«ãã¡ã€ã«ãæ¯åããŠã³ããŒãããªãããã actions/cache ã§ãã£ãã·ã¥ããŸãã cache/restore + cache/save ãã¿ãŒã³ :::message actions/cache@v5 ã® save-always ãªãã·ã§ã³ã¯éæšå¥šã«ãªããŸããã代ããã« cache/restore ãš cache/save ãåé¢ãã cache/save ã« if: always() ãä»ãããã¿ãŒã³ã䜿ããŸãã ::: - name: Restore embeddings cache uses: actions/cache/restore@v5 with: path: output/embeddings_cache.json key: embeddings-cache-${{ hashFiles('_posts/**') }}-${{ github.run_id }} restore-keys: embeddings-cache- # ... Embedding å®è¡ ... - name: Save embeddings cache if: always() uses: actions/cache/save@v5 with: path: output/embeddings_cache.json key: embeddings-cache-${{ hashFiles('_posts/**') }}-${{ github.run_id }} if: always() ã«ãããã¿ã€ã ã¢ãŠãæã§ããã£ãã·ã¥ãä¿åããŸããã»ã¯ã·ã§ã³ 6 ã®ã1 ä»¶ãã€ä¿åããšçµã¿åãããŠãäžæãšåå®è¡ãç¹°ãè¿ããŠããã£ãã·ã¥ãèç©ãããŸãã ãã£ãã·ã¥ããŒã« run_id ãä»ããçç± GitHub Actions ã®ãã£ãã·ã¥ã¯åãããŒã§äžæžãã§ããŸããïŒã€ãã¥ãŒã¿ãã«ïŒãããã¯ã¿ã€ã ã¢ãŠãâåå®è¡ã®ãã¿ãŒã³ã§åé¡ã«ãªããŸãã run_id ãªãã®å Žå: key: embeddings-cache-abc123 1åç®: save "abc123" â â
200èšäºåä¿å 2åç®: restore "abc123" â 200èšäºåŸ©å
â 远å 200èšäº â save "abc123" â â ããŒãæ¢ã«ååš 3åç®: restore "abc123" â 1åç®ã®200èšäºåãããªãïŒ2åç®ã®ææãæ¶ããïŒ run_id ããã®å Žå: save key: embeddings-cache-abc123-{run_id} â æ¯åãŠããŒã¯ restore-keys: embeddings-cache-abc123- â ãã¬ãã£ãã¯ã¹äžèŽã§ææ°ãååŸ 1åç®: save "abc123-100" â â
200èšäºå 2åç®: restore "abc123-" â run100ãã200èšäºåŸ©å
â 远å 200èšäº â save "abc123-200" â â
400èšäºå 3åç®: restore "abc123-" â run200ãã400èšäºåŸ©å
â ç¶ããã push ã®ãªãã©ã€ããžã㯠3 ã€ã®ãžã§ãã䞊åã§ãã©ã³ãã« push ãããããç«¶åãçºçããŸããææ°ããã¯ãªãä»ãã®ãªãã©ã€ã§å¯ŸåŠããŸãã pushed=false for i in 1 2 3 4 5; do git pull --rebase origin "$BRANCH_NAME" && git push origin "$BRANCH_NAME" && pushed=true && break echo "Push failed (attempt $i), retrying..." sleep $((i * 2)) done [ "$pushed" = "true" ] || { echo "ERROR: All push attempts failed"; exit 1; } å€ããã©ã³ãã®åé¡ èªåçæçšãã©ã³ããååã®å®è¡ããæ®ã£ãŠããå Žåãå€ãã³ãŒããããŒã¹ã«ãªããŸãã git reset --hard ${{ github.sha }} ã§æ¯åããªã¬ãŒå
ã®ææ°ã³ãããã«ãªã»ããããŸãã workflow_dispatch ã§ã®ãã¹ãå®è¡ main ã«ããŒãžåã®åäœç¢ºèªã§ã¯ workflow_dispatch ããªã¬ãŒãäžæçã«è¿œå ããŸããããã ããGUI ã® Actions ã¿ãã«ã¯ããã©ã«ããã©ã³ãã®ã¯ãŒã¯ãããŒãã衚瀺ãããªããããfeature ãã©ã³ãã® workflow_dispatch 㯠GUI ããå®è¡ã§ããŸããã CLI çµç±ã§ããã° --ref ã§ãã©ã³ããæå®ããŠå®è¡å¯èœã§ãã gh workflow run "Auto Create Related Data" --ref feat/related-content-gen-go-rewrite 9. å®éçšã§èŠãã广 æ§ã·ã¹ãã ïŒPython + Azure OpenAIïŒããæ°ã·ã¹ãã ïŒGo + OllamaïŒãžã®ç§»è¡ã§ãã»ã¯ã·ã§ã³ 1 ã§æãã 3 ã€ã®èª²é¡ã¯ããããæ¬¡ã®ããã«å€ãããŸããã èª²é¡ æ§ïŒPython + Azure OpenAIïŒ æ°ïŒGo + OllamaïŒ å®è¡æŠç¥ æ¯åå
šé EmbedïŒ900+ ä»¶ïŒ å·®åã®ã¿ EmbedïŒSHA-256 ããã·ã¥æ¯èŒïŒ Rate Limit (429) é »çºã»ãªãã©ã€ã§äžå®å® æ§é çã«çºçããªãïŒå€éš API ãªãïŒ æšè«ã³ã¹ã åŸé課éïŒAzure OpenAIïŒ ãŒãïŒCI ã©ã³ããŒå
å®çµïŒ æ¯èŒãã¹ãã¯åçºã®åŠçç§æ°ã§ã¯ãªãããèšäºè¿œå ã®ãã³ã«å
šéåèšç®ãå¿
èŠãããå€éš API å¶çŽã«éçšãæ¯ãåããããããšããéçšç¹æ§ã§ããæ§ã¯ Azure ã®ãããŒãžãäžŠåæšè«ãæ°ã¯ self-hosted CI ã©ã³ã㌠1 å°ã®ã·ãŒã±ã³ã·ã£ã«åŠçã§ããããã尺床ãéããŸãã å·®åæŽæ°æã®å®æž¬äŸ 959 èšäºäž 49 ä»¶ïŒ5%ïŒã dirty ã ã£ã run ã§ã¯ã 19 å 21 ç§ã§å®èµ° ããŸããïŒself-hosted runner 1 å°ã»é次åŠçã§ 1 èšäºãããçŽ 22ã24 ç§ïŒãå·®åãŒããªã Embed ã¯ã¹ããããããã©ã³ãã³ã°èšç®ãšåºåã ãã§ 1ã2 åã§å®äºããŸãã æ®èª²é¡ dirty ã 150 ä»¶ãè¶
ããç¶æ³ïŒcache eviction çŽåŸã cron ãé·æé倱æããŠããããšãªã©ïŒã§ã¯ timeout-minutes: 60 ã«åãŸããªãããšããããŸããçŸç¶ã¯è€æ° run ã«åããŠé²æãç©ã¿äžããèšèšã§ã«ããŒããŠããŸãããæ¬¡ã®æã¡æãšã㊠timeout å»¶é·ãš output/embeddings_cache.json ã® git 管çåãåè£ã§ã GitHub Actions cache 㯠7 æ¥ã¢ã¯ã»ã¹ãªãã§èªå eviction ãããããã鱿¬¡ cronïŒææ 9 æïŒã§ Restore ãè§Šã£ãŠ keep-warm ããŠããŸãããã確å®ã«ãããªã git 管çåããS3 ãªã©ã®å€éš storage ã«å¯ããæããããŸã 10. ãŸãšã æ¬èšäºã§ã¯ãé¢é£èšäºã®ã¬ã³ã¡ã³ãã·ã¹ãã ã Go + OllamaïŒããŒã«ã« EmbeddingïŒã§åæ§ç¯ããéçšã玹ä»ããŸããããªããé¢é£æ±äººã«ã€ããŠãåæ§ã® Embedding + ã³ãµã€ã³é¡äŒŒåºŠã®ä»çµã¿ã§çæããŠããŸãã é
ç® çµæ 察象èšäºæ° 960 ä»¶ååŸïŒå·çæç¹ïŒ ã©ã³ãã³ã°èšç® 730msïŒEmbedding çæã¯å«ãŸããæž¬å®æç¹ 956 ä»¶ïŒ ããã¹ãåãè©°ã å
é 4000 æåã§å
𿿝 88.7% ã®é¡äŒŒåºŠãç¶æ å·®åãã£ãã·ã¥ å·®åãŒããªã 1ã2 åãå°æ°å·®åãªãæ°åãåæ°å å€éšäŸå Ollama + Qwen3-EmbeddingïŒAPI ããŒäžèŠïŒ SHA-256 å·®åãã£ãã·ã¥ã§å€æŽèšäºã ããå Embed ããã©ã³ãã³ã°ã¯äºåæ£èŠåãš min-heap Top-K ã§ 730msïŒ956èšäºã®ãã¢ã¯ã€ãºèšç®ïŒãå€éš API äŸåãæé€ããŠã429 ãšã©ãŒãšã³ã¹ãã®åé¡ãè§£æ¶ããŸããã ååã®å
šé Embedding 㯠CPU ã©ã³ããŒã§æ°æéããããã¢ãã«å€æŽãåæå°å
¥æã«ãåãã³ã¹ããæãããšã«ãªããŸããæ±ãæ¹ã¯ã»ã¯ã·ã§ã³ 6 ãš 9 ã«æžããéãã§ãGPU ã©ã³ããŒã䜿ããã°æ¹åããŸãããçŸæç¹ã§ã¯ CI ã®å¶çŽã§ãã ãã 1 ã€ãæšèŠå質ã®å®éè©äŸ¡ããŸã ãããŸããããEmbedding ã®é¡äŒŒåºŠã 88.7% ä¿ãããŠãããããšãšãé¢é£èšäºã®æšèŠã劥åœã§ãããããšã¯å¥ã®åé¡ã§ããæ§ã·ã¹ãã ãšã® Top-K äžèŽçããã¯ãªãã¯ã¹ã«ãŒçã®èšæž¬ãæ®ã£ãŠããŸãã ããã¹ãåãè©°ããæ¹åã®äœå°ããããŸããçŸåšã¯å
é 4000 æåãã«ãŒã³åäœã§ã«ããããŠããŸãããæã®éäžã§åããå¯èœæ§ããããŸããå¥ç¹ïŒ ã ïŒãæ¹è¡ã®äœçœ®ã§åãæ¹ããEmbedding ã®å
¥åãšããŠã¯ã¯ãªãŒã³ã§ããä»åã®ãŠãŒã¹ã±ãŒã¹ã§ã¯åœ±é¿ã¯è»œåŸ®ã§ããã粟床ã远æ±ããå Žåã¯æ€èšã«å€ããŸãã 11. ãã®ä»çµã¿ã®å¿çšå¯èœæ§ ãããŒã«ã« Embedding + ã³ãµã€ã³é¡äŒŒåºŠ + å·®åãã£ãã·ã¥ãã®ä»çµã¿ã¯ãããã°ã®é¢é£èšäºã«éããŸãããConfluence ã Notion ã®ç€Ÿå
ããã¥ã¡ã³ããåããã€ãã©ã€ã³ã§ Embedding ããã°ãããã®ä»æ§æžã«é¢é£ããããã¥ã¡ã³ãããèªåæç€ºã§ããŸããOllama ã¯ããŒã«ã«å®è¡ãªã®ã§ã瀟å€ã«éä¿¡ã§ããªã瀟å
ææžã§ãæ±ããŸãã SHA-256 å·®åãã£ãã·ã¥ãš 1 ä»¶ãã€ä¿åã®äžæèæ§ãã¿ãŒã³ã¯ãã®ãŸãŸæµçšã§ããŸããOllama + 軜éã¢ãã«ãªã API ããŒäžèŠã§ CI ã§ãããŒã«ã«ã§ãåããŸãã ããŸã: Claude Code ãšã®éçºããã»ã¹ ä»åã®éçºã¯ Claude Code ãšã®ãã¢ããã°ã©ãã³ã°ã§é²ããŸããã kairo ã«ããéçºã¯ãŒã¯ãã㌠éçºã¯ãŒã¯ãããŒã«ã¯ã¯ã©ã¹ã¡ãœãã瀟㮠tsumiki ã® kairo ã䜿ããŸãããkairo 㯠Claude Code åãã®ã¹ãã«ã§ã4 ã€ã®ã³ãã³ãã§ãœãããŠã§ã¢éçºãé²ããŸãã kairo-requirements : EARS èšæ³ã§æ©èœã»éæ©èœèŠä»¶ãå®çŸ©ãä»å㯠3 æ¹åŒã® PoC æ¯èŒïŒONNX / llama.cpp / OllamaïŒããã®ãã§ãŒãºã§å®è¡ããŸãã kairo-design : èŠä»¶ããã¢ãŒããã¯ãã£å³ãããŒã¿ãããŒãåå®çŸ©ãçæ kairo-tasks : èšèšãå®è£
ã¿ã¹ã¯ã«åå²ãäŸåé¢ä¿ãšãã¹ãã±ãŒã¹ãå®çŸ©ãä»å㯠10 ã¿ã¹ã¯ã»3 ãã§ãŒãºã«åè§£ kairo-loop : ã¿ã¹ã¯ã 1 ã€ã〠Red â Green â Refactor ã® TDD ãµã€ã¯ã«ã§å®è£
ã7 ã¿ã¹ã¯ããã®ã³ãã³ãã§åããŸãã PR ã¬ãã¥ãŒ å®è£
åŸã® PR ã¬ãã¥ãŒã§ã¯ãClaude Code ã«ä»¥äžã®ããã«æç€ºããŸããã /pr-review-toolkit:review-pr all pr-review-toolkit 㯠Anthropic å
¬åŒã® Claude Code ãã©ã°ã€ã³ã§ã6 çš®ã®ã¬ãã¥ãŒãšãŒãžã§ã³ãïŒã³ãŒãå質ããšã©ãŒãã³ããªã³ã°ããã¹ãã«ãã¬ããžãã³ã¡ã³ãæŽåæ§ãåèšèšãã³ãŒãç°¡çŽ åïŒã䞊åã«ã¬ãã¥ãŒããŸããã»ã¯ã·ã§ã³ 5.2 ã®ã¬ã¹ãã³ã¹ããªããŒã·ã§ã³ïŒä»¶æ°ã»ç©ºãã¯ãã«ãã§ãã¯ïŒã¯ããã®ã¬ãã¥ãŒã§ææãããåé¡ãžã®å¯Ÿå¿ã§ãã Go 1.26 ã§ã®æé©å Claude Code ã«ãGo 1.26 ã§æé©åããŠããšæç€ºããŸããã go fix ã«ããèªåå€æïŒ strings.Index â strings.Cut ã sort.Strings â slices.Sort ã context.Background() â t.Context() ãªã©ïŒã«å ããæ°ããèšèªæ©èœãã©ã€ãã©ãª API ãæŽ»çšãããªãã¡ã¯ã¿ãªã³ã°ã宿œãããŸããã èšäºã®å·çã»æ ¡æ£ ãã®èšäºèªäœã Claude Code ã§å·çããŠããŸããæ ¡æ£ã«ã¯ 3 ã€ã®ããŒã«ã䜿ããŸããã textlint + ja-technical-writing : åé·è¡šçŸãæ¥ç¶è©ã®éè€ãªã©ãæ¥æ¬èªã®æè¡ææžåãæ ¡æ£ skill-deslop : AI çææç« ã«ç¹æã®åé·ãã¿ãŒã³ïŒåããã©ãå眮ããååæ
ã®å€çšãªã©ïŒã®æ€åºã»é€å» Codex plugin for Claude Code : OpenAI å
¬åŒã® Claude Code ãã©ã°ã€ã³ã§ãCodex CLI ããµããšãŒãžã§ã³ããšããŠåŒã³åºããŸããèšäºå
šäœã®è«çç Žç¶»ãæ°å€ççŸã®ãã§ãã¯ã«äœ¿ããŸãããå®éšããŒã¿æŽæ°ã«äŒŽãæ°å€ã®äžæŽåãã³ãŒãã¹ããããã®å€æ°åäžäžèŽãªã©ã人éã®ã¬ãã¥ãŒã§ã¯èŠèœãšããããåé¡ãæ€åºã§ããŸãã ãããŸã§èªãã§ããã ãããããšãããããŸãããäœãã®åèã«ãªãã°å¹žãã§ãããªãããã®èšäºã®äžéšã«è¡šç€ºãããŠãããé¢é£ããèšäºããšãé¢é£ããæ±äººãããæ¬èšäºã§ç޹ä»ããä»çµã¿ã§çæãããå®ç©ã§ãã