玄同 765
大语言模型 (LLM) 开发工程师 | 中国传媒大学 · 数字媒体技术(智能交互与游戏设计)
CSDN · 个人主页 | GitHub · Follow
关于作者
- 深耕领域:大语言模型开发 / RAG 知识库 / AI Agent 落地 / 模型微调
- 技术栈:Python | RAG (LangChain / Dify + Milvus) | FastAPI + Docker
- 工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案
「让 AI 交互更智能,让技术落地更高效」 欢迎技术探讨与项目合作,解锁大模型与智能交互的无限可能!
FinchBot (雀翎) – 一个真正灵活的 AI Agent 框架

作者:玄同765 (xt765) 项目地址:GitHub – FinchBot 国内镜像:Gitee – FinchBot
摘要
FinchBot (雀翎) 是一个轻量级、模块化的 AI Agent 框架,基于 LangChain v1.2 和 LangGraph v1.0 构建。它不是又一个简单的 LLM 封装,而是一个深思熟虑的架构设计,专注于三个核心问题:
本文将深入剖析 FinchBot 的架构设计,带你了解一个生产级 Agent 框架的诞生过程。
一、为什么选择 FinchBot?
在 AI Agent 框架百花齐放的今天,你可能会问:为什么还需要 FinchBot?
1.1 现有框架的痛点
| 扩展困难 | 需要修改核心代码 | 继承基类或创建 Markdown 文件 |
| 记忆脆弱 | 依赖 LLM 上下文窗口 | 双层持久化存储 + 语义检索 |
| 提示词僵化 | 硬编码在代码中 | 文件系统,热加载 |
| 架构过时 | 基于 LangChain 旧版 API | LangChain v1.2 + LangGraph v1.0 |
1.2 FinchBot 的设计哲学
隐私优先 → 本地 Embedding,数据不上云
模块化 → 每个组件独立可替换
开发者友好 → 类型安全 + 完善文档
生产级稳定 → 双重检查锁 + 自动重试 + 超时控制
开箱即用 → 零配置启动,自动降级,富文本界面
1.3 开箱即用体验
FinchBot 将 “开箱即用” 作为核心设计理念——无需复杂配置即可上手:
三步快速上手:
# 第一步:配置 API 密钥和默认模型
uv run finchbot config
# 第二步:管理你的会话
uv run finchbot sessions
# 第三步:开始对话
uv run finchbot chat
| 三步上手 | config → sessions → chat,三个命令完成完整工作流程 |
| 环境变量配置 | 所有配置均可通过环境变量设置(OPENAI_API_KEY、ANTHROPIC_API_KEY 等) |
| Rich CLI 界面 | 全屏键盘导航,↑/↓ 箭头选择,交互式操作 |
| i18n 国际化 | 内置中英文支持,自动检测系统语言 |
| 自动降级 | 网页搜索自动降级:Tavily → Brave → DuckDuckGo |
| 零配置启动 | 只需设置 API Key,运行 finchbot chat 即可 |
二、记忆架构:双层存储 + Agentic RAG
FinchBot 实现了先进的双层记忆架构,彻底解决了 LLM 上下文窗口限制和长期记忆遗忘问题。
2.1 为什么是 Agentic RAG?
| 检索触发 | 固定流程 | Agent 自主决策 |
| 检索策略 | 单一向量检索 | 混合检索 + 权重动态调整 |
| 记忆管理 | 被动存储 | 主动 remember/recall/forget |
| 分类能力 | 无 | 自动分类 + 重要性评分 |
| 更新机制 | 全量重建 | 增量同步 |
2.2 双层存储架构
#mermaid-svg-iaPbHEuZ5ILhD8cY{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iaPbHEuZ5ILhD8cY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iaPbHEuZ5ILhD8cY .error-icon{fill:#552222;}#mermaid-svg-iaPbHEuZ5ILhD8cY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iaPbHEuZ5ILhD8cY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iaPbHEuZ5ILhD8cY .marker.cross{stroke:#333333;}#mermaid-svg-iaPbHEuZ5ILhD8cY svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iaPbHEuZ5ILhD8cY p{margin:0;}#mermaid-svg-iaPbHEuZ5ILhD8cY .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-iaPbHEuZ5ILhD8cY .cluster-label text{fill:#333;}#mermaid-svg-iaPbHEuZ5ILhD8cY .cluster-label span{color:#333;}#mermaid-svg-iaPbHEuZ5ILhD8cY .cluster-label span p{background-color:transparent;}#mermaid-svg-iaPbHEuZ5ILhD8cY .label text,#mermaid-svg-iaPbHEuZ5ILhD8cY span{fill:#333;color:#333;}#mermaid-svg-iaPbHEuZ5ILhD8cY .node rect,#mermaid-svg-iaPbHEuZ5ILhD8cY .node circle,#mermaid-svg-iaPbHEuZ5ILhD8cY .node ellipse,#mermaid-svg-iaPbHEuZ5ILhD8cY .node polygon,#mermaid-svg-iaPbHEuZ5ILhD8cY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iaPbHEuZ5ILhD8cY .rough-node .label text,#mermaid-svg-iaPbHEuZ5ILhD8cY .node .label text,#mermaid-svg-iaPbHEuZ5ILhD8cY .image-shape .label,#mermaid-svg-iaPbHEuZ5ILhD8cY .icon-shape .label{text-anchor:middle;}#mermaid-svg-iaPbHEuZ5ILhD8cY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-iaPbHEuZ5ILhD8cY .rough-node .label,#mermaid-svg-iaPbHEuZ5ILhD8cY .node .label,#mermaid-svg-iaPbHEuZ5ILhD8cY .image-shape .label,#mermaid-svg-iaPbHEuZ5ILhD8cY .icon-shape .label{text-align:center;}#mermaid-svg-iaPbHEuZ5ILhD8cY .node.clickable{cursor:pointer;}#mermaid-svg-iaPbHEuZ5ILhD8cY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-iaPbHEuZ5ILhD8cY .arrowheadPath{fill:#333333;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iaPbHEuZ5ILhD8cY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iaPbHEuZ5ILhD8cY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iaPbHEuZ5ILhD8cY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iaPbHEuZ5ILhD8cY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-iaPbHEuZ5ILhD8cY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iaPbHEuZ5ILhD8cY .cluster text{fill:#333;}#mermaid-svg-iaPbHEuZ5ILhD8cY .cluster span{color:#333;}#mermaid-svg-iaPbHEuZ5ILhD8cY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-iaPbHEuZ5ILhD8cY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iaPbHEuZ5ILhD8cY rect.text{fill:none;stroke-width:0;}#mermaid-svg-iaPbHEuZ5ILhD8cY .icon-shape,#mermaid-svg-iaPbHEuZ5ILhD8cY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iaPbHEuZ5ILhD8cY .icon-shape p,#mermaid-svg-iaPbHEuZ5ILhD8cY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-iaPbHEuZ5ILhD8cY .icon-shape rect,#mermaid-svg-iaPbHEuZ5ILhD8cY .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iaPbHEuZ5ILhD8cY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-iaPbHEuZ5ILhD8cY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-iaPbHEuZ5ILhD8cY :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
服务层
存储层
业务层
MemoryManager
SQLiteStore真相源
VectorMemoryStore语义检索
RetrievalService混合检索
ClassificationService自动分类
ImportanceScorer重要性评分
DataSyncManager数据同步
结构化层 (SQLite)
# 作为唯一真相源 (Source of Truth)
# 存储内容:完整文本、元数据、分类、重要性、访问日志
class SQLiteStore:
async def add_memory(self, content: str, metadata: dict) –> str:
"""写入记忆,返回唯一 ID"""
async def search_memories(self, query: str, ...) –> list[MemoryItem]:
"""关键词检索,支持元数据过滤"""
async def get_stats(self) –> dict:
"""获取统计信息"""
语义层 (Vector Store)
# 基于 ChromaDB + FastEmbed 本地向量存储
# 支持自然语言语义搜索
class VectorMemoryStore:
async def recall(self, query: str, top_k: int) –> list[MemoryItem]:
"""语义检索,返回最相似的 K 条记忆"""
def _lazy_init(self) –> None:
"""后台线程延迟初始化,不阻塞主流程"""
2.3 混合检索策略
FinchBot 采用加权 RRF (Weighted Reciprocal Rank Fusion) 策略,结合关键词检索和语义检索:
class QueryType(StrEnum):
"""查询类型,决定检索权重"""
KEYWORD_ONLY = "keyword_only" # 纯关键词 (1.0/0.0)
SEMANTIC_ONLY = "semantic_only" # 纯语义 (0.0/1.0)
FACTUAL = "factual" # 事实型 (0.8/0.2)
CONCEPTUAL = "conceptual" # 概念型 (0.2/0.8)
COMPLEX = "complex" # 复杂型 (0.5/0.5)
AMBIGUOUS = "ambiguous" # 歧义型 (0.3/0.7)
RRF 融合算法
def _weighted_rrf(self, query, keyword_weight, vector_weight, k=60):
"""加权 RRF 融合算法"""
scores: dict[str, float] = {}
# 关键词检索结果
keyword_results = self.sqlite_store.search_memories(query)
for rank, item in enumerate(keyword_results):
memory_id = item["id"]
score = keyword_weight * (1.0 / (k + rank + 1))
scores[memory_id] = scores.get(memory_id, 0.0) + score
# 向量检索结果
vector_results = self.vector_store.recall(query)
for rank, item in enumerate(vector_results):
memory_id = item["id"]
score = vector_weight * (1.0 / (k + rank + 1))
scores[memory_id] = scores.get(memory_id, 0.0) + score
# 按融合分数排序
return sorted(scores.items(), key=lambda x: x[1], reverse=True)
2.4 自动分类与重要性评分
# 自动分类(基于关键词 + 语义)
categories = {
"personal": ["我是", "名字", "年龄", "住址"],
"preference": ["喜欢", "讨厌", "偏好", "习惯"],
"work": ["工作", "项目", "任务", "会议"],
"contact": ["邮箱", "电话", "微信"],
"goal": ["目标", "计划", "想要"],
"schedule": ["时间", "日期", "日程"],
}
# 重要性评分规则
IMPORTANCE_RULES = {
"personal": 0.9, # 个人信息最重要
"preference": 0.7, # 偏好次之
"contact": 0.8, # 联系方式重要
"schedule": 0.6, # 日程中等
}
2.5 使用示例
from finchbot.memory import MemoryManager, QueryType
from pathlib import Path
# 初始化
manager = MemoryManager(Path.home() / ".finchbot" / "workspace")
# 保存记忆(自动分类 + 重要性评分)
memory = manager.remember(
content="用户偏好使用深色主题,喜欢简洁的界面设计",
category="preference", # 可手动指定,也可自动推断
importance=0.8
)
# 检索记忆 – 语义优先
results = manager.recall(
query="用户界面偏好",
query_type=QueryType.CONCEPTUAL, # 概念型查询
top_k=5
)
# 检索记忆 – 关键词优先
results = manager.recall(
query="我的邮箱是多少",
query_type=QueryType.FACTUAL, # 事实型查询
top_k=3
)
# 删除记忆
stats = manager.forget("旧邮箱")
三、动态提示词系统:用户可编辑的 Agent 大脑
FinchBot 的提示词系统采用文件系统 + 模块化组装的设计,让用户可以自由定制 Agent 的行为。
3.1 Bootstrap 文件系统
~/.finchbot/
├── SYSTEM.md # 角色设定
├── MEMORY_GUIDE.md # 记忆使用指南
├── SOUL.md # 灵魂设定(性格特征)
├── AGENT_CONFIG.md # Agent 配置
└── workspace/
└── skills/ # 自定义技能
SYSTEM.md 示例
# FinchBot (雀翎)
你是一个轻量级 AI 助手,基于 LangChain Ecosystem 构建。
## 角色定位
你是 FinchBot,一个专业的 AI 助手。
## 人称使用规则
– 用"用户"指代正在与你对话的人
– 用"我"或"FinchBot"指代你自己
– 不要使用"我们"、"咱们"等模糊称呼
## 工具使用原则
– 主动使用工具完成任务,不要只是说"我会记住"
– 当用户说"记住"、"别忘了"等关键词时,立即调用 remember 工具
3.2 提示词加载流程
#mermaid-svg-LH7b1AvQkCaqOR3n{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LH7b1AvQkCaqOR3n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LH7b1AvQkCaqOR3n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LH7b1AvQkCaqOR3n .error-icon{fill:#552222;}#mermaid-svg-LH7b1AvQkCaqOR3n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LH7b1AvQkCaqOR3n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LH7b1AvQkCaqOR3n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LH7b1AvQkCaqOR3n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LH7b1AvQkCaqOR3n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LH7b1AvQkCaqOR3n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LH7b1AvQkCaqOR3n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LH7b1AvQkCaqOR3n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LH7b1AvQkCaqOR3n .marker.cross{stroke:#333333;}#mermaid-svg-LH7b1AvQkCaqOR3n svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LH7b1AvQkCaqOR3n p{margin:0;}#mermaid-svg-LH7b1AvQkCaqOR3n .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-LH7b1AvQkCaqOR3n .cluster-label text{fill:#333;}#mermaid-svg-LH7b1AvQkCaqOR3n .cluster-label span{color:#333;}#mermaid-svg-LH7b1AvQkCaqOR3n .cluster-label span p{background-color:transparent;}#mermaid-svg-LH7b1AvQkCaqOR3n .label text,#mermaid-svg-LH7b1AvQkCaqOR3n span{fill:#333;color:#333;}#mermaid-svg-LH7b1AvQkCaqOR3n .node rect,#mermaid-svg-LH7b1AvQkCaqOR3n .node circle,#mermaid-svg-LH7b1AvQkCaqOR3n .node ellipse,#mermaid-svg-LH7b1AvQkCaqOR3n .node polygon,#mermaid-svg-LH7b1AvQkCaqOR3n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LH7b1AvQkCaqOR3n .rough-node .label text,#mermaid-svg-LH7b1AvQkCaqOR3n .node .label text,#mermaid-svg-LH7b1AvQkCaqOR3n .image-shape .label,#mermaid-svg-LH7b1AvQkCaqOR3n .icon-shape .label{text-anchor:middle;}#mermaid-svg-LH7b1AvQkCaqOR3n .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LH7b1AvQkCaqOR3n .rough-node .label,#mermaid-svg-LH7b1AvQkCaqOR3n .node .label,#mermaid-svg-LH7b1AvQkCaqOR3n .image-shape .label,#mermaid-svg-LH7b1AvQkCaqOR3n .icon-shape .label{text-align:center;}#mermaid-svg-LH7b1AvQkCaqOR3n .node.clickable{cursor:pointer;}#mermaid-svg-LH7b1AvQkCaqOR3n .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LH7b1AvQkCaqOR3n .arrowheadPath{fill:#333333;}#mermaid-svg-LH7b1AvQkCaqOR3n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LH7b1AvQkCaqOR3n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LH7b1AvQkCaqOR3n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LH7b1AvQkCaqOR3n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LH7b1AvQkCaqOR3n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LH7b1AvQkCaqOR3n .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LH7b1AvQkCaqOR3n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LH7b1AvQkCaqOR3n .cluster text{fill:#333;}#mermaid-svg-LH7b1AvQkCaqOR3n .cluster span{color:#333;}#mermaid-svg-LH7b1AvQkCaqOR3n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LH7b1AvQkCaqOR3n .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LH7b1AvQkCaqOR3n rect.text{fill:none;stroke-width:0;}#mermaid-svg-LH7b1AvQkCaqOR3n .icon-shape,#mermaid-svg-LH7b1AvQkCaqOR3n .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LH7b1AvQkCaqOR3n .icon-shape p,#mermaid-svg-LH7b1AvQkCaqOR3n .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LH7b1AvQkCaqOR3n .icon-shape rect,#mermaid-svg-LH7b1AvQkCaqOR3n .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LH7b1AvQkCaqOR3n .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LH7b1AvQkCaqOR3n .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LH7b1AvQkCaqOR3n :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Agent 启动
加载 Bootstrap 文件
SYSTEM.md
MEMORY_GUIDE.md
SOUL.md
AGENT_CONFIG.md
组装提示词
加载常驻技能
构建技能摘要 XML
生成工具文档
注入运行时信息
完整系统提示
发送给 LLM
3.3 模块化组装代码
# context.py – 核心加载逻辑
def build_system_prompt(self, skill_names, use_cache=True) –> str:
parts = []
# 1. 加载 Bootstrap 文件
bootstrap = self._load_bootstrap_files()
parts.append(bootstrap)
# 2. 加载常驻技能
always_skills = self.skills.get_always_skills()
always_content = self.skills.load_skills_for_context(always_skills)
parts.append(always_content)
# 3. 构建技能摘要 (XML 格式)
skills_summary = self.skills.build_skills_summary()
parts.append(skills_summary)
# 4. 生成工具文档
tools_doc = self.tools_generator.generate_tools_content()
parts.append(tools_doc)
return "\\n\\n—\\n\\n".join(parts)
3.4 运行时信息注入
# core.py – 运行时信息
def build_system_prompt(workspace: Path) –> str:
prompt_parts = []
# … Bootstrap 文件 …
# 运行时信息
prompt_parts.append(f"## 当前时间\\n{datetime.now().isoformat()}")
prompt_parts.append(f"## 运行环境\\n{platform.system()} {platform.release()}")
prompt_parts.append(f"## 工作目录\\n{workspace}")
return "\\n\\n".join(prompt_parts)
3.5 用户定制示例
用户只需编辑 ~/.finchbot/SYSTEM.md 即可改变 Agent 行为:
<!– 用户自定义的 SYSTEM.md –>
# FinchBot (雀翎)
## 角色定位
你是一个专注于 Python 开发的 AI 助手。
## 回答风格
– 代码优先,解释在后
– 使用中文回答
– 给出完整可运行的代码示例
## 专业领域
– Python 后端开发
– FastAPI / Flask
– 数据处理与分析
四、技能与工具:无限扩展的 Agent 能力
FinchBot 的扩展性建立在两个层次上:工具层 (Tool) 和 技能层 (Skill)。
4.1 工具系统:代码级能力扩展
工具是 Agent 与外部世界交互的桥梁。FinchBot 提供了 11 个内置工具,并支持轻松扩展。
工具系统架构
#mermaid-svg-PdgnMwOva6crB5jr{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PdgnMwOva6crB5jr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PdgnMwOva6crB5jr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PdgnMwOva6crB5jr .error-icon{fill:#552222;}#mermaid-svg-PdgnMwOva6crB5jr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PdgnMwOva6crB5jr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PdgnMwOva6crB5jr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PdgnMwOva6crB5jr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PdgnMwOva6crB5jr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PdgnMwOva6crB5jr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PdgnMwOva6crB5jr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PdgnMwOva6crB5jr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PdgnMwOva6crB5jr .marker.cross{stroke:#333333;}#mermaid-svg-PdgnMwOva6crB5jr svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PdgnMwOva6crB5jr p{margin:0;}#mermaid-svg-PdgnMwOva6crB5jr .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-PdgnMwOva6crB5jr .cluster-label text{fill:#333;}#mermaid-svg-PdgnMwOva6crB5jr .cluster-label span{color:#333;}#mermaid-svg-PdgnMwOva6crB5jr .cluster-label span p{background-color:transparent;}#mermaid-svg-PdgnMwOva6crB5jr .label text,#mermaid-svg-PdgnMwOva6crB5jr span{fill:#333;color:#333;}#mermaid-svg-PdgnMwOva6crB5jr .node rect,#mermaid-svg-PdgnMwOva6crB5jr .node circle,#mermaid-svg-PdgnMwOva6crB5jr .node ellipse,#mermaid-svg-PdgnMwOva6crB5jr .node polygon,#mermaid-svg-PdgnMwOva6crB5jr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PdgnMwOva6crB5jr .rough-node .label text,#mermaid-svg-PdgnMwOva6crB5jr .node .label text,#mermaid-svg-PdgnMwOva6crB5jr .image-shape .label,#mermaid-svg-PdgnMwOva6crB5jr .icon-shape .label{text-anchor:middle;}#mermaid-svg-PdgnMwOva6crB5jr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PdgnMwOva6crB5jr .rough-node .label,#mermaid-svg-PdgnMwOva6crB5jr .node .label,#mermaid-svg-PdgnMwOva6crB5jr .image-shape .label,#mermaid-svg-PdgnMwOva6crB5jr .icon-shape .label{text-align:center;}#mermaid-svg-PdgnMwOva6crB5jr .node.clickable{cursor:pointer;}#mermaid-svg-PdgnMwOva6crB5jr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PdgnMwOva6crB5jr .arrowheadPath{fill:#333333;}#mermaid-svg-PdgnMwOva6crB5jr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PdgnMwOva6crB5jr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PdgnMwOva6crB5jr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PdgnMwOva6crB5jr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PdgnMwOva6crB5jr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PdgnMwOva6crB5jr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PdgnMwOva6crB5jr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PdgnMwOva6crB5jr .cluster text{fill:#333;}#mermaid-svg-PdgnMwOva6crB5jr .cluster span{color:#333;}#mermaid-svg-PdgnMwOva6crB5jr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PdgnMwOva6crB5jr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PdgnMwOva6crB5jr rect.text{fill:none;stroke-width:0;}#mermaid-svg-PdgnMwOva6crB5jr .icon-shape,#mermaid-svg-PdgnMwOva6crB5jr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PdgnMwOva6crB5jr .icon-shape p,#mermaid-svg-PdgnMwOva6crB5jr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PdgnMwOva6crB5jr .icon-shape rect,#mermaid-svg-PdgnMwOva6crB5jr .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PdgnMwOva6crB5jr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PdgnMwOva6crB5jr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PdgnMwOva6crB5jr :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
内置工具 – 11个
工具注册中心
自定义扩展
继承 FinchTool
注册到 Registry
ToolRegistry全局注册表
双重检查锁线程安全
文件操作read/write/edit/list
网络能力search/extract
记忆管理remember/recall/forget
系统控制exec/session_title
Agent 调用
内置工具一览
| 文件操作 | read_file | 读取本地文件 |
| write_file | 写入本地文件 | |
| edit_file | 编辑文件内容 | |
| list_dir | 列出目录内容 | |
| 网络能力 | web_search | 联网搜索 (Tavily/Brave/DDG) |
| web_extract | 网页内容提取 | |
| 记忆管理 | remember | 主动存储记忆 |
| recall | 检索记忆 | |
| forget | 删除/归档记忆 | |
| 系统控制 | exec | 安全执行 Shell 命令 |
| session_title | 管理会话标题 |
网页搜索:三引擎降级设计
FinchBot 的网页搜索工具采用巧妙的三引擎自动降级机制,兼顾灵活性和开箱即用体验:
| 1 | Tavily | 需要 | 质量最佳,专为 AI 优化,深度搜索 |
| 2 | Brave Search | 需要 | 免费额度大,隐私友好 |
| 3 | DuckDuckGo | 无需 | 始终可用,零配置 |
工作原理:
这个设计确保即使没有任何 API Key 配置,网页搜索也能开箱即用!
会话标题:智能命名,开箱即用
session_title 工具体现了 FinchBot 的开箱即用理念:
| 自动生成 | 对话 2-3 轮后,AI 自动根据内容生成标题 | “Python 异步编程讨论” |
| Agent 修改 | 告诉 Agent “把会话标题改成 XXX” | Agent 调用工具自动修改 |
| 手动重命名 | 在会话管理器中按 r 键重命名 | 用户手动输入新标题 |
# Agent 调用示例
session_title(action="set", title="新会话标题")
# 获取当前标题
session_title(action="get")
这个设计让用户无需关心技术细节,无论是自动还是手动,都能轻松管理会话。
工具注册机制
# 工具基类定义
from finchbot.tools.base import FinchTool
from typing import Any, ClassVar
class MyCustomTool(FinchTool):
"""自定义工具示例"""
name: str = "my_custom_tool"
description: str = "我的自定义工具描述"
parameters: ClassVar[dict[str, Any]] = {
"type": "object",
"properties": {
"input_text": {
"type": "string",
"description": "输入文本"
}
},
"required": ["input_text"]
}
def _run(self, input_text: str) –> str:
# 实现你的逻辑
return f"处理结果: {input_text}"
双重检查锁定保证线程安全
# core.py 中的线程安全实现
def _register_default_tools() –> None:
global _default_tools_registered
if _default_tools_registered:
return
with _tools_registration_lock:
if _default_tools_registered: # 双重检查
return
# 实际注册逻辑…
_default_tools_registered = True
4.2 技能系统:用 Markdown 定义 Agent 能力
技能是 FinchBot 的独特创新——用 Markdown 文件定义 Agent 的能力边界。
最大特色:Agent 自动创建技能
FinchBot 内置了 skill-creator 技能,这也是开箱即用理念的体现:
只需告诉 Agent 你想要什么技能,Agent 就会自动创建好!
用户: 帮我创建一个翻译技能,可以把中文翻译成英文
Agent: 好的,我来为你创建翻译技能…
[调用 skill-creator 技能]
✅ 已创建 skills/translator/SKILL.md
现在你可以直接使用翻译功能了!
工作流程:
#mermaid-svg-3ADASVzwYZtBEYku{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3ADASVzwYZtBEYku .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3ADASVzwYZtBEYku .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3ADASVzwYZtBEYku .error-icon{fill:#552222;}#mermaid-svg-3ADASVzwYZtBEYku .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3ADASVzwYZtBEYku .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3ADASVzwYZtBEYku .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3ADASVzwYZtBEYku .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3ADASVzwYZtBEYku .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3ADASVzwYZtBEYku .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3ADASVzwYZtBEYku .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3ADASVzwYZtBEYku .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3ADASVzwYZtBEYku .marker.cross{stroke:#333333;}#mermaid-svg-3ADASVzwYZtBEYku svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3ADASVzwYZtBEYku p{margin:0;}#mermaid-svg-3ADASVzwYZtBEYku .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-3ADASVzwYZtBEYku .cluster-label text{fill:#333;}#mermaid-svg-3ADASVzwYZtBEYku .cluster-label span{color:#333;}#mermaid-svg-3ADASVzwYZtBEYku .cluster-label span p{background-color:transparent;}#mermaid-svg-3ADASVzwYZtBEYku .label text,#mermaid-svg-3ADASVzwYZtBEYku span{fill:#333;color:#333;}#mermaid-svg-3ADASVzwYZtBEYku .node rect,#mermaid-svg-3ADASVzwYZtBEYku .node circle,#mermaid-svg-3ADASVzwYZtBEYku .node ellipse,#mermaid-svg-3ADASVzwYZtBEYku .node polygon,#mermaid-svg-3ADASVzwYZtBEYku .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3ADASVzwYZtBEYku .rough-node .label text,#mermaid-svg-3ADASVzwYZtBEYku .node .label text,#mermaid-svg-3ADASVzwYZtBEYku .image-shape .label,#mermaid-svg-3ADASVzwYZtBEYku .icon-shape .label{text-anchor:middle;}#mermaid-svg-3ADASVzwYZtBEYku .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3ADASVzwYZtBEYku .rough-node .label,#mermaid-svg-3ADASVzwYZtBEYku .node .label,#mermaid-svg-3ADASVzwYZtBEYku .image-shape .label,#mermaid-svg-3ADASVzwYZtBEYku .icon-shape .label{text-align:center;}#mermaid-svg-3ADASVzwYZtBEYku .node.clickable{cursor:pointer;}#mermaid-svg-3ADASVzwYZtBEYku .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3ADASVzwYZtBEYku .arrowheadPath{fill:#333333;}#mermaid-svg-3ADASVzwYZtBEYku .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3ADASVzwYZtBEYku .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3ADASVzwYZtBEYku .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3ADASVzwYZtBEYku .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3ADASVzwYZtBEYku .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3ADASVzwYZtBEYku .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3ADASVzwYZtBEYku .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3ADASVzwYZtBEYku .cluster text{fill:#333;}#mermaid-svg-3ADASVzwYZtBEYku .cluster span{color:#333;}#mermaid-svg-3ADASVzwYZtBEYku div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3ADASVzwYZtBEYku .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3ADASVzwYZtBEYku rect.text{fill:none;stroke-width:0;}#mermaid-svg-3ADASVzwYZtBEYku .icon-shape,#mermaid-svg-3ADASVzwYZtBEYku .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3ADASVzwYZtBEYku .icon-shape p,#mermaid-svg-3ADASVzwYZtBEYku .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3ADASVzwYZtBEYku .icon-shape rect,#mermaid-svg-3ADASVzwYZtBEYku .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3ADASVzwYZtBEYku .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3ADASVzwYZtBEYku .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3ADASVzwYZtBEYku :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
用户描述需求
Agent 理解意图
调用 skill-creator
生成 SKILL.md
技能立即可用
下次对话自动加载
无需手动创建文件、无需编写代码,一句话就能扩展 Agent 能力!
技能文件结构
skills/
├── skill-creator/ # 技能创建器(内置)- 开箱即用的核心
│ └── SKILL.md
├── summarize/ # 智能总结(内置)
│ └── SKILL.md
├── weather/ # 天气查询(内置)
│ └── SKILL.md
└── my-custom-skill/ # Agent 自动创建或用户自定义
└── SKILL.md
技能定义格式
<!– skills/weather/SKILL.md –>
—
name: weather
description: 查询当前天气和天气预报(无需 API 密钥)
metadata:
finchbot:
emoji: 🌤️
always: false
requires:
bins: [curl]
env: []
—
# 天气查询技能
## 功能说明
使用 wttr.in 服务查询天气信息…
## 使用方式
当用户询问天气相关问题时…
技能加载机制
#mermaid-svg-UMfY3FP71ZKW3y1v{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UMfY3FP71ZKW3y1v .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UMfY3FP71ZKW3y1v .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UMfY3FP71ZKW3y1v .error-icon{fill:#552222;}#mermaid-svg-UMfY3FP71ZKW3y1v .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UMfY3FP71ZKW3y1v .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UMfY3FP71ZKW3y1v .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UMfY3FP71ZKW3y1v .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UMfY3FP71ZKW3y1v .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UMfY3FP71ZKW3y1v .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UMfY3FP71ZKW3y1v .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UMfY3FP71ZKW3y1v .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UMfY3FP71ZKW3y1v .marker.cross{stroke:#333333;}#mermaid-svg-UMfY3FP71ZKW3y1v svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UMfY3FP71ZKW3y1v p{margin:0;}#mermaid-svg-UMfY3FP71ZKW3y1v .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-UMfY3FP71ZKW3y1v .cluster-label text{fill:#333;}#mermaid-svg-UMfY3FP71ZKW3y1v .cluster-label span{color:#333;}#mermaid-svg-UMfY3FP71ZKW3y1v .cluster-label span p{background-color:transparent;}#mermaid-svg-UMfY3FP71ZKW3y1v .label text,#mermaid-svg-UMfY3FP71ZKW3y1v span{fill:#333;color:#333;}#mermaid-svg-UMfY3FP71ZKW3y1v .node rect,#mermaid-svg-UMfY3FP71ZKW3y1v .node circle,#mermaid-svg-UMfY3FP71ZKW3y1v .node ellipse,#mermaid-svg-UMfY3FP71ZKW3y1v .node polygon,#mermaid-svg-UMfY3FP71ZKW3y1v .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UMfY3FP71ZKW3y1v .rough-node .label text,#mermaid-svg-UMfY3FP71ZKW3y1v .node .label text,#mermaid-svg-UMfY3FP71ZKW3y1v .image-shape .label,#mermaid-svg-UMfY3FP71ZKW3y1v .icon-shape .label{text-anchor:middle;}#mermaid-svg-UMfY3FP71ZKW3y1v .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UMfY3FP71ZKW3y1v .rough-node .label,#mermaid-svg-UMfY3FP71ZKW3y1v .node .label,#mermaid-svg-UMfY3FP71ZKW3y1v .image-shape .label,#mermaid-svg-UMfY3FP71ZKW3y1v .icon-shape .label{text-align:center;}#mermaid-svg-UMfY3FP71ZKW3y1v .node.clickable{cursor:pointer;}#mermaid-svg-UMfY3FP71ZKW3y1v .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UMfY3FP71ZKW3y1v .arrowheadPath{fill:#333333;}#mermaid-svg-UMfY3FP71ZKW3y1v .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UMfY3FP71ZKW3y1v .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UMfY3FP71ZKW3y1v .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UMfY3FP71ZKW3y1v .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UMfY3FP71ZKW3y1v .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UMfY3FP71ZKW3y1v .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UMfY3FP71ZKW3y1v .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UMfY3FP71ZKW3y1v .cluster text{fill:#333;}#mermaid-svg-UMfY3FP71ZKW3y1v .cluster span{color:#333;}#mermaid-svg-UMfY3FP71ZKW3y1v div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UMfY3FP71ZKW3y1v .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UMfY3FP71ZKW3y1v rect.text{fill:none;stroke-width:0;}#mermaid-svg-UMfY3FP71ZKW3y1v .icon-shape,#mermaid-svg-UMfY3FP71ZKW3y1v .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UMfY3FP71ZKW3y1v .icon-shape p,#mermaid-svg-UMfY3FP71ZKW3y1v .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UMfY3FP71ZKW3y1v .icon-shape rect,#mermaid-svg-UMfY3FP71ZKW3y1v .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UMfY3FP71ZKW3y1v .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UMfY3FP71ZKW3y1v .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UMfY3FP71ZKW3y1v :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
是
否
是
否
Agent 启动
扫描 skills 目录
工作区技能存在?
加载工作区技能
内置技能存在?
加载内置技能
跳过
检查依赖
依赖满足?
标记为可用
标记为不可用
构建技能摘要
注入系统提示
核心设计亮点
| Agent 自动创建 | 告诉 Agent 需求,自动生成技能文件 |
| 双层技能源 | 工作区技能优先,内置技能兜底 |
| 依赖检查 | 自动检查 CLI 工具和环境变量 |
| 缓存失效检测 | 基于文件修改时间,智能缓存 |
| 渐进式加载 | 常驻技能优先,按需加载其他 |
五、LangChain 1.2 架构实践
FinchBot 基于 LangChain v1.2 和 LangGraph v1.0 构建,采用最新的 Agent 架构。
5.1 Agent 创建流程
from langchain.agents import create_agent
from langgraph.checkpoint.sqlite import SqliteSaver
def create_finch_agent(
model: BaseChatModel,
workspace: Path,
tools: Sequence[BaseTool] | None = None,
use_persistent: bool = True,
) –> tuple[CompiledStateGraph, SqliteSaver | MemorySaver]:
# 1. 初始化检查点(持久化状态)
if use_persistent:
checkpointer = SqliteSaver.from_conn_string(str(db_path))
else:
checkpointer = MemorySaver()
# 2. 构建系统提示
system_prompt = build_system_prompt(workspace)
# 3. 创建 Agent(使用 LangChain 官方 API)
agent = create_agent(
model=model,
tools=list(tools) if tools else None,
system_prompt=system_prompt,
checkpointer=checkpointer,
)
return agent, checkpointer
5.2 LangGraph 状态管理
#mermaid-svg-jqyvL9nZMEe6oyJb{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jqyvL9nZMEe6oyJb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jqyvL9nZMEe6oyJb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jqyvL9nZMEe6oyJb .error-icon{fill:#552222;}#mermaid-svg-jqyvL9nZMEe6oyJb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jqyvL9nZMEe6oyJb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jqyvL9nZMEe6oyJb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jqyvL9nZMEe6oyJb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jqyvL9nZMEe6oyJb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jqyvL9nZMEe6oyJb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jqyvL9nZMEe6oyJb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jqyvL9nZMEe6oyJb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jqyvL9nZMEe6oyJb .marker.cross{stroke:#333333;}#mermaid-svg-jqyvL9nZMEe6oyJb svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jqyvL9nZMEe6oyJb p{margin:0;}#mermaid-svg-jqyvL9nZMEe6oyJb .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-jqyvL9nZMEe6oyJb .cluster-label text{fill:#333;}#mermaid-svg-jqyvL9nZMEe6oyJb .cluster-label span{color:#333;}#mermaid-svg-jqyvL9nZMEe6oyJb .cluster-label span p{background-color:transparent;}#mermaid-svg-jqyvL9nZMEe6oyJb .label text,#mermaid-svg-jqyvL9nZMEe6oyJb span{fill:#333;color:#333;}#mermaid-svg-jqyvL9nZMEe6oyJb .node rect,#mermaid-svg-jqyvL9nZMEe6oyJb .node circle,#mermaid-svg-jqyvL9nZMEe6oyJb .node ellipse,#mermaid-svg-jqyvL9nZMEe6oyJb .node polygon,#mermaid-svg-jqyvL9nZMEe6oyJb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jqyvL9nZMEe6oyJb .rough-node .label text,#mermaid-svg-jqyvL9nZMEe6oyJb .node .label text,#mermaid-svg-jqyvL9nZMEe6oyJb .image-shape .label,#mermaid-svg-jqyvL9nZMEe6oyJb .icon-shape .label{text-anchor:middle;}#mermaid-svg-jqyvL9nZMEe6oyJb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jqyvL9nZMEe6oyJb .rough-node .label,#mermaid-svg-jqyvL9nZMEe6oyJb .node .label,#mermaid-svg-jqyvL9nZMEe6oyJb .image-shape .label,#mermaid-svg-jqyvL9nZMEe6oyJb .icon-shape .label{text-align:center;}#mermaid-svg-jqyvL9nZMEe6oyJb .node.clickable{cursor:pointer;}#mermaid-svg-jqyvL9nZMEe6oyJb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jqyvL9nZMEe6oyJb .arrowheadPath{fill:#333333;}#mermaid-svg-jqyvL9nZMEe6oyJb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jqyvL9nZMEe6oyJb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jqyvL9nZMEe6oyJb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jqyvL9nZMEe6oyJb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jqyvL9nZMEe6oyJb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jqyvL9nZMEe6oyJb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jqyvL9nZMEe6oyJb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jqyvL9nZMEe6oyJb .cluster text{fill:#333;}#mermaid-svg-jqyvL9nZMEe6oyJb .cluster span{color:#333;}#mermaid-svg-jqyvL9nZMEe6oyJb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jqyvL9nZMEe6oyJb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jqyvL9nZMEe6oyJb rect.text{fill:none;stroke-width:0;}#mermaid-svg-jqyvL9nZMEe6oyJb .icon-shape,#mermaid-svg-jqyvL9nZMEe6oyJb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jqyvL9nZMEe6oyJb .icon-shape p,#mermaid-svg-jqyvL9nZMEe6oyJb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jqyvL9nZMEe6oyJb .icon-shape rect,#mermaid-svg-jqyvL9nZMEe6oyJb .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jqyvL9nZMEe6oyJb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jqyvL9nZMEe6oyJb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jqyvL9nZMEe6oyJb :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
否
是
用户输入
加载 Checkpoint
构建 Prompt
LLM 推理
需要工具?
生成回复
执行工具
保存 Checkpoint
返回用户
5.3 持久化检查点
# 使用上下文管理器确保资源正确释放
@contextmanager
def get_sqlite_checkpointer(workspace: Path) –> Iterator[SqliteSaver]:
db_path = workspace / ".finchbot" / "checkpoints.db"
with SqliteSaver.from_conn_string(str(db_path)) as checkpointer:
yield checkpointer
5.4 支持的 LLM 提供商
| OpenAI | GPT-5, GPT-5.2, O3-mini | 综合能力最强 |
| Anthropic | Claude Sonnet 4.5, Opus 4.6 | 安全性高,长文本 |
| DeepSeek | DeepSeek Chat, Reasoner | 国产,性价比高 |
| Gemini | Gemini 2.5 Flash | Google 最新 |
| Groq | Llama 4 Scout/Maverick | 极速推理 |
| Moonshot | Kimi K1.5/K2.5 | 长文本,国产 |
六、快速上手
6.1 最佳实践:三步上手
# 第一步:配置 API 密钥和默认模型
uv run finchbot config
# 第二步:管理你的会话
uv run finchbot sessions
# 第三步:开始对话
uv run finchbot chat
这三个命令覆盖了 FinchBot 的核心工作流程:
| finchbot config | 交互式配置 | 配置 LLM 提供商、API 密钥、默认模型、网页搜索等 |
| finchbot sessions | 会话管理 | 全屏界面创建、重命名、删除会话,查看会话历史 |
| finchbot chat | 开始对话 | 启动交互式聊天,自动加载最近活跃的会话 |
6.2 安装
# 克隆仓库
git clone https://github.com/xt765/finchbot.git
cd finchbot
# 使用 uv 安装依赖
uv sync
6.3 备选方案:环境变量
# 或直接设置环境变量
export OPENAI_API_KEY="your-api-key"
uv run finchbot chat
6.4 可选:下载本地嵌入模型
# 用于记忆系统的语义搜索(可选但推荐)
uv run finchbot models download
6.5 让 Agent 创建技能
# 无需手动创建!直接在对话中告诉 Agent:
# "帮我创建一个 XXX 技能,可以…"
# Agent 会自动调用 skill-creator 技能
# 生成 SKILL.md 文件并立即可用
七、总结
FinchBot 不是一个简单的 LLM 封装,而是一个深思熟虑的 Agent 框架设计:
| 记忆架构 | 双层存储,Agentic RAG,加权 RRF |
| 提示词系统 | 文件系统,热加载,模块化组装 |
| 工具系统 | 注册表模式,线程安全,11 个内置工具,三引擎降级 |
| 技能系统 | Markdown 定义,Agent 自动创建,开箱即用 |
| 架构实践 | LangChain v1.2,LangGraph v1.0 |
| 开箱即用 | 环境变量配置,Rich CLI,i18n,自动降级 |
如果你正在寻找一个:
- ✅ 隐私优先(本地 Embedding)
- ✅ 真持久化(双层记忆)
- ✅ 生产级稳定(完善的错误处理)
- ✅ 灵活扩展(技能 + 工具双层)
- ✅ 最新架构(LangChain 1.2)
- ✅ 开箱即用(零配置启动,自动降级)
的 AI Agent 框架,FinchBot 值得一试。
相关链接
- 📦 项目地址: GitHub – FinchBot
- 📖 文档: FinchBot 文档
- 💬 问题反馈: GitHub Issues
如果这个项目对你有帮助,请给个 Star ⭐️




