这是一个以 CLI 为主 的手写智能 Agent 项目,当前核心能力已经覆盖:
- Plan-and-Execute + ReAct 主循环
- 子智能体 / 多智能体协作
- Skills 技能系统
- 本地 RAG 知识库(支持
md / txt / docx / pdf) - MCP Server 工具接入
- Hook 事件机制
- 会话记忆与长期记忆
项目的目标不是做一个“单轮聊天壳”,而是做一个可执行任务、可扩展、可编排的 Agent 框架。
-
通用问答直答路径
- 对纯概念型问题,Agent 会跳过任务规划,直接走回答路径。
-
Plan-and-Execute 路径
- 先调用模型生成
<step>计划。 - 用户确认后,逐步执行每个步骤。
- 先调用模型生成
-
ReAct 执行路径
- 每个步骤内部通过
<thought> / <action> / <observation>小循环完成。
- 每个步骤内部通过
-
失败恢复
- 同一工具连续失败时,会触发恢复逻辑,避免无意义重试。
-
历史压缩与会话上下文
- 自动注入最近的会话历史。
- 超过阈值时压缩消息,降低上下文溢出风险。
-
子智能体
task()- 在独立上下文中执行子任务,不污染父上下文。
-
队友管理
- 支持创建队友、列出队友、查看收件箱、广播、发送定向消息。
-
计划审批 / 优雅下线
- 队友可提交计划审批请求。
- 领导可发起 shutdown request,队友可批准或拒绝。
-
团队状态命令
/status/team/inbox [name]
-
技能发现
- 启动时扫描
skills/*/SKILL.md。
- 启动时扫描
-
两种触发方式
- Slash 命令:
/analyze-code - 关键词匹配:例如“帮我分析代码质量”
- Slash 命令:
-
按需加载
- 先只加载轻量 manifest。
- 真正执行时再
load_skill()读取完整技能正文。
-
附加资源延迟读取
- 技能目录内的参考资料不会一上来全部注入提示词。
当前内置技能目录:
analyze-codelist-fileswrite-tests
-
支持文档格式
mdtxtdocx- 文本型
pdf
-
结构化解析
- 提取标题、段落、章节路径、页码。
- 先形成
block,再组合成chunk。
-
结构化分块
- 尽量不跨章节切块。
- 支持 chunk overlap。
- 超长段优先做句子级语义切分,再退回字符滑窗切分。
-
索引构建
- 使用
SentenceTransformer("all-MiniLM-L6-v2")生成 embedding。 - 使用 ChromaDB 持久化向量库。
- 使用
-
查询增强
- 先做向量召回。
- 再做轻量关键词重排。
- 查询结果带上更丰富的 metadata:
- 来源文件
- 相对路径
- 文件类型
- 标题
- 章节路径
- chunk 序号
- PDF 页码范围
- 支持从
.mcp/config.json读取 MCP server 配置 - 当前仅支持
stdiotransport - 启动时自动连接 server 并加载 tools
- 自动把 MCP tool 包装成 Agent 可调用工具
/status可查看 MCP server 连接状态
-
SessionStart
- 在会话开始前运行
-
PreToolUse
- 工具执行前运行
- 当前默认会拦截空的终端命令
-
PostToolUse
- 工具执行后运行
- 当前默认记录工具调用日志
基础工具:
read_filewrite_to_filerun_terminal_commandlist_directorysearch_in_filesweb_searchquery_knowledge_base
Agent 扩展工具:
load_skillsave_memorytaskspawn_teammatelist_teammatessend_messagebroadcast_messageread_team_inboxget_statusrequest_shutdownreview_plan- 动态 MCP tools(如果已连接 MCP server)
.
├── agent.py # ReActAgent、子智能体、CLI 入口
├── team.py # 多智能体消息总线与队友线程管理
├── tools.py # 基础工具与知识库查询
├── skills.py # 技能注册、匹配、按需加载
├── hooks.py # HookRunner 与默认 Hook
├── memory.py # 长期记忆存储
├── prompt_template.py # Plan / ReAct / Subagent / Direct Answer 提示词模板
├── internal_mcp/
│ ├── client.py # MCP client 管理与 tool 调用
│ ├── config.py # .mcp/config.json 解析
│ └── registry.py # MCP tool 包装与注册
├── skills/
│ ├── analyze-code/
│ ├── list-files/
│ └── write-tests/
├── rag/
│ ├── build_index.py # 索引构建入口
│ ├── document_pipeline.py # 文档解析、block/chunk 构建
│ ├── docs/ # 知识库原始文档
│ └── chroma_db/ # Chroma 持久化目录
└── README.md
核心依赖:
google-genaichromadbsentence-transformerspython-docxpypdfmcpddgs
uv sync在项目根目录创建 .env:
GOOGLE_API_KEY=your_google_api_key_here
HTTPS_PROXY=http://127.0.0.1:7890
HTTP_PROXY=http://127.0.0.1:7890说明:
- 使用
gemini-*模型时需要GOOGLE_API_KEY - 使用 Ollama 本地模型时不需要 Google API Key
使用 Gemini:
uv run python agent.py .使用 Ollama:
ollama pull qwen2.5:3b
uv run python agent.py . --model qwen2.5:3b查看帮助:
uv run python agent.py --help先把知识库文档放到 rag/docs/,然后运行:
uv run python rag/build_index.py支持格式:
.md.txt.docx.pdf
Slash 技能:
/analyze-code
/list-files
/write-tests
团队状态命令:
/status
/team
/inbox
/inbox alice
自然语言示例:
请帮我分析这个仓库的代码结构
请用多 agent 模式处理这个任务,并创建 researcher/coder/tester 队友
帮我查询知识库里关于 LangChain Chains 的内容
flowchart TD
A["用户输入"] --> B["加载 memory section"]
B --> C["运行 SessionStart Hook"]
C --> D{"是否特殊命令"}
D -->|是| E["/status · /team · /inbox"]
D -->|否| F{"是否命中 slash skill 或关键词"}
F -->|是| G["生成 skill hint 或 load_skill 提示"]
F -->|否| H["直接进入任务决策"]
G --> H
H --> I{"是否通用问答"}
I -->|是| J["Direct Answer"]
I -->|否| K["Plan 阶段生成 step 列表"]
K --> L{"规划是否成功"}
L -->|否| M["降级为纯 ReAct Loop"]
L -->|是| N["用户确认计划"]
N --> O["逐步执行 execute_step"]
O --> P["汇总所有 step 结果"]
P --> Q["输出 final_answer"]
J --> Q
M --> Q
flowchart TD
A["主智能体"] --> B["spawn_teammate"]
B --> C["TeammateManager 创建线程"]
C --> D["队友独立 ReAct Loop"]
D --> E["build_teammate_tools"]
E --> F["读取 inbox / 执行工具 / 发送消息"]
F --> G{"是否完成任务"}
G -->|否| D
G -->|是| H["send_message 或 task_result 回传 lead"]
A --> I["/team · /status · /inbox"]
A --> J["request_shutdown · review_plan"]
J --> C
flowchart TD
A["rag/docs 中的 md / txt / docx / pdf"] --> B["load_documents"]
B --> C["按格式解析成 document 和 blocks"]
C --> D["build_chunks"]
D --> E["结构化 chunk、overlap 与 metadata"]
E --> F["SentenceTransformer 生成 embedding"]
F --> G["ChromaDB 持久化"]
H["query_knowledge_base"] --> I["问题 embedding"]
I --> G
G --> J["向量召回候选"]
J --> K["关键词轻量重排"]
K --> L["返回片段、来源、标题、章节、页码"]
flowchart TD
A["启动 Agent"] --> B["扫描 skills/*/SKILL.md"]
B --> C["解析 frontmatter 和 Description/Keywords"]
C --> D["仅保存轻量 manifest"]
E["用户输入"] --> F{"是否 /skill-name"}
F -->|是| G["精确命中技能"]
F -->|否| H["match_skill 关键词匹配"]
G --> I["提示先调用 load_skill"]
H --> I
I --> J["按需读取完整技能正文"]
J --> K["必要时再读取技能附加资源"]
K --> L["进入计划或执行阶段"]
flowchart TD
A["项目目录 .mcp/config.json"] --> B["load_mcp_server_configs"]
B --> C["MCPClientManager.load_servers"]
C --> D["连接 stdio server"]
D --> E["list_tools"]
E --> F["MCPToolRegistry 生成包装函数"]
F --> G["注册到 Agent tools"]
G --> H["模型在执行阶段调用 mcp_xxx 工具"]
H --> I["client.call_tool"]
I --> J["返回格式化结果"]
flowchart TD
A["用户开始会话"] --> B["SessionStart Hook"]
B --> C{"exit_code"}
C -->|BLOCK| D["直接终止"]
C -->|APPEND| E["附加消息到任务上下文"]
C -->|CONTINUE| F["继续执行 Agent"]
F --> G["模型生成 action"]
G --> H["PreToolUse Hook"]
H --> I{"是否允许执行工具"}
I -->|否| J["返回阻止信息"]
I -->|是| K["执行工具"]
K --> L["PostToolUse Hook"]
L --> M["写回 observation"]
agent.py 中的 ReActAgent.run() 是总入口,当前主流程大致分为三条:
-
特殊命令路径
/status/team/inbox [name]
-
通用问答路径
- 识别为概念问答后,直接调用
_direct_answer() - 默认只暴露
web_search和query_knowledge_base
- 识别为概念问答后,直接调用
-
任务执行路径
- 先规划
- 再逐步执行
- 最后汇总
当前多智能体分为两层:
-
轻量子智能体
task(prompt)- 用于派生一个独立上下文的小代理执行子任务
-
队友线程模型
- 由
team.py中的TeammateManager管理 - 基于
MessageBus的 inbox 文件通信 - 适合更持久的 team-style 协作
- 由
当前 RAG 的核心文件:
rag/document_pipeline.pyrag/build_index.pytools.py::query_knowledge_base
当前分块参数:
CHUNK_SIZE = 500CHUNK_OVERLAP = 50
当前 chunking 逻辑:
- 尽量保持同一 chunk 不跨章节
- 普通情况按 block 组合 chunk
- 超长段优先按句子/换行做语义切分
- 仍不够时退回字符滑窗切分
技能系统当前是“轻量发现 + 按需加载”模式:
- 启动时只读取 manifest
- 真正执行时再加载完整技能正文
- 技能附加资源只暴露路径,不一次性全部注入上下文
当前 MCP 配置文件位置:
.mcp/config.json
当前配置要求:
servers必须是数组- 当前只支持
stdio command必填args必须是字符串数组env必须是字符串字典
一个最小示例:
{
"servers": [
{
"name": "example",
"transport": "stdio",
"command": "python",
"args": ["path/to/server.py"],
"enabled": true
}
]
}默认 Hook 在 hooks.py 中注册:
SessionStartPreToolUsePostToolUse
默认行为:
- 会话开始时打印
SessionStart - 工具执行前校验空终端命令
- 工具执行后打印
PostToolUse
- 在
tools.py中定义函数并写清 docstring - 在
agent.py的main()中加入基础工具列表,或在ReActAgent.__init__()中注册为方法工具 - 启动后工具会自动出现在提示词工具列表中
在 skills/<skill-name>/SKILL.md 中编写技能文件,推荐包含:
- frontmatter(可选)
# 标题## Description## Keywords## Steps
技能会在下次启动时自动发现。
- 在
hooks.py中实现一个 handler - 返回
HookResult或字典 - 在
build_default_hook_runner()中注册事件
- 在项目根目录创建或修改
.mcp/config.json - 配置好
command、args、env - 重启 Agent
- 用
/status查看 MCP server 是否成功连接
- 概念型问题:适合直接问,Agent 会倾向走直答路径
- 项目分析 / 改代码:适合走 Plan-and-Execute + ReAct
- 复杂任务拆分:显式要求使用 multi-agent
- 固定类型任务:优先用 Skills
- 知识问答:先构建 RAG 索引,再用
query_knowledge_base - 外部工具生态接入:优先通过 MCP
- 使用 Gemini 时请确保
.env和代理配置可用 run_terminal_command属于高风险工具,执行前务必确认命令内容- 构建 RAG 前请先把文档放进
rag/docs/ - PDF 支持基于文本提取,对扫描版图片 PDF 不保证效果
- 当前 MCP 仅支持
stdiotransport
- MarkTechStation/VideoCode
- Google Gemini API
- Ollama
- ChromaDB
- sentence-transformers
本项目基于 MIT License 开源。