# GoAgent **Repository Path**: zhoudawei666/go-agent ## Basic Information - **Project Name**: GoAgent - **Description**: kfbot:基于 Go + Gin + LangChainGo + Ollama 的本地智能客服示例。支持 Markdown 知识库构建 RAG,向量检索与混合重排,向量不足时关键词回退;可选接入 Milvus 做向量持久化与多实例共享。 - **Primary Language**: Go - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-04-02 - **Last Updated**: 2026-05-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: Go语言, Agent ## README # kfbot [![Go](https://img.shields.io/badge/Go-%3E%3D1.24-00ADD8?logo=go)](https://go.dev/) [![Ollama](https://img.shields.io/badge/Ollama-local%20LLM-111111)](https://ollama.com/) [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE) **kfbot** 是一个基于 **Go + [Gin](https://github.com/gin-gonic/gin) + [LangChainGo](https://github.com/tmc/langchaingo) + [Ollama](https://github.com/ollama/ollama)** 的本地智能客服示例:对话与嵌入均通过 LangChainGo——对话用 Ollama `llms.Model`(`GenerateContent`),嵌入用 `embeddings.Embedder`(底层为 LangChainGo Ollama 的 `CreateEmbedding`,经 `EmbedDocuments` / `EmbedQuery` 批量与查询)。配合 Markdown 知识库、RAG、混合重排与关键词回退;**无需**外网 API Key(联网搜索工具除外)。 下文涵盖:功能说明、目录布局、架构、安装与运行、知识库与检索原理、配置与排障等;**HTTP 接口说明**见 [webapi/API.md](webapi/API.md)。 --- ## 功能特性 - **Markdown 知识库**:读取 `knowledge/*.md`,按二级标题切分 chunk;孤立的一级标题会与首个二级段落合并,避免空标题块干扰检索。 - **向量 RAG**:通过 Ollama Embedding(默认 `nomic-embed-text`)建索引;查询时余弦相似度 + 混合分(向量 + 字面重合 + 营业时间类问法加权)。 - **Milvus(可选)**:设置 `MILVUS_ADDR` 后,向量持久化到 [Milvus](https://milvus.io/),并提供 `POST /knowledge`(上传 `.md` 文件,自动切块写入)、`DELETE /knowledge/:id` 按向量 ID 删除;检索仍用同一套 `nomic-embed-text` 向量。 - **关键词回退**:向量未就绪或未过阈值时,使用整句 / 前缀 / 子串匹配整篇文档。 - **HTTP API**:`POST /chat` 对话;可选 `POST /knowledge` 以 multipart 上传 Markdown 文件写入知识。字段与 curl 示例见 **[webapi/API.md](webapi/API.md)**。 - **部署简单**:无 Milvus 时进程内建索引;有 Milvus 时适合多实例共享向量库。 - **智能体 + 工具调用**:`agent` 在 RAG 之外,可按规则调用 `advanced_search`(Tavily / SerpAPI,见 `tools`),并把检索摘要一并交给模型。 - **多轮上下文**:`POST /chat` 的 `history` 经 LangChainGo 转为 `llms.MessageContent` 后调用 `GenerateContent`(见 [Hello-Agents](https://hello-agents.datawhale.cc/) 中「上下文工程」),与当前轮知识库提示共同构成完整上下文。 --- ## 项目结构 ``` . ├── main.go # 唯一入口:加载配置、初始化 RAG / Milvus / 工具、启动 HTTP ├── config/ # 模型名、阈值、路径等常量 ├── knowledge/ # Markdown 加载与切块(含 *.md 知识文件) ├── rag/ # 内存向量索引、混合检索、关键词回退 ├── milvus/ # Milvus 存储与检索(可选) ├── ollama/ # LangChainGo:对话 LLM + 嵌入 Embedder(同一 Ollama 服务) ├── tools/ # 工具注册表 + 联网搜索(Tavily / SerpAPI) ├── agent/ # 智能体:编排知识检索 + 工具 + 提示词 ├── webapi/ # Gin 路由与 Handler;API 说明见 webapi/API.md ├── auth/ # 从请求头/Cookie 取 token,Redis 解析 user_id ├── store/ # PostgreSQL 对话表 + 摘要文本(供 Milvus 写入) ├── .env.example # 环境变量模板(复制为 `.env` 后填写;`.env` 不入库) ├── go.mod / go.sum ├── README.md └── LICENSE ``` 编译(在项目根目录): ```bash go build -o kfbot . # Windows: go build -o kfbot.exe . ``` 编译产物建议加入 `.gitignore`,勿提交到仓库。 --- ## 架构 ``` ┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ Client │────▶│ kfbot :8080 │────▶│ Ollama :11434 │ │ curl / App │ │ Gin+RAG+LCGo │ │ embed + chat │ └─────────────┘ └──────────────┘ └─────────────────┘ │ ./knowledge/*.md ``` 对话与嵌入均走 **LangChainGo**(`llms` + `embeddings` + Ollama 服务)。 | 角色 | 默认模型 | 说明 | |------|----------|------| | 对话(Chat) | `qwen2.5:7b-instruct-q4_K_M` | [LangChainGo Ollama](https://pkg.go.dev/github.com/tmc/langchaingo/llms/ollama) `GenerateContent`,可在 `config/config.go` 中更换 | | 嵌入(Embed) | `nomic-embed-text` | [LangChainGo embeddings](https://pkg.go.dev/github.com/tmc/langchaingo/embeddings) + Ollama,需 `ollama pull` | ### 对话双写(企业级:PG 全文 + Milvus 摘要向量) 配置 **`POSTGRES_DSN`**、**`REDIS_ADDR`**(及可选 **`MILVUS_ADDR`/`MILVUS_DIALOGUE_COLLECTION`**)后: - **PostgreSQL 表 `chat_messages`**:存完整用户/助手消息(含 `tool_result`),带 `tenant_id`、`user_id`、`session_id`,用于列表展示、审计与短期上下文;**不设用户表**,`user_id` 优先来自 Redis;解析不到时使用默认 **`user_id=1`**(见 `config.DefaultUserID()`)。 - **Redis**:请求头 `Authorization: Bearer `(或与 poetize 一致:`token` 查询参数 / Cookie / JSON 字段 `token`)作为 key,读取 JSON 中的 **`id`** 作为用户 ID(对齐 `poetize-server-cpp` `getUserIdFromRequest`)。 - **Milvus 独立 collection**(默认 `kfbot_dialogue_memory`):仅存**一轮摘要** + 向量 + `user_id`/`tenant_id`/`session_id`,用于长期语义召回;与知识库 collection **分离**,非重复冗余。 未配置 `POSTGRES_DSN` 时对话照常,仅不写 PG;有 PG 时即使用默认用户 **1** 也会落库(便于本地联调)。 ### 上下文召回(三层) 每次 `POST /chat` 顺序为:**先**做召回(不含本轮用户句),**再**把本轮用户消息写入 PG,**最后**调用 LLM: 1. **短期对话**:从 PostgreSQL **检索**同会话、**本轮写入前**的最近若干条消息(默认约 **5~10 条**,见 `config.ShortTermMessageLimit`),作为 `GenerateContent` 的多轮 `history`;若 PG 无记录则回退请求体中的 `history`。 2. **长期记忆**:若 Milvus 对话记忆 collection 已启用,按 `user_id` + `tenant_id` 过滤,对该用户**跨会话**对话摘要做:**向量检索**(与当前问题相关,条数上限 `config.LongTermRecallTopK`)+ **Query 按时间**取近期摘要(`config.DialogueMemoryRecentListLimit`),合并去重后拼入「长期记忆」区块。 3. **知识库(RAG)**:在 `agent` 内对当前问题做向量/关键词检索,拼入「参考知识」区块。 最终由 LangChainGo 在「短期 history + 单条用户提示(含长期记忆 + 知识 + 可选联网)」上生成回复。 ### 与 Hello-Agents 的对应关系 本仓库可与 Datawhale 开源教程 **[《从零开始构建智能体》](https://hello-agents.datawhale.cc/)**([Hello-Agents 在线阅读](https://hello-agents.datawhale.cc/))对照学习,概念与实现大致对应如下: | 教程主题 | 本仓库中的体现 | |----------|------------------| | 第八章 记忆与检索、RAG | `knowledge/` 切块、`rag/` 向量检索与混合重排、可选 `milvus/` 持久化向量库 | | 第四章 ReAct 等范式 | 简化流水线:**感知**(用户问题)→ **检索**(RAG)→ **可选行动**(`advanced_search`)→ **生成**(LangChainGo `GenerateContent`),非多轮「Thought」文本输出,但结构一致 | | 第九章 上下文工程 | `POST /chat` 的 `history` 会注入多轮消息(仅保留最近若干条),与当前轮知识库提示一起构成完整上下文 | 更系统的多智能体、MCP、评估等内容仍以教程为准;本仓库侧重 **本地 Ollama + Go 服务** 的可运行客服示例。 --- ## 环境要求 | 组件 | 说明 | |------|------| | [Go](https://go.dev/dl/) | 版本以仓库内 `go.mod` 为准(建议 1.22+) | | [Ollama](https://ollama.com/) | 本地运行,默认地址 `http://localhost:11434` | | [Milvus](https://milvus.io/)(可选) | 2.x,gRPC 默认 `127.0.0.1:19530`;可用 [Docker 单机](https://milvus.io/docs/install_standalone-docker.md) 启动 | 建议内存与显存能同时容纳 **对话模型 + 嵌入模型**;资源紧张时可换更小的 chat / embed 模型,并在 `config/config.go` 中修改对应常量。 ### 使用 Milvus(可选) 1. 启动 Milvus(示例,以官方文档为准): ```bash docker run -d --name milvus -p 19530:19530 -p 9091:9091 milvusdb/milvus:v2.4.5-latest ``` 2. 启动本服务前设置环境变量: ```bash # Linux / macOS export MILVUS_ADDR=127.0.0.1:19530 export MILVUS_COLLECTION=kfbot_knowledge # 可选,默认即此名 # Windows PowerShell $env:MILVUS_ADDR="127.0.0.1:19530" ``` 未设置 `MILVUS_ADDR` 时,行为与原先一致:仅在**进程内存**中构建向量索引(重启后需重建)。 首次连接且 collection **为空**时,会自动把 `knowledge/*.md` 切块后写入 Milvus。 --- ## 快速开始 ### 1. 安装 Ollama 并拉取模型 **Linux / macOS** ```bash curl -fsSL https://ollama.com/install.sh | sh ``` **Windows**(PowerShell,以 [官方文档](https://ollama.com/download) 为准) ```powershell winget install Ollama.Ollama # 或: irm https://ollama.com/install.ps1 | iex ``` 拉取运行所需模型: ```bash ollama pull qwen2.5:7b-instruct-q4_K_M ollama pull nomic-embed-text ``` ### 2. 克隆并编译 ```bash git clone cd go build -o kfbot . ``` 将 `` 换成克隆后的仓库根目录(与 `go.mod` 同级;若未指定目录名,一般为远程仓库名)。 ### 3. 启动服务 确保 Ollama 已在运行,于项目根目录执行: ```bash ./kfbot ``` Windows: ```powershell .\kfbot.exe ``` 日志中出现 `本地智能客服已启动:http://0.0.0.0:8080`,且向量索引构建成功(或明确回退到关键词检索)即表示就绪。 ### 4. API 调用 接口字段、请求头与 curl 示例见 **[webapi/API.md](webapi/API.md)**。 --- ## 知识库说明 - **路径**:`./knowledge/`,扩展名 `.md`。 - **写法**:建议用 `##` 分节;正文含时间、步骤、条款时,模型更容易稳定引用。 - **更新**:修改或新增 `.md` 后需**重启进程**,以重新构建向量索引。 --- ## 检索流程 1. 对**用户问题**用 `nomic-embed-text` 做 Embedding。 2. **已启用 Milvus**:在库内做 COSINE 向量检索取候选,再按与内存模式相同的**混合分**重排与阈值过滤。 3. **未启用 Milvus**:在进程内向量表上算余弦相似度,再混合分重排。 4. 通过最低余弦、混合分与「头两名是否过近」等规则过滤弱结果;若仍无合格结果,则回退到**关键词**匹配整篇文档。 5. 将最终片段拼入提示词,再调用本地 Chat 模型生成 `answer`。 调参入口见下表 `EmbedMinCos`、`EmbedMinHybrid` 等。 --- ## 配置说明 ### 环境变量文件(`.env`) 启动时在 `main` 开头会尝试加载项目根目录下的 `.env`(使用 [godotenv](https://github.com/joho/godotenv))。若文件不存在,则仅使用系统环境变量,不影响运行。 请复制 **`.env.example`** 为 **`.env`**,再按需取消注释或填写;`.env` 已列入 `.gitignore`,**不要**把含密钥的 `.env` 提交到 Git。 主要业务常量仍在 `config/config.go`(可按需改为从环境变量读取): | 常量 | 默认值 | 说明 | |------|--------|------| | `OllamaServer` | `http://localhost:11434` | Ollama 服务地址 | | `ModelName` | `qwen2.5:7b-instruct-q4_K_M` | 对话模型 | | `EmbedModel` | `nomic-embed-text` | 嵌入模型(须与索引一致) | | `KnowPath` | `./knowledge` | 知识库目录 | | `EmbedTopK` | `3` | 注入提示词的片段条数上限 | | `EmbedRetrieveN` | `16` | 向量候选池大小 | | `EmbedMinCos` / `EmbedMinHybrid` 等 | 见源码 | 检索阈值与混合策略 | | 环境变量 `MILVUS_ADDR` | 未设置 | 设为 `host:port` 时启用 Milvus | | 环境变量 `MILVUS_COLLECTION` | `kfbot_knowledge` | Collection 名称 | 生产环境建议: ```bash export GIN_MODE=release # Linux / macOS set GIN_MODE=release # Windows cmd ``` ### 联网搜索工具(可选) 与 Python 版「多源搜索」思路一致,在 Go 中通过 **HTTP** 调用 Tavily / SerpAPI(无需在仓库内安装 Python)。 | 环境变量 | 说明 | |----------|------| | `TAVILY_API_KEY` | [Tavily](https://tavily.com/) API,优先使用 | | `SERPAPI_API_KEY` | [SerpAPI](https://serpapi.com/),Tavily 不可用时回退 | | `WEB_SEARCH_AUTO=1` | 任意问题都尝试联网(慎用,有费用与延迟) | 未设置上述密钥时,工具不会发起外网请求。默认仅在用户问题包含「网上 / 搜索 / 最新 / 新闻 / 搜一下」等触发词时调用 `advanced_search`(与 `WEB_SEARCH_AUTO` 二选一扩展)。 对话成功且触发工具时,JSON 响应可能多一个字段 **`tool`**:联网摘要文本,便于调试。 --- ## 常见问题 | 现象 | 处理 | |------|------| | 启动提示向量索引未启用 | 确认已执行 `ollama pull nomic-embed-text`,且本机可访问 `OllamaServer` | | `502` 与 `error` 字段 | 检查对话模型是否已拉取、Ollama 是否运行、端口是否被占用 | | 回答与知识不符 | 查看返回中的 `know`;调整 `config/config.go` 阈值或优化 Markdown 结构与措辞 | | 仅有关键词检索 | 嵌入构建失败时会自动回退;修复 Ollama 与模型后重启 | | `503` 调用 `/knowledge` | 未设置 `MILVUS_ADDR`,Milvus 未启用 | | Milvus 连接失败 | 检查 `MILVUS_ADDR`、防火墙与 Milvus 容器是否监听 19530 | --- ## 开发与构建 ```bash go mod tidy go run . go test ./... go build -o kfbot . ``` --- ## 许可证 本项目以 **GNU AGPL-3.0** 许可证发布,详见仓库根目录 [LICENSE](LICENSE)。 --- ## 致谢 - [gin-gonic/gin](https://github.com/gin-gonic/gin) — HTTP 框架 - [tmc/langchaingo](https://github.com/tmc/langchaingo) — LangChain Go,对话层 `llms` + Ollama - [ollama/ollama](https://github.com/ollama/ollama) — 本地模型服务(LangChainGo 通过 HTTP 调用其 API)