# pc_supper_agent **Repository Path**: hongshu2018/pc_supper_agent ## Basic Information - **Project Name**: pc_supper_agent - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-27 - **Last Updated**: 2026-08-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # PC 用户助手(可维护版本) 基于 **LangGraph + Ollama (Qwen)** 的 PC 用户助手。从“能跑的 MVP”重构为 **对扩展开放、对修改封闭(OCP)** 的长期可维护版本:新增能力(如跨专业就业、 技能学习)只需“加一个工具类 + 注册一条配置”,核心代码无需改动。 ## 架构总览 ``` Docker 部署层 └── FastAPI 应用 ├── API 层 (app/api) 路由与请求/响应模型 ├── 服务层 (app/services) 意图识别 / 路由决策 / 工具调用 / 通用对话 ├── 核心层 (app/core) 配置 / 状态 / LLM 工厂 / 工具注册中心 / 图构建器 / 记忆 / 检索 / 上下文组合 ├── 工具层 (app/tools) 每个能力一个类(扩展点) ├── 提示词 (app/prompts) YAML 驱动的提示词模板 └── 配置层 (configs) config.yaml 驱动工具注册 外部依赖:Ollama(模型) / Redis(可选,预留缓存) / 后端 HTTP 服务 ``` 工作流(LangGraph 图): ``` intent_recognition ──► query ──► route_query ──► tool_ ──► END └─ chat ──► route_chat ──► tool_ ──► END └ general ─────────────────► general_chat ──► END ``` 图节点按 `configs/config.yaml` 中的工具注册表**动态生成**:新增工具自动获得 对应节点,无需改 `graph_builder`。意图识别会返回置信度;低于阈值时回落到 `general` (通用对话)由正常聊天兜底,不再输出“未能理解用户语义”错误串(避免污染记忆库)。 ## 目录结构 ``` pc_supper_agent/ ├── docker/ Dockerfile / docker-compose.yml / .env.example / .dockerignore ├── app/ │ ├── main.py FastAPI 入口 │ ├── cli.py 命令行交互入口 │ ├── api/ routes.py / schemas.py │ ├── core/ config / state_manager / llm_factory / tool_registry / graph_builder / memory / retrieval / context / graph_retrieval │ ├── services/ intent / routing / tool / chat │ ├── tools/ base.py + 各能力工具 │ ├── prompts/ intent_prompts / routing_prompts / chat_prompts (.yaml) │ └── utils/ logger / http_client ├── configs/config.yaml 主配置 + 工具注册表 ├── tests/ pytest(含 FakeChatModel 端到端用例) ├── scripts/init_data.py 部署前自检脚本 └── pyproject.toml ``` ## 如何新增一个能力(核心扩展流程) 以“跨专业就业咨询”为例,只需两步: **1. 新建工具类** `app/tools/cross_major_career.py`: ```python from app.tools.base import BaseTool, ToolContext, generate_chat_response class CrossMajorCareerTool(BaseTool): @property def name(self): return "cross_major_career" @property def description(self): return "跨专业就业咨询:非科班转行、复合背景打造" @property def category(self): return "chat" # query / chat / action def system_prompt(self): return "你是一位跨专业就业指导专家……" def execute(self, context: ToolContext): return self.respond(context) # 自动注入记忆 + RAG 上下文 ``` **2. 在 `configs/config.yaml` 注册:** ```yaml tools: - name: "cross_major_career" enabled: true description: "跨专业就业咨询" category: "chat" tool_class: "app.tools.cross_major_career.CrossMajorCareerTool" ``` 完成。意图识别 → 路由 → 工具节点会自动接入,无需改动任何核心代码。 (仓库中 `cross_major_career.py` 与 `skill_learning.py` 已是按此方式接入的示例。) > 查询类工具(`category: query`)的 `execute` 直接返回数据(未来替换为真实 > HTTP 调用即可,见 `app/utils/http_client.py`);对话类工具(`category: chat`) > 通过 `system_prompt()` + 模型生成专业回答。 ## 意图置信度门控(软路由) 意图识别节点会要求模型同时返回 `intent` 与 `confidence`(结构化 JSON)。 置信度仅作**业务软路由**:`confidence < 阈值` 时回落到 `general`(通用对话), 由正常聊天兜底——不再输出“未能理解用户语义”错误串(既避免污染记忆库,也保留对话连续性)。 - 阈值在 `configs/config.yaml` 的 `intent.confidence_threshold` 配置(默认 `0.7`), 无需改代码即可调整灵敏度。 - 解析具备容错:支持裸 JSON、Markdown 代码块包裹的 JSON,以及旧式纯标签输出。 ## 二期能力:多用户记忆 + GraphRAG 检索增强 > 遵循 OCP:记忆与 RAG 都抽象为「上下文提供方(ContextProvider)」,由 `ContextComposer` > 按配置聚合并注入生成节点。新增上下文源(如用户画像库)只需实现 `ContextProvider` 并在 > `ContextComposer` 注册,不动节点 / 工具 / 提示词。 ### 多用户长期记忆(`app/core/memory.py`) - `MemoryManager` 抽象 + `LocalMemoryManager`(Chroma 持久化 + 本地 Ollama 嵌入 `nomic-embed-text`,按 `user_id` 元数据隔离多用户)。 - 配置 `config.memory`(`enabled / backend / embed_model / top_k / save_async`)。 - **保存守卫**:仅有效意图(query/chat/general)且有结果时写入;异步 best-effort, 不阻断主流程,避免把无效 / 错误结果写入记忆。 - 测试用 `FakeMemory`(离线替身)。 ### GraphRAG 知识图谱检索(`app/core/graph_retrieval.py`) - `LocalGraphRetriever`:NetworkX 存储 + 多跳遍历,全本地、不依赖 OpenAI。 - **构建期(离线)**:`scripts/ingest.py` 读 `data/knowledge/*.md` → 本地 LLM 抽取三元组 → 建图 → **关系整理(consolidation)**推断潜在关系 / 同义合并 → pickle 持久化 `data/graph/kg.pkl`。 - **查询期(运行时)**:实体链接(关键词对齐图节点)→ 多跳遍历(`max_hops`)→ 拼成上下文注入提示词。 - 配置 `config.rag`(`backend: graph | vector`,`extraction_model`,`max_hops`,`top_k`,`consolidate`)。 - `vector` 后端为后续扩展点(OCP seam 已预留),当前 `graph` 已落地。 ### 上下文如何注入 `graph_builder` 用 `with_memory` 切面包裹 `tool_node` 与 `general_chat` 节点:组合 `memory + rag` 上下文写入 `state["augmented_context"]`,生成节点把其拼入系统提示词。 ### 使用步骤 ```bash # 1) 构建知识图谱(需 Ollama 已拉取 extraction_model,默认 qwen3.5:7b) uv run python scripts/ingest.py # 2) 启动服务(记忆与 RAG 已按 config.yaml 自动启用) uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 ``` - 示例知识库见 `data/knowledge/products.md`(产品参数、相似产品、所属行业关系)。 - 多用户:每次请求携带 `user_id`,记忆按 `user_id` 隔离。 - Docker 部署时 `data/` 已挂卷持久化(`docker-compose.yml`)。 ## 本地运行 ```bash # 1) 安装依赖(需要 uv) uv sync # 2) 部署/启动 Ollama 并拉取模型 ollama pull qwen3.5:2b # 3) 启动 API 服务 uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 # 或命令行交互 python main.py # 4) 自检 python scripts/init_data.py ``` API 示例: ```bash curl -X POST http://localhost:8000/api/v1/chat \ -H "Content-Type: application/json" \ -d '{"message": "我想跨专业就业做数据分析", "user_id": "u1"}' ``` - `GET /api/v1/tools` 查看已注册工具 - `GET /api/v1/health` 健康检查 - `GET /docs` 交互式 API 文档 ## Docker 部署 ```bash cd docker cp .env.example .env # 按需修改 docker compose up --build -d ``` - `app` 服务暴露 `:8000`,`ollama` 暴露 `:11434`,`redis` 暴露 `:6379`。 - `configs/` 以只读卷挂载,改配置无需重新构建镜像。 ## 测试 ```bash uv sync uv run --with pytest pytest -q ``` 测试**完全离线**:用 `FakeChatModel` 替换真实 Ollama,并用 `FakeMemory` / `FakeRetriever` 替换记忆与检索后端。覆盖:工具注册、图编译、意图→路由→工具端到端链路(含跨专业就业 / 技能学习工具)、上下文注入(记忆 + RAG 进入生成)、多用户记忆隔离,以及 GraphRAG 离线检索(固定图 fixture、多跳边界)。置信度低于阈值时回落通用对话的兜底路径亦覆盖。 ## 设计原则 - **开闭原则(OCP)**:能力扩展通过“配置 + 新类”实现,核心图/服务不变。 - **关注点分离**:API / 服务 / 核心 / 工具 / 提示词 / 配置各司其职。 - **配置驱动**:模型、温度、工具清单全部外置,环境差异用环境变量覆盖。 - **可观测**:每个工具即一个图节点,链路在 LangGraph 可视化中清晰可见。 - **可测试**:LLM 通过工厂注入,便于用假模型做无依赖端到端测试。