Files

1 line
30 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "a5sl/role-play-agent", "files": {"README.md": {"9108883e8580aead2f8496720d77182fba5616ef": {"t": 1785746598.3718984, "n": 2542, "h": "b1e27711c01344e0", "c": "# RPagent — AI Role-Playing Agent\n\nA character-driven AI agent that role-plays as fictional characters using game dialogue as memory. Built with a hand-written ReAct loop on top of DeepSeek, ChromaDB, and Streamlit.\n\n## What it does\n\n- **QA Mode** — Ask questions about your documents, get answers backed by RAG retrieval\n- **Roleplay Mode** — Talk to an AI character that stays in-character using Persona Cards, emotional triggers, and dialogue memory from actual game scripts\n\n## Quick Start\n\n```bash\n# 1. Install\npip install -r requirements.txt\n\n# 2. Configure\ncp .env.example .env\n# Edit .env, add your DEEPSEEK_API_KEY=sk-...\n\n# 3. Launch the Web UI\nstreamlit run src/ui/app.py\n```\n\n## CLI Modes\n\n```bash\npython -m src.rag_cli # Pure RAG (document Q&A)\npython -m src.agent_cli # Agent with tool-calling\npython -m src.rp_cli data/personas/美岬.yaml # Roleplay as a character\npython -m src.character.memory_cli stats # Dialogue memory stats\n```\n\n## How it works\n\n```\nUser input → Agent thinks → picks a tool → retrieves context from ChromaDB → generates response\n```\n\n- **Agent Loop**: Hand-written ReAct pattern — no LangChain magic, fully transparent\n- **Character System**: Persona Cards (YAML) define identity, personality, speech style, knowledge boundaries, and emotional triggers\n- **Memory**: Game dialogues imported into ChromaDB, semantically retrieved per conversation turn, injected into the character's system prompt\n- **Emotional Triggers**: Keyword-matched emotional states that temporarily shift the character's mood\n\n## Project layout\n\n```\nsrc/\n├── agent/ # ReAct loop, roleplay agent, tool definitions\n├── character/ # Persona cards, prompt builder, dialogue parsers, memory\n├── document/ # PDF/TXT loading, chunking, embedding, retrieval\n├── ui/ # Streamlit app\n├── config.py # Global settings\n├── agent_cli.py # QA Agent CLI\n├── rp_cli.py # Roleplay CLI\n└── rag_cli.py # RAG CLI\n```\n\n## Philosophy\n\nEvery phase produces runnable code. The agent loop is handwritten for transparency — no framework black boxes. Character data is decoupled from agent logic so multi-character conversations can be added later.\n\n## Dependencies\n\n- **LLM**: DeepSeek (OpenAI-compatible API)\n- **Vector DB**: ChromaDB with sentence-transformers for local embeddings\n- **UI**: Streamlit\n- **Docs parsing**: pypdf, markdown\n\n---\n\n*For architecture details, data flow diagrams, and the full roadmap, see [ARCHITECTURE.md](dev/ARCHITECTURE.md).*\n"}, "4406869c45f8673685a93de5caad07b7280489b8": {"t": 1785766177.5887873, "n": 2542, "h": "b1e27711c01344e0", "c": "# RPagent — AI Role-Playing Agent\n\nA character-driven AI agent that role-plays as fictional characters using game dialogue as memory. Built with a hand-written ReAct loop on top of DeepSeek, ChromaDB, and Streamlit.\n\n## What it does\n\n- **QA Mode** — Ask questions about your documents, get answers backed by RAG retrieval\n- **Roleplay Mode** — Talk to an AI character that stays in-character using Persona Cards, emotional triggers, and dialogue memory from actual game scripts\n\n## Quick Start\n\n```bash\n# 1. Install\npip install -r requirements.txt\n\n# 2. Configure\ncp .env.example .env\n# Edit .env, add your DEEPSEEK_API_KEY=sk-...\n\n# 3. Launch the Web UI\nstreamlit run src/ui/app.py\n```\n\n## CLI Modes\n\n```bash\npython -m src.rag_cli # Pure RAG (document Q&A)\npython -m src.agent_cli # Agent with tool-calling\npython -m src.rp_cli data/personas/美岬.yaml # Roleplay as a character\npython -m src.character.memory_cli stats # Dialogue memory stats\n```\n\n## How it works\n\n```\nUser input → Agent thinks → picks a tool → retrieves context from ChromaDB → generates response\n```\n\n- **Agent Loop**: Hand-written ReAct pattern — no LangChain magic, fully transparent\n- **Character System**: Persona Cards (YAML) define identity, personality, speech style, knowledge boundaries, and emotional triggers\n- **Memory**: Game dialogues imported into ChromaDB, semantically retrieved per conversation turn, injected into the character's system prompt\n- **Emotional Triggers**: Keyword-matched emotional states that temporarily shift the character's mood\n\n## Project layout\n\n```\nsrc/\n├── agent/ # ReAct loop, roleplay agent, tool definitions\n├── character/ # Persona cards, prompt builder, dialogue parsers, memory\n├── document/ # PDF/TXT loading, chunking, embedding, retrieval\n├── ui/ # Streamlit app\n├── config.py # Global settings\n├── agent_cli.py # QA Agent CLI\n├── rp_cli.py # Roleplay CLI\n└── rag_cli.py # RAG CLI\n```\n\n## Philosophy\n\nEvery phase produces runnable code. The agent loop is handwritten for transparency — no framework black boxes. Character data is decoupled from agent logic so multi-character conversations can be added later.\n\n## Dependencies\n\n- **LLM**: DeepSeek (OpenAI-compatible API)\n- **Vector DB**: ChromaDB with sentence-transformers for local embeddings\n- **UI**: Streamlit\n- **Docs parsing**: pypdf, markdown\n\n---\n\n*For architecture details, data flow diagrams, and the full roadmap, see [ARCHITECTURE.md](dev/ARCHITECTURE.md).*\n"}, "4412e13933b21fc9ad07d5f8328f36cef057d09b": {"t": 1785766179.340064, "n": 8894, "h": "5053ee606b9b6edc", "c": "# Build Agent — 从零学习 Agent 开发\n\n一个渐进式 Agent 学习项目。从 RAG 管线开始,逐步构建为支持角色扮演的多功能 Agent 系统。\n\n## 项目哲学\n\n> 每个 Phase 产出能跑的代码,而不是一堆未验证的文件。\n\n- **增量构建**:每个 Phase 只做一件事,跑通再进下一步\n- **手写核心**:Agent 循环手写而非依赖框架黑盒\n- **可扩展**:架构预留了多 Agent 协作的升级空间\n\n---\n\n## 架构总览\n\n```\n┌──────────────────────────────────────────────────────┐\n│ UI 层 (Streamlit) │\n│ 文档管理 / 角色选择 / 对话展示 │\n├──────────────────────────────────────────────────────┤\n│ Agent 层 (core.py) │\n│ ReAct 循环 / 工具调度 / 记忆管理 │\n│ ┌─────────────┐ ┌──────────────────┐ │\n│ │ QA Mode │ │ Roleplay Mode │ │\n│ │ (检索→回答) │ │ (Persona→对话) │ │\n│ └─────────────┘ └──────────────────┘ │\n├──────────────────────────────────────────────────────┤\n│ Character 层 (character/) │\n│ Persona Card / Prompt 生成 / 对话解析 / 注册表 │\n├──────────────────────────────────────────────────────┤\n│ Document 层 (document/) │\n│ 文档加载 / 文本分块 / 向量嵌入 / 语义检索 │\n├──────────────────────────────────────────────────────┤\n│ 数据层 │\n│ ChromaDB (向量) / 文件系统 (原始文档) │\n└──────────────────────────────────────────────────────┘\n```\n\n### 数据流\n\n```\nQA 模式:\n 用户问题 → Agent 判断用哪个工具 → 检索 ChromaDB → 拼接上下文 → 生成回答\n\nRP 模式:\n 用户消息 → Agent 以角色人格回应 → 按需检索角色记忆 → 更新动态上下文 → 生成对话\n```\n\n### 扩展预留\n\n```\n未来 A2A(Agent-to-Agent):\n ┌──────────┐ ┌──────────────┐ ┌──────────┐\n │ Luna Agent│ ←→ │ Conversation │ ←→ │ Max Agent │\n └──────────┘ │ (消息总线) │ └──────────┘\n └──────────────┘\n │\n 用户旁观 / 介入\n```\n\n**设计原则**:\n- `Character` 是纯数据,不依赖任何 Agent\n- `Agent` 接收 `Character` 配置,不关心具体角色\n- 未来多 Agent:`Conversation` 管理 N 个 Agent,路由消息\n- 消息总线接口预留在 `src/conversation/`(Phase 9+)\n\n---\n\n## 路线图\n\n| Phase | 状态 | 内容 |\n|-------|------|------|\n| 1: RAG 管线 | ✅ | 文档→分块→嵌入→检索→回答 |\n| 2: Agent 循环 | ✅ | ReAct + Tool Calling,手写循环 |\n| 3: 对话记忆 | ✅ | 摘要缓冲,Token 预算管理 |\n| 4: Streamlit UI | ✅ | 文档管理 + 对话界面 + 思考展示 |\n| 5: 人格 Prompt | ✅ | Persona Card 结构 + 3层 Prompt 生成器 |\n| **5a: 数据清洗** | ✅ | 多游戏解析器架构 + .ast 对话提取 + Trigger 自动扫描 |\n| 6: 对话导入 | ✅ | 游戏对话入 ChromaDB + 角色记忆检索 |\n| 7: 角色 Agent | ✅ | 动态上下文 + 情感线索记忆 |\n| 8: 多角色 UI | 📋 | 角色切换 + Persona 编辑 |\n| 9: A2A(规划) | 💡 | 多 Agent 自动对话 |\n\n---\n\n## 快速开始\n\n```bash\n# 1. 安装依赖\npip install -r requirements.txt\n\n# 2. 配置 API Key\ncp .env.example .env\n# 编辑 .env,填入 DEEPSEEK_API_KEY=sk-...\n\n# 3. 运行\nstreamlit run src/ui/app.py # Web UI(含文档管理 + 角色对话 + 记忆管理)\npython -m src.agent_cli # Agent CLI(QA 模式,含角色记忆检索)\npython -m src.rag_cli # 纯 RAG CLI\npython -m src.character.memory_cli # 对话记忆管理 CLI(Phase 6)\npython -m src.rp_cli # 角色扮演 CLI(Phase 7)\n```\n\n---\n\n## 项目结构\n\n```\nbuild_agent/\n├── src/\n│ ├── config.py # 全局配置\n│ ├── document/ # 文档管线\n│ │ ├── loader.py # PDF/TXT/MD 加载\n│ │ ├── chunker.py # 文本分块策略\n│ │ ├── embedder.py # 向量嵌入 + ChromaDB\n│ │ └── retriever.py # 语义检索接口\n│ ├── agent/ # Agent 核心\n│ │ ├── core.py # ReAct 循环 + 记忆管理(QA Agent)\n│ │ ├── rp_agent.py # 角色扮演 Agent(Phase 7)\n│ │ └── tools.py # 工具定义(含角色记忆检索)\n│ ├── character/ # 角色系统(Phase 5+)\n│ │ ├── persona.py # Persona Card 数据结构 + YAML 加载\n│ │ ├── prompt.py # 3 层 System Prompt 生成器\n│ │ ├── parser.py # 数据清洗 CLI 入口\n│ │ ├── trigger_scanner.py # Trigger 自动扫描器(Phase 5a)\n│ │ ├── memory.py # 对话记忆导入 + 检索(Phase 6)\n│ │ ├── memory_cli.py # 记忆管理 CLI(Phase 6)\n│ │ └── parsers/ # 多游戏解析器包\n│ │ ├── __init__.py # 游戏注册表\n│ │ ├── base.py # GameParser 抽象基类 + 通用清洗管线\n│ │ └── nukitashi_ast.py # NUKITASHI .ast 解析器\n│ ├── ui/\n│ │ └── app.py # Streamlit 界面\n│ ├── rag_cli.py # Phase 1 CLI\n│ ├── agent_cli.py # Phase 2 CLI\n│ └── rp_cli.py # Phase 7 CLI\n├── data/\n│ ├── game_scripts/ # 原始游戏脚本\n│ │ └── NUKITASHI/ # 150 个 .ast 文件\n│ ├── cleaned/ # 清洗后数据\n│ │ └── NUKITASHI/ # 按路线分组的 JSONL\n│ └── personas/ # Persona Card + Trigger 扫描结果\n├── vector_db/ # ChromaDB 持久化\n├── requirements.txt\n└── README.md\n```\n\n---\n\n## 关键设计决策\n\n| 决策 | 选择 | 理由 |\n|------|------|------|\n| Agent 循环 | 手写 ReAct | 学习目的,不用框架黑盒 |\n| LLM | DeepSeek (OpenAI 兼容) | 国内可访问,Tool Calling 支持好 |\n| 向量库 | ChromaDB | 零配置,Windows 友好 |\n| 记忆策略 | 摘要缓冲 | 比纯截断保留更多上下文 |\n| 角色-解耦 | Character 纯数据类 | 为 A2A 预留,Agent 不依赖具体角色 |\n| A2A 预留 | Conversation 消息总线 | Phase 9+,当前只留接口设计 |\n| 多游戏解析 | GameParser 抽象基类 | 每个游戏只需实现 parse_file(),下游全复用 |\n| Trigger 提取 | LLM 批量扫描 + 启发式预过滤 | 从角色台词自动检测情绪触发点,人工审核确认 |\n\n---\n\n## Trigger 自动扫描器(Phase 5a)\n\n`src/character/trigger_scanner.py` 从游戏对话中自动检测角色的情绪触发点:\n\n```\n角色对话 JSONL → 重建上下文窗口 → 启发式预过滤 → LLM 批量分析 → 聚合候选 trigger\n```\n\n**工作原理**:\n1. 从清洗后的对话数据中,为角色的每一句台词提取上下文窗口(前 5 句 + 后 3 句)\n2. 启发式预过滤:优先分析情绪回复(短回复、省略号、括号注释、情绪关键词)\n3. 批量发送给 LLM(每次 8 个窗口),LLM 返回结构化 JSON:`{trigger_topic, emotion_shift, reaction, confidence}`\n4. 聚合同话题 trigger,计算频率和置信度,按强弱分级:strong / moderate / weak\n\n**输出示例**(文乃,100 窗口扫描):\n```\n过去的生活 → 完全沉默(频率 3,moderate)\n笑容 → 回避表情话题(频率 2,moderate) \n人身攻击 → 惊愕退缩(频率 1,weak)\n```\n\n**用法**:\n```bash\npython -m src.character.trigger_scanner 文乃 data/cleaned/NUKITASHI/route_fk.jsonl\n```\n\n**未来的 Persona Card 生成**:Trigger Scanner 提供情绪触发点 → 人审核 → 写入 Persona Card YAML。大部分 Persona Card 字段(性格、说话风格、知识边界)仍需人工精调。\n\n---\n\n## Phase 5a: 多游戏解析器架构\n\n`src/character/parsers/` 实现了游戏无关的对话提取管线:\n\n| 组件 | 职责 | 复用性 |\n|------|------|--------|\n| `GameParser`(抽象基类) | 定义 `parse_file()` 接口 | 所有游戏 |\n| `LuaTableReader` | Lua table 语法解析工具 | `.ast` 格式游戏 |\n| `clean_game_scripts()` | 通用清洗管线(JSONL 输出) | 所有游戏 |\n| `NukitashiASTParser` | NUKITASHI .ast 格式实现 | 仅 NUKITASHI |\n| `DialogueEntry` | 清洗后数据模型 | 所有游戏 |\n\n**添加新游戏只需**:创建 `parsers/<game>_parser.py`,实现 `parse_file()` 方法,在注册表加一行。\n\n---\n\n## Phase 6: 对话记忆导入与检索\n\n`src/character/memory.py` 将清洗后的游戏对话导入 ChromaDB,支持按角色/场景进行语义检索。这是 Phase 7(角色 Agent)的基础设施。\n\n### 数据流\n\n```\nCleaned JSONL → 逐行嵌入 → ChromaDB (collection: character_memory)\n ↓\nUser query → Embed query → Search (可按 speaker/route 过滤) → Retrieved dialogue context\n```\n\n### 核心 API\n\n| 函数 | 用途 |\n|------|------|\n| `import_dialogues(jsonl_path)` | 将 JSONL 对话导入 ChromaDB |\n| `search_character_memory(query, speaker)` | 检索特定角色的对话记忆 |\n| `search_dialogue_memory(query, speaker, route)` | 通用对话搜索(可选过滤) |\n| `retrieve_character_context(query, speaker)` | 返回格式化的上下文字符串,可直接注入 LLM Prompt |\n| `get_memory_stats()` | 已导入对话的统计信息 |\n| `delete_memory()` | 清空记忆 |\n\n### Agent 工具\n\nPhase 6 为 Agent 新增了两个工具:\n\n| 工具 | 用途 |\n|------|------|\n| `search_character_dialogue(speaker, query)` | 搜索某角色关于某话题说过什么 |\n| `search_game_scenes(query, speaker?)` | 搜索游戏场景对话(可选限定角色) |\n\n### CLI 使用\n\n```bash\n# 导入对话\npython -m src.character.memory_cli import data/cleaned/NUKITASHI/route_fk.jsonl\npython -m src.character.memory_cli import data/cleaned/NUKITASHI/all_dialogues.jsonl --max 10000\n\n# 查看统计\npython -m src.character.memory_cli stats\npython -m src.character.memory_cli characters\n\n# 搜索\npython -m src.character.memory_cli search --speaker 文乃 \"过去的事\"\npython -m src.character.memory_cli search \"战斗场景\" --k 6\n\n# 删除\npython -m src.character.memory_cli delete\n```\n\n### 与 Phase 7 的关系\n\nPhase 7(角色 Agent)使用 `retrieve_character_context()` 向 LLM 注入角色的动态记忆,使角色能够回忆过去、感知情绪。\n\n---\n\n## Phase 7: 角色 Agent\n\n`src/agent/rp_agent.py` 是一个完整的角色扮演 Agent——连接 PersonaCard(身份)+ 记忆检索(记忆)+ 情感触发(情绪)。\n\n### 与 QA Agent 的本质区别\n\n| | QA Agent (core.py) | RP Agent (rp_agent.py) |\n|---|---|---|\n| 循环模式 | ReAct(Think→Act→Observe) | 对话(Listen→Remember→Reply) |\n| 工具调用 | 有(6 个工具) | 无(只用记忆检索) |\n| System Prompt | 固定 QA 导向 | 每轮重建(注入 dynamic_context) |\n| 记忆角色 | 工具返回的检索结果 | 角色\"记得\"的过往台词 |\n| Temperature | 0.5 | 0.8 |\n\n### 每轮对话流程\n\n```\n用户消息\n → 关键词匹配 → 检查 PersonaCard 情绪触发点\n → 语义检索 → 搜索角色过往台词 (ChromaDB)\n → 动态上下文 → 合并情绪状态 + 记忆片段\n → System Prompt 重建(build_system_prompt 注入 dynamic_context)\n → LLM 生成 → 角色 in-character 回复\n```\n\n### 核心能力\n\n| 能力 | 实现 |\n|------|------|\n| **角色人格** | PersonaCard → System Prompt(身份/性格/说话风格/知识边界/人际关系) |\n| **对话记忆** | 每轮自动检索 ChromaDB,注入相关过往台词 |\n| **情感触发** | 关键词词典 + fallback 子串匹配,触发时临时改变情绪状态 |\n| **情绪衰减** | 话题转移后自动恢复基线情绪 |\n| **长对话管理** | 角色感知的摘要压缩(保留情绪弧线和关系进展) |\n| **优雅降级** | 记忆未导入时仍能以静态 Persona 模式运作 |\n\n### 用法\n\n```bash\n# CLI\npython -m src.rp_cli data/personas/美岬.yaml\n# 对话中输入 \"context\" 查看幕后信息(情绪/记忆/token)\n\n# Streamlit UI\nstreamlit run src/ui/app.py\n# 切换到 \"Roleplay\" 标签 → 加载 Persona → 开始对话\n```\n\n### 情感触发机制\n\n不使用 LLM 推理(降低成本),而是预建关键词词典 + 子串匹配:\n\n```\n触发话题 → 扩展关键词 → 匹配用户输入 → 临时覆盖情绪状态 → 注入 dynamic_context\n```\n\n内置词典覆盖:父母/家庭/过去/死亡/夸奖/笑容/孤独/恐惧/恋爱/身高/学校/肚子/存在/性/食物 共 15 个情感域。未覆盖的触发话题自动拆分为 2-char 子串匹配。\n\n"}}, "src/config.py": {"9108883e8580aead2f8496720d77182fba5616ef": {"t": 1785746866.633658, "n": 3782, "h": "a26aba266ffa9f00", "c": "\"\"\"\n配置中心 —— Agent 所有行为的控制参数集中在这里。\n\nAgent 开发的第一个难点:参数调优。\n同样的代码,chunk_size 从 500 改成 1000,Agent 的回答质量可能天差地别。\n把所有可调参数集中在此,方便你后期实验对照。\n\"\"\"\nimport os\nfrom pathlib import Path\nfrom dotenv import load_dotenv\n\n# 加载 .env 文件中的环境变量\nload_dotenv()\n\n# ============================================================\n# 项目路径\n# ============================================================\nPROJECT_ROOT = Path(__file__).parent.parent\nDATA_DIR = PROJECT_ROOT / \"data\"\nVECTOR_DB_DIR = PROJECT_ROOT / \"vector_db\"\n\n# ============================================================\n# DeepSeek API 配置(兼容 OpenAI 格式)\n# ============================================================\nDEEPSEEK_API_KEY = os.getenv(\"DEEPSEEK_API_KEY\")\nDEEPSEEK_BASE_URL = os.getenv(\"DEEPSEEK_BASE_URL\", \"https://api.deepseek.com\")\n\ndef get_api_key():\n \"\"\"延迟检查 API Key,只在真正需要时才报错\"\"\"\n if not DEEPSEEK_API_KEY:\n raise ValueError(\n \"未找到 DEEPSEEK_API_KEY!\\n\"\n \"请在 .env 文件中设置: DEEPSEEK_API_KEY=sk-...\"\n )\n return DEEPSEEK_API_KEY\n\n# 模型选择:\n# - deepseek-chat: DeepSeek-V3,性价比最高的日常模型\n# - deepseek-reasoner: DeepSeek-R1,深度推理,适合复杂任务\nMODEL_NAME = os.getenv(\"MODEL_NAME\", \"deepseek-v4-flash\")\n\n# LLM 参数\nTEMPERATURE = 0.5 # 0=确定性,1=创造性。Agent 需要一定确定性来正确调用工具\nMAX_TOKENS = 4096 # 单次回复最大 token 数\n\n# ============================================================\n# Embedding 模型配置\n# ============================================================\n# all-MiniLM-L6-v2: 384维,轻量快速,免费本地运行\n# 首次运行会自动下载模型(约 80MB)\nEMBEDDING_MODEL = os.getenv(\"EMBEDDING_MODEL\", \"all-MiniLM-L6-v2\")\n\n# HuggingFace 镜像(国内用户需要)\n# sentence-transformers 底层从 huggingface.co 下载模型\n# 设置此变量可使用国内镜像加速\nHF_ENDPOINT = os.getenv(\"HF_ENDPOINT\", \"https://hf-mirror.com\")\nif HF_ENDPOINT:\n os.environ[\"HF_ENDPOINT\"] = HF_ENDPOINT\n\n# ============================================================\n# 文档分块参数\n# ============================================================\n# 这是 RAG 最关键的超参数之一:\n# - 太小(200):语义碎片化,检索到的片段缺乏上下文\n# - 太大(2000):一个 chunk 包含太多无关内容,降低检索精度\n# - 1000 + 200 overlap 是经过大量实践验证的平衡点\nCHUNK_SIZE = 1000 # 每个文本块的最大字符数\nCHUNK_OVERLAP = 200 # 相邻块之间的重叠字符数(保留上下文连续性)\n\n# ============================================================\n# 检索参数\n# ============================================================\nRETRIEVAL_K = 4 # 每次检索返回的最相关片段数\n# 为什么是 4?\n# - 太少(1-2):可能漏掉关键信息\n# - 太多(8-10):噪声增加,且消耗大量 token\n# - 4 是实践中常用的默认值,适合 Claude 的上下文窗口\n\n# ============================================================\n# Agent 参数\n# ============================================================\nMAX_AGENT_ITERATIONS = 10 # Agent 最多执行多少轮\"思考-行动\"\n# 这个参数直接体现 Agent 的核心难点:\n# 设太小 → 复杂问题没推理完就被截断\n# 设太大 → Agent 可能陷入循环(反复调同一个工具却得不到满意结果)\n# 10 是 LangChain 的默认值,对学习阶段合适\n\nAGENT_VERBOSE = True # 是否打印 Agent 思考过程(学习期强烈建议 True)\n\n# ============================================================\n# 角色扮演 Agent 参数 (Phase 7)\n# ============================================================\nRP_TEMPERATURE = 0.8 # 角色扮演需要更高创造性(QA 用 0.5)\nRP_MAX_TOKENS = 2048 # 角色单次回复最大 token\nRP_MAX_TOKEN_LIMIT = 6000 # RP 对话 token 预算(比 QA 宽松,无工具调用)\nRP_MEMORY_K = 4 # 每轮检索的角色记忆条数\nRP_MIN_INPUT_FOR_MEMORY = 4 # 用户输入少于这个字数时跳过记忆检索\nRP_MAX_CONTEXT_CHARS = 800 # dynamic_context 最大字符数\n\n# ============================================================\n# 对话记忆参数\n# ============================================================\nMAX_TOKEN_LIMIT = 4000 # 记忆缓冲区的最大 token 数\n# 这是记忆管理的核心难点:\n# Claude 上下文窗口有限(Sonnet 约 200K),但每轮对话、检索结果、\n# 工具输出都在消耗 token。必须控制记忆大小,否则几轮对话后 agent 就\"忘\"了\n\n# ============================================================\n# Web 搜索参数\n# ============================================================\nWEB_SEARCH_RESULTS = 3 # 每次网页搜索返回的结果数\n\n# 确保必要目录存在\nDATA_DIR.mkdir(exist_ok=True)\nVECTOR_DB_DIR.mkdir(exist_ok=True)\n"}, "4412e13933b21fc9ad07d5f8328f36cef057d09b": {"t": 1785766177.0294118, "n": 3782, "h": "a26aba266ffa9f00", "c": "\"\"\"\n配置中心 —— Agent 所有行为的控制参数集中在这里。\n\nAgent 开发的第一个难点:参数调优。\n同样的代码,chunk_size 从 500 改成 1000,Agent 的回答质量可能天差地别。\n把所有可调参数集中在此,方便你后期实验对照。\n\"\"\"\nimport os\nfrom pathlib import Path\nfrom dotenv import load_dotenv\n\n# 加载 .env 文件中的环境变量\nload_dotenv()\n\n# ============================================================\n# 项目路径\n# ============================================================\nPROJECT_ROOT = Path(__file__).parent.parent\nDATA_DIR = PROJECT_ROOT / \"data\"\nVECTOR_DB_DIR = PROJECT_ROOT / \"vector_db\"\n\n# ============================================================\n# DeepSeek API 配置(兼容 OpenAI 格式)\n# ============================================================\nDEEPSEEK_API_KEY = os.getenv(\"DEEPSEEK_API_KEY\")\nDEEPSEEK_BASE_URL = os.getenv(\"DEEPSEEK_BASE_URL\", \"https://api.deepseek.com\")\n\ndef get_api_key():\n \"\"\"延迟检查 API Key,只在真正需要时才报错\"\"\"\n if not DEEPSEEK_API_KEY:\n raise ValueError(\n \"未找到 DEEPSEEK_API_KEY!\\n\"\n \"请在 .env 文件中设置: DEEPSEEK_API_KEY=sk-...\"\n )\n return DEEPSEEK_API_KEY\n\n# 模型选择:\n# - deepseek-chat: DeepSeek-V3,性价比最高的日常模型\n# - deepseek-reasoner: DeepSeek-R1,深度推理,适合复杂任务\nMODEL_NAME = os.getenv(\"MODEL_NAME\", \"deepseek-v4-flash\")\n\n# LLM 参数\nTEMPERATURE = 0.5 # 0=确定性,1=创造性。Agent 需要一定确定性来正确调用工具\nMAX_TOKENS = 4096 # 单次回复最大 token 数\n\n# ============================================================\n# Embedding 模型配置\n# ============================================================\n# all-MiniLM-L6-v2: 384维,轻量快速,免费本地运行\n# 首次运行会自动下载模型(约 80MB)\nEMBEDDING_MODEL = os.getenv(\"EMBEDDING_MODEL\", \"all-MiniLM-L6-v2\")\n\n# HuggingFace 镜像(国内用户需要)\n# sentence-transformers 底层从 huggingface.co 下载模型\n# 设置此变量可使用国内镜像加速\nHF_ENDPOINT = os.getenv(\"HF_ENDPOINT\", \"https://hf-mirror.com\")\nif HF_ENDPOINT:\n os.environ[\"HF_ENDPOINT\"] = HF_ENDPOINT\n\n# ============================================================\n# 文档分块参数\n# ============================================================\n# 这是 RAG 最关键的超参数之一:\n# - 太小(200):语义碎片化,检索到的片段缺乏上下文\n# - 太大(2000):一个 chunk 包含太多无关内容,降低检索精度\n# - 1000 + 200 overlap 是经过大量实践验证的平衡点\nCHUNK_SIZE = 1000 # 每个文本块的最大字符数\nCHUNK_OVERLAP = 200 # 相邻块之间的重叠字符数(保留上下文连续性)\n\n# ============================================================\n# 检索参数\n# ============================================================\nRETRIEVAL_K = 4 # 每次检索返回的最相关片段数\n# 为什么是 4?\n# - 太少(1-2):可能漏掉关键信息\n# - 太多(8-10):噪声增加,且消耗大量 token\n# - 4 是实践中常用的默认值,适合 Claude 的上下文窗口\n\n# ============================================================\n# Agent 参数\n# ============================================================\nMAX_AGENT_ITERATIONS = 10 # Agent 最多执行多少轮\"思考-行动\"\n# 这个参数直接体现 Agent 的核心难点:\n# 设太小 → 复杂问题没推理完就被截断\n# 设太大 → Agent 可能陷入循环(反复调同一个工具却得不到满意结果)\n# 10 是 LangChain 的默认值,对学习阶段合适\n\nAGENT_VERBOSE = True # 是否打印 Agent 思考过程(学习期强烈建议 True)\n\n# ============================================================\n# 角色扮演 Agent 参数 (Phase 7)\n# ============================================================\nRP_TEMPERATURE = 0.8 # 角色扮演需要更高创造性(QA 用 0.5)\nRP_MAX_TOKENS = 2048 # 角色单次回复最大 token\nRP_MAX_TOKEN_LIMIT = 6000 # RP 对话 token 预算(比 QA 宽松,无工具调用)\nRP_MEMORY_K = 4 # 每轮检索的角色记忆条数\nRP_MIN_INPUT_FOR_MEMORY = 4 # 用户输入少于这个字数时跳过记忆检索\nRP_MAX_CONTEXT_CHARS = 800 # dynamic_context 最大字符数\n\n# ============================================================\n# 对话记忆参数\n# ============================================================\nMAX_TOKEN_LIMIT = 4000 # 记忆缓冲区的最大 token 数\n# 这是记忆管理的核心难点:\n# Claude 上下文窗口有限(Sonnet 约 200K),但每轮对话、检索结果、\n# 工具输出都在消耗 token。必须控制记忆大小,否则几轮对话后 agent 就\"忘\"了\n\n# ============================================================\n# Web 搜索参数\n# ============================================================\nWEB_SEARCH_RESULTS = 3 # 每次网页搜索返回的结果数\n\n# 确保必要目录存在\nDATA_DIR.mkdir(exist_ok=True)\nVECTOR_DB_DIR.mkdir(exist_ok=True)\n"}}}}